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.
5 #include "consensus/validation.h"
6 #include "wallet/feebumper.h"
7 #include "wallet/wallet.h"
8 #include "policy/policy.h"
9 #include "policy/rbf.h"
10 #include "validation.h" //for mempool access
11 #include "txmempool.h"
12 #include "utilmoneystr.h"
16 // Calculate the size of the transaction assuming all signatures are max size
17 // Use DummySignatureCreator, which inserts 72 byte signatures everywhere.
18 // TODO: re-use this in CWallet::CreateTransaction (right now
19 // CreateTransaction uses the constructed dummy-signed tx to do a priority
20 // calculation, but we should be able to refactor after priority is removed).
21 // NOTE: this requires that all inputs must be in mapWallet (eg the tx should
23 int64_t CalculateMaximumSignedTxSize(const CWallet
*pWallet
, const CTransaction
&tx
)
25 CMutableTransaction
txNew(tx
);
26 std::vector
<std::pair
<const CWalletTx
*, unsigned int>> vCoins
;
27 // Look up the inputs. We should have already checked that this transaction
28 // IsAllFromMe(ISMINE_SPENDABLE), so every input should already be in our
29 // wallet, with a valid index into the vout array.
30 for (auto& input
: tx
.vin
) {
31 const auto mi
= pWallet
->mapWallet
.find(input
.prevout
.hash
);
32 assert(mi
!= pWallet
->mapWallet
.end() && input
.prevout
.n
< mi
->second
.tx
->vout
.size());
33 vCoins
.emplace_back(std::make_pair(&(mi
->second
), input
.prevout
.n
));
35 if (!pWallet
->DummySignTx(txNew
, vCoins
)) {
36 // This should never happen, because IsAllFromMe(ISMINE_SPENDABLE)
37 // implies that we can sign for every input.
40 return GetVirtualTransactionSize(txNew
);
43 CFeeBumper::CFeeBumper(const CWallet
*pWallet
, const uint256 txidIn
, int newConfirmTarget
, bool specifiedConfirmTarget
, CAmount totalFee
, bool newTxReplaceable
)
51 AssertLockHeld(pWallet
->cs_wallet
);
52 if (!pWallet
->mapWallet
.count(txid
)) {
53 vErrors
.push_back("Invalid or non-wallet transaction id");
54 currentResult
= BumpFeeResult::INVALID_ADDRESS_OR_KEY
;
57 auto it
= pWallet
->mapWallet
.find(txid
);
58 const CWalletTx
& wtx
= it
->second
;
60 if (pWallet
->HasWalletSpend(txid
)) {
61 vErrors
.push_back("Transaction has descendants in the wallet");
62 currentResult
= BumpFeeResult::INVALID_PARAMETER
;
68 auto it_mp
= mempool
.mapTx
.find(txid
);
69 if (it_mp
!= mempool
.mapTx
.end() && it_mp
->GetCountWithDescendants() > 1) {
70 vErrors
.push_back("Transaction has descendants in the mempool");
71 currentResult
= BumpFeeResult::INVALID_PARAMETER
;
76 if (wtx
.GetDepthInMainChain() != 0) {
77 vErrors
.push_back("Transaction has been mined, or is conflicted with a mined transaction");
78 currentResult
= BumpFeeResult::WALLET_ERROR
;
82 if (!SignalsOptInRBF(wtx
)) {
83 vErrors
.push_back("Transaction is not BIP 125 replaceable");
84 currentResult
= BumpFeeResult::WALLET_ERROR
;
88 if (wtx
.mapValue
.count("replaced_by_txid")) {
89 vErrors
.push_back(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", txid
.ToString(), wtx
.mapValue
.at("replaced_by_txid")));
90 currentResult
= BumpFeeResult::WALLET_ERROR
;
94 // check that original tx consists entirely of our inputs
95 // 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)
96 if (!pWallet
->IsAllFromMe(wtx
, ISMINE_SPENDABLE
)) {
97 vErrors
.push_back("Transaction contains inputs that don't belong to this wallet");
98 currentResult
= BumpFeeResult::WALLET_ERROR
;
102 // figure out which output was change
103 // if there was no change output or multiple change outputs, fail
105 for (size_t i
= 0; i
< wtx
.tx
->vout
.size(); ++i
) {
106 if (pWallet
->IsChange(wtx
.tx
->vout
[i
])) {
108 vErrors
.push_back("Transaction has multiple change outputs");
109 currentResult
= BumpFeeResult::WALLET_ERROR
;
116 vErrors
.push_back("Transaction does not have a change output");
117 currentResult
= BumpFeeResult::WALLET_ERROR
;
121 // Calculate the expected size of the new transaction.
122 int64_t txSize
= GetVirtualTransactionSize(*(wtx
.tx
));
123 const int64_t maxNewTxSize
= CalculateMaximumSignedTxSize(pWallet
, *wtx
.tx
);
124 if (maxNewTxSize
< 0) {
125 vErrors
.push_back("Transaction contains inputs that cannot be signed");
126 currentResult
= BumpFeeResult::INVALID_ADDRESS_OR_KEY
;
130 // calculate the old fee and fee-rate
131 nOldFee
= wtx
.GetDebit(ISMINE_SPENDABLE
) - wtx
.tx
->GetValueOut();
132 CFeeRate
nOldFeeRate(nOldFee
, txSize
);
133 CFeeRate nNewFeeRate
;
134 // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
135 // future proof against changes to network wide policy for incremental relay
136 // fee that our node may not be aware of.
137 CFeeRate walletIncrementalRelayFee
= CFeeRate(WALLET_INCREMENTAL_RELAY_FEE
);
138 if (::incrementalRelayFee
> walletIncrementalRelayFee
) {
139 walletIncrementalRelayFee
= ::incrementalRelayFee
;
143 CAmount minTotalFee
= nOldFeeRate
.GetFee(maxNewTxSize
) + ::incrementalRelayFee
.GetFee(maxNewTxSize
);
144 if (totalFee
< minTotalFee
) {
145 vErrors
.push_back(strprintf("Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)",
146 FormatMoney(minTotalFee
), FormatMoney(nOldFeeRate
.GetFee(maxNewTxSize
)), FormatMoney(::incrementalRelayFee
.GetFee(maxNewTxSize
))));
147 currentResult
= BumpFeeResult::INVALID_PARAMETER
;
150 CAmount requiredFee
= pWallet
->GetRequiredFee(maxNewTxSize
);
151 if (totalFee
< requiredFee
) {
152 vErrors
.push_back(strprintf("Insufficient totalFee (cannot be less than required fee %s)",
153 FormatMoney(requiredFee
)));
154 currentResult
= BumpFeeResult::INVALID_PARAMETER
;
158 nNewFeeRate
= CFeeRate(totalFee
, maxNewTxSize
);
160 // if user specified a confirm target then don't consider any global payTxFee
161 if (specifiedConfirmTarget
) {
162 nNewFee
= pWallet
->GetMinimumFee(maxNewTxSize
, newConfirmTarget
, mempool
, CAmount(0));
164 // otherwise use the regular wallet logic to select payTxFee or default confirm target
166 nNewFee
= pWallet
->GetMinimumFee(maxNewTxSize
, newConfirmTarget
, mempool
);
169 nNewFeeRate
= CFeeRate(nNewFee
, maxNewTxSize
);
171 // New fee rate must be at least old rate + minimum incremental relay rate
172 // walletIncrementalRelayFee.GetFeePerK() should be exact, because it's initialized
173 // in that unit (fee per kb).
174 // However, nOldFeeRate is a calculated value from the tx fee/size, so
175 // add 1 satoshi to the result, because it may have been rounded down.
176 if (nNewFeeRate
.GetFeePerK() < nOldFeeRate
.GetFeePerK() + 1 + walletIncrementalRelayFee
.GetFeePerK()) {
177 nNewFeeRate
= CFeeRate(nOldFeeRate
.GetFeePerK() + 1 + walletIncrementalRelayFee
.GetFeePerK());
178 nNewFee
= nNewFeeRate
.GetFee(maxNewTxSize
);
182 // Check that in all cases the new fee doesn't violate maxTxFee
183 if (nNewFee
> maxTxFee
) {
184 vErrors
.push_back(strprintf("Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)",
185 FormatMoney(nNewFee
), FormatMoney(maxTxFee
)));
186 currentResult
= BumpFeeResult::WALLET_ERROR
;
190 // check that fee rate is higher than mempool's minimum fee
191 // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
192 // This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
193 // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
194 // moment earlier. In this case, we report an error to the user, who may use totalFee to make an adjustment.
195 CFeeRate minMempoolFeeRate
= mempool
.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE
) * 1000000);
196 if (nNewFeeRate
.GetFeePerK() < minMempoolFeeRate
.GetFeePerK()) {
197 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())));
198 currentResult
= BumpFeeResult::WALLET_ERROR
;
202 // Now modify the output to increase the fee.
203 // If the output is not large enough to pay the fee, fail.
204 CAmount nDelta
= nNewFee
- nOldFee
;
207 CTxOut
* poutput
= &(mtx
.vout
[nOutput
]);
208 if (poutput
->nValue
< nDelta
) {
209 vErrors
.push_back("Change output is too small to bump the fee");
210 currentResult
= BumpFeeResult::WALLET_ERROR
;
214 // If the output would become dust, discard it (converting the dust to fee)
215 poutput
->nValue
-= nDelta
;
216 if (poutput
->nValue
<= poutput
->GetDustThreshold(::dustRelayFee
)) {
217 LogPrint(BCLog::RPC
, "Bumping fee and discarding dust output\n");
218 nNewFee
+= poutput
->nValue
;
219 mtx
.vout
.erase(mtx
.vout
.begin() + nOutput
);
222 // Mark new tx not replaceable, if requested.
223 if (!newTxReplaceable
) {
224 for (auto& input
: mtx
.vin
) {
225 if (input
.nSequence
< 0xfffffffe) input
.nSequence
= 0xfffffffe;
229 currentResult
= BumpFeeResult::OK
;
232 bool CFeeBumper::commit(CWallet
*pWallet
)
234 AssertLockHeld(pWallet
->cs_wallet
);
236 if (txid
.IsNull() || !pWallet
->mapWallet
.count(txid
)) {
237 vErrors
.push_back("Invalid or non-wallet transaction id");
238 currentResult
= BumpFeeResult::MISC_ERROR
;
240 CWalletTx
& oldWtx
= pWallet
->mapWallet
[txid
];
242 CWalletTx
wtxBumped(pWallet
, MakeTransactionRef(std::move(mtx
)));
243 // commit/broadcast the tx
244 CReserveKey
reservekey(pWallet
);
245 wtxBumped
.mapValue
= oldWtx
.mapValue
;
246 wtxBumped
.mapValue
["replaces_txid"] = oldWtx
.GetHash().ToString();
247 wtxBumped
.vOrderForm
= oldWtx
.vOrderForm
;
248 wtxBumped
.strFromAccount
= oldWtx
.strFromAccount
;
249 wtxBumped
.fTimeReceivedIsTxTime
= true;
250 wtxBumped
.fFromMe
= true;
251 CValidationState state
;
252 if (!pWallet
->CommitTransaction(wtxBumped
, reservekey
, g_connman
.get(), state
)) {
253 // NOTE: CommitTransaction never returns false, so this should never happen.
254 vErrors
.push_back(strprintf("Error: The transaction was rejected! Reason given: %s", state
.GetRejectReason()));
258 bumpedTxid
= wtxBumped
.GetHash();
259 if (state
.IsInvalid()) {
260 // This can happen if the mempool rejected the transaction. Report
261 // what happened in the "errors" response.
262 vErrors
.push_back(strprintf("Error: The transaction was rejected: %s", FormatStateMessage(state
)));
265 // mark the original tx as bumped
266 if (!pWallet
->MarkReplaced(oldWtx
.GetHash(), wtxBumped
.GetHash())) {
267 // TODO: see if JSON-RPC has a standard way of returning a response
268 // along with an exception. It would be good to return information about
269 // wtxBumped to the caller even if marking the original transaction
270 // replaced does not succeed for some reason.
271 vErrors
.push_back("Error: Created new bumpfee transaction but could not mark the original transaction as replaced.");