Browse Source

Merge #9279: Consensus: Move CFeeRate out of libconsensus

381a46e Consensus: Policy: MOVEONLY: Move CFeeRate out of the consensus module (Jorge Timón)
330bb5a Consensus: Minimal way to move dust out of consensus (Jorge Timón)

Tree-SHA512: 19a2ea8169afd5a9d3f940d8974e34cfaead153e3ff3068ac82fccdb8694d19d9b45938904ec9e8cd095bd5ca3a0080364da29372f6aaf56b11a6c2ccd6c7a4d
0.15
Wladimir J. van der Laan 8 years ago
parent
commit
08a7316c14
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 3
      src/Makefile.am
  2. 45
      src/amount.h
  3. 1
      src/init.cpp
  4. 1
      src/miner.cpp
  5. 1
      src/net.h
  6. 2
      src/policy/feerate.cpp
  7. 54
      src/policy/feerate.h
  8. 1
      src/policy/fees.h
  9. 39
      src/policy/policy.cpp
  10. 6
      src/policy/policy.h
  11. 37
      src/primitives/transaction.h
  12. 7
      src/qt/coincontroldialog.cpp
  13. 2
      src/qt/guiutil.cpp
  14. 2
      src/qt/paymentserver.cpp
  15. 1
      src/rpc/blockchain.cpp
  16. 1
      src/test/amount_tests.cpp
  17. 1
      src/txmempool.h
  18. 1
      src/validation.h
  19. 1
      src/wallet/coincontrol.h
  20. 2
      src/wallet/feebumper.cpp
  21. 1
      src/wallet/rpcwallet.cpp
  22. 10
      src/wallet/wallet.cpp
  23. 1
      src/wallet/wallet.h

3
src/Makefile.am

@ -116,6 +116,7 @@ BITCOIN_CORE_H = \
netbase.h \ netbase.h \
netmessagemaker.h \ netmessagemaker.h \
noui.h \ noui.h \
policy/feerate.h \
policy/fees.h \ policy/fees.h \
policy/policy.h \ policy/policy.h \
policy/rbf.h \ policy/rbf.h \
@ -301,7 +302,6 @@ libbitcoin_consensus_a_SOURCES = \
libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) libbitcoin_common_a_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES)
libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) libbitcoin_common_a_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS)
libbitcoin_common_a_SOURCES = \ libbitcoin_common_a_SOURCES = \
amount.cpp \
base58.cpp \ base58.cpp \
chainparams.cpp \ chainparams.cpp \
coins.cpp \ coins.cpp \
@ -312,6 +312,7 @@ libbitcoin_common_a_SOURCES = \
keystore.cpp \ keystore.cpp \
netaddress.cpp \ netaddress.cpp \
netbase.cpp \ netbase.cpp \
policy/feerate.cpp \
protocol.cpp \ protocol.cpp \
scheduler.cpp \ scheduler.cpp \
script/sign.cpp \ script/sign.cpp \

45
src/amount.h

@ -6,10 +6,7 @@
#ifndef BITCOIN_AMOUNT_H #ifndef BITCOIN_AMOUNT_H
#define BITCOIN_AMOUNT_H #define BITCOIN_AMOUNT_H
#include "serialize.h" #include <stdint.h>
#include <stdlib.h>
#include <string>
/** Amount in satoshis (Can be negative) */ /** Amount in satoshis (Can be negative) */
typedef int64_t CAmount; typedef int64_t CAmount;
@ -17,8 +14,6 @@ typedef int64_t CAmount;
static const CAmount COIN = 100000000; static const CAmount COIN = 100000000;
static const CAmount CENT = 1000000; static const CAmount CENT = 1000000;
extern const std::string CURRENCY_UNIT;
/** No amount larger than this (in satoshi) is valid. /** No amount larger than this (in satoshi) is valid.
* *
* Note that this constant is *not* the total money supply, which in Bitcoin * Note that this constant is *not* the total money supply, which in Bitcoin
@ -31,42 +26,4 @@ extern const std::string CURRENCY_UNIT;
static const CAmount MAX_MONEY = 21000000 * COIN; static const CAmount MAX_MONEY = 21000000 * COIN;
inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); } inline bool MoneyRange(const CAmount& nValue) { return (nValue >= 0 && nValue <= MAX_MONEY); }
/**
* Fee rate in satoshis per kilobyte: CAmount / kB
*/
class CFeeRate
{
private:
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
public:
/** Fee rate of 0 satoshis per kB */
CFeeRate() : nSatoshisPerK(0) { }
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/**
* Return the fee in satoshis for the given size in bytes.
*/
CAmount GetFee(size_t nBytes) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
CAmount GetFeePerK() const { return GetFee(1000); }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nSatoshisPerK);
}
};
#endif // BITCOIN_AMOUNT_H #endif // BITCOIN_AMOUNT_H

