Skip to content

Commit 19698ac

Browse files
committed
Merge bitcoin#17568: wallet: fix when sufficient preset inputs and subtractFeeFromOutputs
eadd130 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow) ff330ba Default to bnb_used = false as there are many cases where BnB is not used (Andrew Chow) Pull request description: bitcoin#17290 introduced a bug where, when we had preset inputs that covered the amount being sent and subtractFeeFrromOutputs was being used, transaction funding would result in a `Fee exceeds maximum configured by -maxtxfee` error. This was happening because we weren't setting `bnb_used = false` when the preset inputs were used as it should have been. This resulted in a too high fee because the change would go to fees accidentally. Apparently this particular case doesn't have a test, so I've added one as well. ACKs for top commit: Sjors: ACK eadd130. I can't get this new test to fail on macOS (without this PR). It passes whether or not I compile with `--enable-debug`. It does fail on Ubuntu. Yay undefined behavior... Anyway, it's a useful test. fanquake: ACK eadd130 instagibbs: utACK bitcoin@eadd130 Tree-SHA512: 7286c321f78666eea558cc591174630d210263594df41cab1065417510591ee514ade0e1d0cec8af09a785757da68de82592b013e8fe8d4966cec3254368706e
2 parents 2ecb7e1 + eadd130 commit 19698ac

File tree

2 files changed

+17
-7
lines changed

2 files changed

+17
-7
lines changed

src/wallet/wallet.cpp

+4-7
Original file line numberDiff line numberDiff line change
@@ -2270,12 +2270,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
22702270
std::vector<COutput> vCoins(vAvailableCoins);
22712271
CAmount value_to_select = nTargetValue;
22722272

2273+
// Default to bnb was not used. If we use it, we set it later
2274+
bnb_used = false;
2275+
22732276
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
22742277
if (coin_control.HasSelected() && !coin_control.fAllowOtherInputs)
22752278
{
2276-
// We didn't use BnB here, so set it to false.
2277-
bnb_used = false;
2278-
22792279
for (const COutput& out : vCoins)
22802280
{
22812281
if (!out.fSpendable)
@@ -2300,14 +2300,12 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
23002300
const CWalletTx& wtx = it->second;
23012301
// Clearly invalid input, fail
23022302
if (wtx.tx->vout.size() <= outpoint.n) {
2303-
bnb_used = false;
23042303
return false;
23052304
}
23062305
// Just to calculate the marginal byte size
23072306
CInputCoin coin(wtx.tx, outpoint.n, wtx.GetSpendSize(outpoint.n, false));
23082307
nValueFromPresetInputs += coin.txout.nValue;
23092308
if (coin.m_input_bytes <= 0) {
2310-
bnb_used = false;
23112309
return false; // Not solvable, can't estimate size for fee
23122310
}
23132311
coin.effective_value = coin.txout.nValue - coin_selection_params.effective_fee.GetFee(coin.m_input_bytes);
@@ -2318,7 +2316,6 @@ bool CWallet::SelectCoins(const std::vector<COutput>& vAvailableCoins, const CAm
23182316
}
23192317
setPresetCoins.insert(coin);
23202318
} else {
2321-
bnb_used = false;
23222319
return false; // TODO: Allow non-wallet inputs
23232320
}
23242321
}
@@ -2678,7 +2675,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std
26782675
}
26792676

26802677
// Choose coins to use
2681-
bool bnb_used;
2678+
bool bnb_used = false;
26822679
if (pick_new_inputs) {
26832680
nValueIn = 0;
26842681
setCoins.clear();

test/functional/rpc_fundrawtransaction.py

+13
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ def run_test(self):
9292
self.test_option_feerate()
9393
self.test_address_reuse()
9494
self.test_option_subtract_fee_from_outputs()
95+
self.test_subtract_fee_with_presets()
9596

9697
def test_change_position(self):
9798
"""Ensure setting changePosition in fundraw with an exact match is handled properly."""
@@ -741,5 +742,17 @@ def test_option_subtract_fee_from_outputs(self):
741742
# The total subtracted from the outputs is equal to the fee.
742743
assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
743744

745+
def test_subtract_fee_with_presets(self):
746+
self.log.info("Test fundrawtxn subtract fee from outputs with preset inputs that are sufficient")
747+
748+
addr = self.nodes[0].getnewaddress()
749+
txid = self.nodes[0].sendtoaddress(addr, 10)
750+
vout = find_vout_for_address(self.nodes[0], txid, addr)
751+
752+
rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [{self.nodes[0].getnewaddress(): 5}])
753+
fundedtx = self.nodes[0].fundrawtransaction(rawtx, {'subtractFeeFromOutputs': [0]})
754+
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex'])
755+
self.nodes[0].sendrawtransaction(signedtx['hex'])
756+
744757
if __name__ == '__main__':
745758
RawTransactionsTest().main()

0 commit comments

Comments
 (0)