Skip to content

Commit 612f1e4

Browse files
committed
bumpfee: Calculate fee by looking up UTXOs
Instead of calculating the fee by using what is stored in the wallet, calculate it by looking up the UTXOs.
1 parent 9eaef10 commit 612f1e4

File tree

1 file changed

+29
-7
lines changed

1 file changed

+29
-7
lines changed

src/wallet/feebumper.cpp

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
6161
}
6262

6363
//! Check if the user provided a valid feeRate
64-
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<bilingual_str>& errors)
64+
static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
6565
{
6666
// check that fee rate is higher than mempool's minimum fee
6767
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
@@ -83,8 +83,6 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wt
8383
CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
8484

8585
// Given old total fee and transaction size, calculate the old feeRate
86-
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
87-
CAmount old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
8886
const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
8987
CFeeRate nOldFeeRate(old_fee, txSize);
9088
// Min total fee is old fee + relay fee
@@ -169,13 +167,37 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
169167
}
170168
const CWalletTx& wtx = it->second;
171169

170+
// Retrieve all of the UTXOs and add them to coin control
171+
// While we're here, calculate the input amount
172+
std::map<COutPoint, Coin> coins;
173+
CAmount input_value = 0;
174+
for (const CTxIn& txin : wtx.tx->vin) {
175+
coins[txin.prevout]; // Create empty map entry keyed by prevout.
176+
}
177+
wallet.chain().findCoins(coins);
178+
for (const CTxIn& txin : wtx.tx->vin) {
179+
const Coin& coin = coins.at(txin.prevout);
180+
if (coin.out.IsNull()) {
181+
errors.push_back(Untranslated(strprintf("%s:%u is already spent", txin.prevout.hash.GetHex(), txin.prevout.n)));
182+
return Result::MISC_ERROR;
183+
}
184+
if (wallet.IsMine(txin.prevout)) {
185+
new_coin_control.Select(txin.prevout);
186+
} else {
187+
new_coin_control.SelectExternal(txin.prevout, coin.out);
188+
}
189+
input_value += coin.out.nValue;
190+
}
191+
172192
Result result = PreconditionChecks(wallet, wtx, errors);
173193
if (result != Result::OK) {
174194
return result;
175195
}
176196

177197
// Fill in recipients(and preserve a single change key if there is one)
198+
// While we're here, calculate the output amount
178199
std::vector<CRecipient> recipients;
200+
CAmount output_value = 0;
179201
for (const auto& output : wtx.tx->vout) {
180202
if (!OutputIsChange(wallet, output)) {
181203
CRecipient recipient = {output.scriptPubKey, output.nValue, false};
@@ -185,16 +207,16 @@ Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCo
185207
ExtractDestination(output.scriptPubKey, change_dest);
186208
new_coin_control.destChange = change_dest;
187209
}
210+
output_value += output.nValue;
188211
}
189212

190-
isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
191-
old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
213+
old_fee = input_value - output_value;
192214

193215
if (coin_control.m_feerate) {
194216
// The user provided a feeRate argument.
195217
// We calculate this here to avoid compiler warning on the cs_wallet lock
196-
const int64_t maxTxSize{CalculateMaximumSignedTxSize(*wtx.tx, &wallet).vsize};
197-
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, errors);
218+
const int64_t maxTxSize{CalculateMaximumSignedTxSize(*wtx.tx, &wallet, &new_coin_control).vsize};
219+
Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
198220
if (res != Result::OK) {
199221
return res;
200222
}

0 commit comments

Comments
 (0)