1
src/init.cpp

@ -25,6 +25,7 @@
#include "netbase.h" #include "netbase.h"
#include "net.h" #include "net.h"
#include "net_processing.h" #include "net_processing.h"
#include "policy/feerate.h"
#include "policy/fees.h" #include "policy/fees.h"
#include "policy/policy.h" #include "policy/policy.h"
#include "rpc/server.h" #include "rpc/server.h"

1
src/miner.cpp

@ -15,6 +15,7 @@
#include "hash.h" #include "hash.h"
#include "validation.h" #include "validation.h"
#include "net.h" #include "net.h"
#include "policy/feerate.h"
#include "policy/policy.h" #include "policy/policy.h"
#include "pow.h" #include "pow.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"

1
src/net.h

@ -14,6 +14,7 @@
#include "hash.h" #include "hash.h"
#include "limitedmap.h" #include "limitedmap.h"
#include "netaddress.h" #include "netaddress.h"
#include "policy/feerate.h"
#include "protocol.h" #include "protocol.h"
#include "random.h" #include "random.h"
#include "streams.h" #include "streams.h"

2
src/amount.cpp → src/policy/feerate.cpp

@ -3,7 +3,7 @@
// Distributed under the MIT software license, see the accompanying // Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h" #include "feerate.h"
#include "tinyformat.h" #include "tinyformat.h"

54
src/policy/feerate.h

@ -0,0 +1,54 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2015 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_POLICY_FEERATE_H
#define BITCOIN_POLICY_FEERATE_H
#include "amount.h"
#include "serialize.h"
#include <string>
extern const std::string CURRENCY_UNIT;
/**
* Fee rate in satoshis per kilobyte: CAmount / kB
*/
class CFeeRate
{
private:
CAmount nSatoshisPerK; // unit is satoshis-per-1,000-bytes
public:
/** Fee rate of 0 satoshis per kB */
CFeeRate() : nSatoshisPerK(0) { }
explicit CFeeRate(const CAmount& _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) { }
/** Constructor for a fee rate in satoshis per kB. The size in bytes must not exceed (2^63 - 1)*/
CFeeRate(const CAmount& nFeePaid, size_t nBytes);
CFeeRate(const CFeeRate& other) { nSatoshisPerK = other.nSatoshisPerK; }
/**
* Return the fee in satoshis for the given size in bytes.
*/
CAmount GetFee(size_t nBytes) const;
/**
* Return the fee in satoshis for a size of 1000 bytes
*/
CAmount GetFeePerK() const { return GetFee(1000); }
friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
std::string ToString() const;
ADD_SERIALIZE_METHODS;
template <typename Stream, typename Operation>
inline void SerializationOp(Stream& s, Operation ser_action) {
READWRITE(nSatoshisPerK);
}
};
#endif // BITCOIN_POLICY_FEERATE_H

1
src/policy/fees.h

@ -6,6 +6,7 @@
#define BITCOIN_POLICYESTIMATOR_H #define BITCOIN_POLICYESTIMATOR_H
#include "amount.h" #include "amount.h"
#include "feerate.h"
#include "uint256.h" #include "uint256.h"
#include "random.h" #include "random.h"
#include "sync.h" #include "sync.h"

39
src/policy/policy.cpp

