Fabcoin Core  0.16.2
P2P Digital Currency
feebumper.cpp
Go to the documentation of this file.
1 // Copyright (c) 2017 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <consensus/validation.h>
6 #include <wallet/coincontrol.h>
7 #include <wallet/feebumper.h>
8 #include <wallet/wallet.h>
9 #include <policy/fees.h>
10 #include <policy/policy.h>
11 #include <policy/rbf.h>
12 #include <validation.h> //for mempool access
13 #include <txmempool.h>
14 #include <utilmoneystr.h>
15 #include <util.h>
16 #include <net.h>
17 
18 // Calculate the size of the transaction assuming all signatures are max size
19 // Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
20 // TODO: re-use this in CWallet::CreateTransaction (right now
21 // CreateTransaction uses the constructed dummy-signed tx to do a priority
22 // calculation, but we should be able to refactor after priority is removed).
23 // NOTE: this requires that all inputs must be in mapWallet (eg the tx should
24 // be IsAllFromMe).
25 int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)
26 {
27  CMutableTransaction txNew(tx);
28  std::vector<CInputCoin> vCoins;
29  // Look up the inputs. We should have already checked that this transaction
30  // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
31  // wallet, with a valid index into the vout array.
32  for (auto& input : tx.vin) {
33  const auto mi = pWallet->mapWallet.find(input.prevout.hash);
34  assert(mi != pWallet->mapWallet.end() && input.prevout.n < mi->second.tx->vout.size());
35  vCoins.emplace_back(CInputCoin(&(mi->second), input.prevout.n));
36  }
37  if (!pWallet->DummySignTx(txNew, vCoins)) {
38  // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
39  // implies that we can sign for every input.
40  return -1;
41  }
42  return GetVirtualTransactionSize(txNew);
43 }
44 
45 bool CFeeBumper::preconditionChecks(const CWallet *pWallet, const CWalletTx& wtx) {
46  if (pWallet->HasWalletSpend(wtx.GetHash())) {
47  vErrors.push_back("Transaction has descendants in the wallet");
49  return false;
50  }
51 
52  {
53  LOCK(mempool.cs);
54  auto it_mp = mempool.mapTx.find(wtx.GetHash());
55  if (it_mp != mempool.mapTx.end() && it_mp->GetCountWithDescendants() > 1) {
56  vErrors.push_back("Transaction has descendants in the mempool");
58  return false;
59  }
60  }
61 
62  if (wtx.GetDepthInMainChain() != 0) {
63  vErrors.push_back("Transaction has been mined, or is conflicted with a mined transaction");
65  return false;
66  }
67  return true;
68 }
69 
70 CFeeBumper::CFeeBumper(const CWallet *pWallet, const uint256 txidIn, const CCoinControl& coin_control, CAmount totalFee)
71  :
72  txid(std::move(txidIn)),
73  nOldFee(0),
74  nNewFee(0)
75 {
76  vErrors.clear();
78  AssertLockHeld(pWallet->cs_wallet);
79  if (!pWallet->mapWallet.count(txid)) {
80  vErrors.push_back("Invalid or non-wallet transaction id");
82  return;
83  }
84  auto it = pWallet->mapWallet.find(txid);
85  const CWalletTx& wtx = it->second;
86 
87  if (!preconditionChecks(pWallet, wtx)) {
88  return;
89  }
90 
91  if (!SignalsOptInRBF(wtx)) {
92  vErrors.push_back("Transaction is not BIP 125 replaceable");
94  return;
95  }
96 
97  if (wtx.mapValue.count("replaced_by_txid")) {
98  vErrors.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid.ToString(), wtx.mapValue.at("replaced_by_txid")));
100  return;
101  }
102 
103  // check that original tx consists entirely of our inputs
104  // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
105  if (!pWallet->IsAllFromMe(wtx, ISMINE_SPENDABLE)) {
106  vErrors.push_back("Transaction contains inputs that don't belong to this wallet");
108  return;
109  }
110 
111  // figure out which output was change
112  // if there was no change output or multiple change outputs, fail
113  int nOutput = -1;
114  for (size_t i = 0; i < wtx.tx->vout.size(); ++i) {
115  if (pWallet->IsChange(wtx.tx->vout[i])) {
116  if (nOutput != -1) {
117  vErrors.push_back("Transaction has multiple change outputs");
119  return;
120  }
121  nOutput = i;
122  }
123  }
124  if (nOutput == -1) {
125  vErrors.push_back("Transaction does not have a change output");
127  return;
128  }
129 
130  // Calculate the expected size of the new transaction.
131  int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
132  const int64_t maxNewTxSize = CalculateMaximumSignedTxSize(*wtx.tx, pWallet);
133  if (maxNewTxSize < 0) {
134  vErrors.push_back("Transaction contains inputs that cannot be signed");
136  return;
137  }
138 
139  // calculate the old fee and fee-rate
140  nOldFee = wtx.GetDebit(ISMINE_SPENDABLE) - wtx.tx->GetValueOut();
141  CFeeRate nOldFeeRate(nOldFee, txSize);
142  CFeeRate nNewFeeRate;
143  // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
144  // future proof against changes to network wide policy for incremental relay
145  // fee that our node may not be aware of.
146  CFeeRate walletIncrementalRelayFee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
147  if (::incrementalRelayFee > walletIncrementalRelayFee) {
148  walletIncrementalRelayFee = ::incrementalRelayFee;
149  }
150 
151  if (totalFee > 0) {
152  CAmount minTotalFee = nOldFeeRate.GetFee(maxNewTxSize) + ::incrementalRelayFee.GetFee(maxNewTxSize);
153  if (totalFee < minTotalFee) {
154  vErrors.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
155  FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxNewTxSize)), FormatMoney(::incrementalRelayFee.GetFee(maxNewTxSize))));
157  return;
158  }
159  CAmount requiredFee = CWallet::GetRequiredFee(maxNewTxSize);
160  if (totalFee < requiredFee) {
161  vErrors.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
162  FormatMoney(requiredFee)));
164  return;
165  }
166  nNewFee = totalFee;
167  nNewFeeRate = CFeeRate(totalFee, maxNewTxSize);
168  } else {
169  nNewFee = CWallet::GetMinimumFee(maxNewTxSize, coin_control, mempool, ::feeEstimator, nullptr /* FeeCalculation */);
170  nNewFeeRate = CFeeRate(nNewFee, maxNewTxSize);
171 
172  // New fee rate must be at least old rate + minimum incremental relay rate
173  // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
174  // in that unit (fee per kb).
175  // However, nOldFeeRate is a calculated value from the tx fee/size, so
176  // add 1 liu to the result, because it may have been rounded down.
177  if (nNewFeeRate.GetFeePerK() < nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK()) {
178  nNewFeeRate = CFeeRate(nOldFeeRate.GetFeePerK() + 1 + walletIncrementalRelayFee.GetFeePerK());
179  nNewFee = nNewFeeRate.GetFee(maxNewTxSize);
180  }
181  }
182 
183  // Check that in all cases the new fee doesn't violate maxTxFee
184  if (nNewFee > maxTxFee) {
185  vErrors.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
188  return;
189  }
190 
191  // check that fee rate is higher than mempool's minimum fee
192  // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
193  // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
194  // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
195  // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
196  CFeeRate minMempoolFeeRate = mempool.GetMinFee(gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000);
197  if (nNewFeeRate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
198  vErrors.push_back(strprintf("New fee rate (%s) is less than the minimum fee rate (%s) to get into the mempool. totalFee value should to be at least %s or settxfee value should be at least %s to add transaction.", FormatMoney(nNewFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFeePerK()), FormatMoney(minMempoolFeeRate.GetFee(maxNewTxSize)), FormatMoney(minMempoolFeeRate.GetFeePerK())));
200  return;
201  }
202 
203  // Now modify the output to increase the fee.
204  // If the output is not large enough to pay the fee, fail.
205  CAmount nDelta = nNewFee - nOldFee;
206  assert(nDelta > 0);
207  mtx = *wtx.tx;
208  CTxOut* poutput = &(mtx.vout[nOutput]);
209  if (poutput->nValue < nDelta) {
210  vErrors.push_back("Change output is too small to bump the fee");
212  return;
213  }
214 
215  // If the output would become dust, discard it (converting the dust to fee)
216  poutput->nValue -= nDelta;
217  if (poutput->nValue <= GetDustThreshold(*poutput, ::dustRelayFee)) {
218  LogPrint(BCLog::RPC, "Bumping fee and discarding dust output\n");
219  nNewFee += poutput->nValue;
220  mtx.vout.erase(mtx.vout.begin() + nOutput);
221  }
222 
223  // Mark new tx not replaceable, if requested.
224  if (!coin_control.signalRbf) {
225  for (auto& input : mtx.vin) {
226  if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
227  }
228  }
229 
231 }
232 
234 {
235  return pWallet->SignTransaction(mtx);
236 }
237 
239 {
240  AssertLockHeld(pWallet->cs_wallet);
241  if (!vErrors.empty() || currentResult != BumpFeeResult::OK) {
242  return false;
243  }
244  if (txid.IsNull() || !pWallet->mapWallet.count(txid)) {
245  vErrors.push_back("Invalid or non-wallet transaction id");
247  return false;
248  }
249  CWalletTx& oldWtx = pWallet->mapWallet[txid];
250 
251  // make sure the transaction still has no descendants and hasn't been mined in the meantime
252  if (!preconditionChecks(pWallet, oldWtx)) {
253  return false;
254  }
255 
256  CWalletTx wtxBumped(pWallet, MakeTransactionRef(std::move(mtx)));
257  // commit/broadcast the tx
258  CReserveKey reservekey(pWallet);
259  wtxBumped.mapValue = oldWtx.mapValue;
260  wtxBumped.mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
261  wtxBumped.vOrderForm = oldWtx.vOrderForm;
262  wtxBumped.strFromAccount = oldWtx.strFromAccount;
263  wtxBumped.fTimeReceivedIsTxTime = true;
264  wtxBumped.fFromMe = true;
265  CValidationState state;
266  if (!pWallet->CommitTransaction(wtxBumped, reservekey, g_connman.get(), state)) {
267  // NOTE: CommitTransaction never returns false, so this should never happen.
268  vErrors.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state.GetRejectReason()));
269  return false;
270  }
271 
272  bumpedTxid = wtxBumped.GetHash();
273  if (state.IsInvalid()) {
274  // This can happen if the mempool rejected the transaction. Report
275  // what happened in the "errors" response.
276  vErrors.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state)));
277  }
278 
279  // mark the original tx as bumped
280  if (!pWallet->MarkReplaced(oldWtx.GetHash(), wtxBumped.GetHash())) {
281  // TODO: see if JSON-RPC has a standard way of returning a response
282  // along with an exception. It would be good to return information about
283  // wtxBumped to the caller even if marking the original transaction
284  // replaced does not succeed for some reason.
285  vErrors.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");
286  }
287  return true;
288 }
289 
CAmount nValue
Definition: transaction.h:134
int64_t GetVirtualTransactionSize(int64_t nWeight, int64_t nSigOpCost)
Compute the virtual transaction size (weight reinterpreted as bytes).
Definition: policy.cpp:254
CAmount GetFeePerK() const
Return the fee in liu for a size of 1000 bytes.
Definition: feerate.h:38
CTxMemPool mempool
CFeeRate GetMinFee(size_t sizelimit) const
The minimum fee to get into the mempool, which may itself not be enough for larger-sized transactions...
Definition: txmempool.cpp:996
bool SignTransaction(CMutableTransaction &tx)
Definition: wallet.cpp:2562
int GetDepthInMainChain(const CBlockIndex *&pindexRet) const
Return depth of transaction in blockchain: <0 : conflicts with a transaction this deep in the blockch...
Definition: wallet.cpp:4504
bool IsAllFromMe(const CTransaction &tx, const isminefilter &filter) const
Returns whether all of the inputs match the filter.
Definition: wallet.cpp:1401
void SetNull()
Definition: uint256.h:46
BumpFeeResult currentResult
Definition: feebumper.h:56
char fFromMe
From me flag is set to 1 for transactions that were created by the wallet on this fabcoin node...
Definition: wallet.h:337
int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *pWallet)
Definition: feebumper.cpp:25
CCriticalSection cs_wallet
Definition: wallet.h:748
const uint256 txid
Definition: feebumper.h:52
const uint256 & GetHash() const
Definition: wallet.h:278
#define strprintf
Definition: tinyformat.h:1054
CAmount maxTxFee
Absolute maximum transaction fee (in liu) used by wallet and mempool (rejects high fee in sendrawtran...
Definition: validation.cpp:104
std::vector< CTxIn > vin
Definition: transaction.h:392
std::string strFromAccount
Definition: wallet.h:338
bool IsChange(const CTxOut &txout) const
Definition: wallet.cpp:1347
bool DummySignTx(CMutableTransaction &txNew, const ContainerType &coins) const
Definition: wallet.h:1274
std::vector< std::string > vErrors
Definition: feebumper.h:55
std::hash for asio::adress
Definition: Common.h:323
assert(len-trim+(2 *lenIndices)<=WIDTH)
uint256 bumpedTxid
Definition: feebumper.h:53
bool MarkReplaced(const uint256 &originalHash, const uint256 &newHash)
Mark a transaction as replaced by another transaction (e.g., BIP 125).
Definition: wallet.cpp:924
Coin Control Features.
Definition: coincontrol.h:16
CAmount GetDebit(const isminefilter &filter) const
filter decides which addresses will count towards the debit
Definition: wallet.cpp:1754
const std::vector< CTxIn > vin
Definition: transaction.h:292
bool HasWalletSpend(const uint256 &txid) const
Check if a given transaction has any of its outputs spent by another transaction in the wallet...
Definition: wallet.cpp:513
mapValue_t mapValue
Key/value map with information about the transaction.
Definition: wallet.h:318
std::string ToString() const
Definition: uint256.cpp:95
static CAmount GetRequiredFee(unsigned int nTxBytes)
Return the minimum required fee taking into account the floating relay fee and user set minimum trans...
Definition: wallet.cpp:3109
indexed_transaction_set mapTx
Definition: txmempool.h:524
CAmount nNewFee
Definition: feebumper.h:58
int64_t CAmount
Amount in lius (Can be negative)
Definition: amount.h:15
#define AssertLockHeld(cs)
Definition: sync.h:85
CBlockPolicyEstimator feeEstimator
Definition: validation.cpp:106
bool signTransaction(CWallet *pWallet)
Definition: feebumper.cpp:233
bool signalRbf
Signal BIP-125 replace by fee.
Definition: coincontrol.h:31
CAmount nOldFee
Definition: feebumper.h:57
CTransactionRef tx
Definition: wallet.h:211
bool IsNull() const
Definition: uint256.h:38
#define LOCK(cs)
Definition: sync.h:175
An output of a transaction.
Definition: transaction.h:131
std::vector< CTxOut > vout
Definition: transaction.h:393
unsigned int fTimeReceivedIsTxTime
Definition: wallet.h:320
std::string FormatMoney(const CAmount &n)
Money parsing/formatting utilities.
CAmount GetDustThreshold(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:18
CCriticalSection cs
Definition: txmempool.h:523
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:287
bool IsInvalid() const
Definition: validation.h:69
std::string GetRejectReason() const
Definition: validation.h:89
#define LogPrint(category,...)
Definition: util.h:164
CAmount GetFee(size_t nBytes) const
Return the fee in liu for the given size in bytes.
Definition: feerate.cpp:23
Capture information about block/transaction validation.
Definition: validation.h:27
256-bit opaque blob.
Definition: uint256.h:132
ArgsManager gArgs
Definition: util.cpp:94
static CAmount GetMinimumFee(unsigned int nTxBytes, const CCoinControl &coin_control, const CTxMemPool &pool, const CBlockPolicyEstimator &estimator, FeeCalculation *feeCalc)
Estimate the minimum fee considering user set parameters and the required fee.
Definition: wallet.cpp:3114
std::string FormatStateMessage(const CValidationState &state)
Convert CValidationState to a human-readable message for logging.
Definition: validation.cpp:407
A key allocated from the key pool.
Definition: wallet.h:1209
std::string GetArg(const std::string &strArg, const std::string &strDefault)
Return string argument or default value.
Definition: util.cpp:504
bool SignalsOptInRBF(const CTransaction &tx)
Definition: rbf.cpp:7
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances...
Definition: wallet.h:672
Fee rate in liu per kilobyte: CAmount / kB.
Definition: feerate.h:20
CMutableTransaction mtx
Definition: feebumper.h:54
std::unique_ptr< CConnman > g_connman
Definition: init.cpp:75
std::map< uint256, CWalletTx > mapWallet
Definition: wallet.h:815
A mutable version of CTransaction.
Definition: transaction.h:390
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:275
CFeeRate incrementalRelayFee
Definition: policy.cpp:250
CFeeBumper(const CWallet *pWalletIn, const uint256 txidIn, const CCoinControl &coin_control, CAmount totalFee)
Definition: feebumper.cpp:70
bool preconditionChecks(const CWallet *pWallet, const CWalletTx &wtx)
Definition: feebumper.cpp:45
bool commit(CWallet *pWalletNonConst)
Definition: feebumper.cpp:238
std::vector< std::pair< std::string, std::string > > vOrderForm
Definition: wallet.h:319
bool CommitTransaction(CWalletTx &wtxNew, CReserveKey &reservekey, CConnman *connman, CValidationState &state)
Call after CreateTransaction unless you want to abort.
Definition: wallet.cpp:3045
CFeeRate dustRelayFee
Definition: policy.cpp:251