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