@ -15,6 +15,43 @@
#include <boost/foreach.hpp> #include <boost/foreach.hpp>
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee)
{
// "Dust" is defined in terms of dustRelayFee,
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
// A typical spendable non-segwit txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
// so dust is a spendable txout less than
// 546*dustRelayFee/1000 (in satoshis).
// A typical spendable segwit txout is 31 bytes big, and will
// need a CTxIn of at least 67 bytes to spend:
// so dust is a spendable txout less than
// 294*dustRelayFee/1000 (in satoshis).
if (txout.scriptPubKey.IsUnspendable())
return 0;
size_t nSize = GetSerializeSize(txout, SER_DISK, 0);
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
// sum the sizes of the parts of a transaction input
// with 75% segwit discount applied to the script size.
nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
} else {
nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
}
return 3 * dustRelayFee.GetFee(nSize);
}
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee)
{
return (txout.nValue < GetDustThreshold(txout, dustRelayFee));
}
/** /**
* Check transaction inputs to mitigate two * Check transaction inputs to mitigate two
* potential denial-of-service attacks: * potential denial-of-service attacks:
@ -106,7 +143,7 @@ bool IsStandardTx(const CTransaction& tx, std::string& reason, const bool witnes
else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) { else if ((whichType == TX_MULTISIG) && (!fIsBareMultisigStd)) {
reason = "bare-multisig"; reason = "bare-multisig";
return false; return false;
} else if (txout.IsDust(dustRelayFee)) { } else if (IsDust(txout, ::dustRelayFee)) {
reason = "dust"; reason = "dust";
return false; return false;
} }

6
src/policy/policy.h

@ -7,12 +7,14 @@
#define BITCOIN_POLICY_POLICY_H #define BITCOIN_POLICY_POLICY_H
#include "consensus/consensus.h" #include "consensus/consensus.h"
#include "feerate.h"
#include "script/interpreter.h" #include "script/interpreter.h"
#include "script/standard.h" #include "script/standard.h"
#include <string> #include <string>
class CCoinsViewCache; class CCoinsViewCache;
class CTxOut;
/** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/ /** Default for -blockmaxsize, which controls the maximum size of block the mining code will create **/
static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000; static const unsigned int DEFAULT_BLOCK_MAX_SIZE = 750000;
@ -72,6 +74,10 @@ static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_
static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE | static const unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
LOCKTIME_MEDIAN_TIME_PAST; LOCKTIME_MEDIAN_TIME_PAST;
CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false); bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType, const bool witnessEnabled = false);
/** /**
* Check for standard transaction types * Check for standard transaction types

37
src/primitives/transaction.h

@ -161,43 +161,6 @@ public:
return (nValue == -1); return (nValue == -1);
} }
CAmount GetDustThreshold(const CFeeRate &minRelayTxFee) const
{
// "Dust" is defined in terms of CTransaction::minRelayTxFee,
// which has units satoshis-per-kilobyte.
// If you'd pay more than 1/3 in fees
// to spend something, then we consider it dust.
// A typical spendable non-segwit txout is 34 bytes big, and will
// need a CTxIn of at least 148 bytes to spend:
// so dust is a spendable txout less than
// 546*minRelayTxFee/1000 (in satoshis).
// A typical spendable segwit txout is 31 bytes big, and will
// need a CTxIn of at least 67 bytes to spend:
// so dust is a spendable txout less than
// 294*minRelayTxFee/1000 (in satoshis).
if (scriptPubKey.IsUnspendable())
return 0;
size_t nSize = GetSerializeSize(*this, SER_DISK, 0);
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
// sum the sizes of the parts of a transaction input
// with 75% segwit discount applied to the script size.
nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
} else {
nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
}
return 3 * minRelayTxFee.GetFee(nSize);
}
bool IsDust(const CFeeRate &minRelayTxFee) const
{
return (nValue < GetDustThreshold(minRelayTxFee));
}
friend bool operator==(const CTxOut& a, const CTxOut& b) friend bool operator==(const CTxOut& a, const CTxOut& b)
{ {
return (a.nValue == b.nValue && return (a.nValue == b.nValue &&

7
src/qt/coincontroldialog.cpp

@ -434,8 +434,7 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
{ {
CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0)); CTxOut txout(amount, (CScript)std::vector<unsigned char>(24, 0));
txDummy.vout.push_back(txout); txDummy.vout.push_back(txout);
if (txout.IsDust(dustRelayFee)) fDust |= IsDust(txout, ::dustRelayFee);
fDust = true;
} }
} }
@ -527,10 +526,10 @@ void CoinControlDialog::updateLabels(WalletModel *model, QDialog* dialog)
if (nChange > 0 && nChange < MIN_CHANGE) if (nChange > 0 && nChange < MIN_CHANGE)
{ {
CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0)); CTxOut txout(nChange, (CScript)std::vector<unsigned char>(24, 0));
if (txout.IsDust(dustRelayFee)) if (IsDust(txout, ::dustRelayFee))
{ {
if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust if (CoinControlDialog::fSubtractFeeFromAmount) // dust-change will be raised until no dust
nChange = txout.GetDustThreshold(dustRelayFee); nChange = GetDustThreshold(txout, ::dustRelayFee);
else else
{ {
nPayFee += nChange; nPayFee += nChange;

2
src/qt/guiutil.cpp

@ -251,7 +251,7 @@ bool isDust(const QString& address, const CAmount& amount)
CTxDestination dest = CBitcoinAddress(address.toStdString()).Get(); CTxDestination dest = CBitcoinAddress(address.toStdString()).Get();
CScript script = GetScriptForDestination(dest); CScript script = GetScriptForDestination(dest);
CTxOut txOut(amount, script); CTxOut txOut(amount, script);
return txOut.IsDust(dustRelayFee); return IsDust(txOut, ::dustRelayFee);
} }
QString HtmlEscape(const QString& str, bool fMultiLine) QString HtmlEscape(const QString& str, bool fMultiLine)

2
src/qt/paymentserver.cpp

@ -580,7 +580,7 @@ bool PaymentServer::processPaymentRequest(const PaymentRequestPlus& request, Sen
// Extract and check amounts // Extract and check amounts
CTxOut txOut(sendingTo.second, sendingTo.first); CTxOut txOut(sendingTo.second, sendingTo.first);
if (txOut.IsDust(dustRelayFee)) { if (IsDust(txOut, ::dustRelayFee)) {
Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).") Q_EMIT message(tr("Payment request error"), tr("Requested payment amount of %1 is too small (considered dust).")
.arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)), .arg(BitcoinUnits::formatWithUnit(optionsModel->getDisplayUnit(), sendingTo.second)),
CClientUIInterface::MSG_ERROR); CClientUIInterface::MSG_ERROR);

1
src/rpc/blockchain.cpp

@ -13,6 +13,7 @@
#include "consensus/validation.h" #include "consensus/validation.h"
#include "validation.h" #include "validation.h"
#include "core_io.h" #include "core_io.h"
#include "policy/feerate.h"
#include "policy/policy.h" #include "policy/policy.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "rpc/server.h" #include "rpc/server.h"

1
src/test/amount_tests.cpp

@ -3,6 +3,7 @@
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "amount.h" #include "amount.h"
#include "policy/feerate.h"
#include "test/test_bitcoin.h" #include "test/test_bitcoin.h"
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>

1
src/txmempool.h

@ -16,6 +16,7 @@
#include "amount.h" #include "amount.h"
#include "coins.h" #include "coins.h"
#include "indirectmap.h" #include "indirectmap.h"
#include "policy/feerate.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "sync.h" #include "sync.h"
#include "random.h" #include "random.h"

1
src/validation.h

@ -14,6 +14,7 @@
#include "coins.h" #include "coins.h"
#include "fs.h" #include "fs.h"
#include "protocol.h" // For CMessageHeader::MessageStartChars #include "protocol.h" // For CMessageHeader::MessageStartChars
#include "policy/feerate.h"
#include "script/script_error.h" #include "script/script_error.h"
#include "sync.h" #include "sync.h"
#include "versionbits.h" #include "versionbits.h"

1
src/wallet/coincontrol.h

@ -5,6 +5,7 @@
#ifndef BITCOIN_WALLET_COINCONTROL_H #ifndef BITCOIN_WALLET_COINCONTROL_H
#define BITCOIN_WALLET_COINCONTROL_H #define BITCOIN_WALLET_COINCONTROL_H
#include "policy/feerate.h"
#include "primitives/transaction.h" #include "primitives/transaction.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"

2
src/wallet/feebumper.cpp

@ -214,7 +214,7 @@ CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, int newConf
// If the output would become dust, discard it (converting the dust to fee) // If the output would become dust, discard it (converting the dust to fee)
poutput->nValue -= nDelta; poutput->nValue -= nDelta;
if (poutput->nValue <= poutput->GetDustThreshold(::dustRelayFee)) { if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {
LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n"); LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
nNewFee += poutput->nValue; nNewFee += poutput->nValue;
mtx.vout.erase(mtx.vout.begin() + nOutput); mtx.vout.erase(mtx.vout.begin() + nOutput);

1
src/wallet/rpcwallet.cpp

@ -12,6 +12,7 @@
#include "wallet/coincontrol.h" #include "wallet/coincontrol.h"
#include "validation.h" #include "validation.h"
#include "net.h" #include "net.h"
#include "policy/feerate.h"
#include "policy/fees.h" #include "policy/fees.h"
#include "policy/policy.h" #include "policy/policy.h"
#include "policy/rbf.h" #include "policy/rbf.h"

10
src/wallet/wallet.cpp

@ -2449,7 +2449,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
} }
} }
if (txout.IsDust(dustRelayFee)) if (IsDust(txout, ::dustRelayFee))
{ {
if (recipient.fSubtractFeeFromAmount && nFeeRet > 0) if (recipient.fSubtractFeeFromAmount && nFeeRet > 0)
{ {
@ -2514,16 +2514,16 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// We do not move dust-change to fees, because the sender would end up paying more than requested. // We do not move dust-change to fees, because the sender would end up paying more than requested.
// This would be against the purpose of the all-inclusive feature. // This would be against the purpose of the all-inclusive feature.
// So instead we raise the change and deduct from the recipient. // So instead we raise the change and deduct from the recipient.
if (nSubtractFeeFromAmount > 0 && newTxOut.IsDust(dustRelayFee)) if (nSubtractFeeFromAmount > 0 && IsDust(newTxOut, ::dustRelayFee))
{ {
CAmount nDust = newTxOut.GetDustThreshold(dustRelayFee) - newTxOut.nValue; CAmount nDust = GetDustThreshold(newTxOut, ::dustRelayFee) - newTxOut.nValue;
newTxOut.nValue += nDust; // raise change until no more dust newTxOut.nValue += nDust; // raise change until no more dust
for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient for (unsigned int i = 0; i < vecSend.size(); i++) // subtract from first recipient
{ {
if (vecSend[i].fSubtractFeeFromAmount) if (vecSend[i].fSubtractFeeFromAmount)
{ {
txNew.vout[i].nValue -= nDust; txNew.vout[i].nValue -= nDust;
if (txNew.vout[i].IsDust(dustRelayFee)) if (IsDust(txNew.vout[i], ::dustRelayFee))
{ {
strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); strFailReason = _("The transaction amount is too small to send after the fee has been deducted");
return false; return false;
@ -2535,7 +2535,7 @@ bool CWallet::CreateTransaction(const std::vector<CRecipient>& vecSend, CWalletT
// Never create dust outputs; if we would, just // Never create dust outputs; if we would, just
// add the dust to the fee. // add the dust to the fee.
if (newTxOut.IsDust(dustRelayFee)) if (IsDust(newTxOut, ::dustRelayFee))
{ {
nChangePosInOut = -1; nChangePosInOut = -1;
nFeeRet += nChange; nFeeRet += nChange;

1
src/wallet/wallet.h

@ -7,6 +7,7 @@
#define BITCOIN_WALLET_WALLET_H #define BITCOIN_WALLET_WALLET_H
#include "amount.h" #include "amount.h"
#include "policy/feerate.h"
#include "streams.h" #include "streams.h"
#include "tinyformat.h" #include "tinyformat.h"
#include "ui_interface.h" #include "ui_interface.h"

Loading…
Cancel
Save