Skip to content

Commit 78322df

Browse files
fanquakejasonbcox
authored andcommitted
Merge #17568: wallet: fix when sufficient preset inputs and subtractFeeFromOutputs
Summary: eadd1304c81e0b89178e4cc7630bd31650850c85 tests: Add a test for funding with sufficient preset inputs and subtractFeeFromOutputs (Andrew Chow) ff330badd45067cb520b1cfa1844f60a4c9f2031 Default to bnb_used = false as there are many cases where BnB is not used (Andrew Chow) Pull request description: #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. Backport of Core [[bitcoin/bitcoin#17568 | PR17568]] Depends on D7688 Test Plan: ``` ninja check test_runner.py rpc_fundrawtransaction ``` Reviewers: #bitcoin_abc, majcosta Reviewed By: #bitcoin_abc, majcosta Differential Revision: https://reviews.bitcoinabc.org/D7691
1 parent d54de83 commit 78322df

File tree

2 files changed

+20
-7
lines changed

2 files changed

+20
-7
lines changed

src/wallet/wallet.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2535,12 +2535,12 @@ bool CWallet::SelectCoins(const std::vector<COutput> &vAvailableCoins,
25352535
std::vector<COutput> vCoins(vAvailableCoins);
25362536
Amount value_to_select = nTargetValue;
25372537

2538+
// Default to bnb was not used. If we use it, we set it later
2539+
bnb_used = false;
2540+
25382541
// coin control -> return all selected outputs (we want all selected to go
25392542
// into the transaction for sure)
25402543
if (coin_control.HasSelected() && !coin_control.fAllowOtherInputs) {
2541-
// We didn't use BnB here, so set it to false.
2542-
bnb_used = false;
2543-
25442544
for (const COutput &out : vCoins) {
25452545
if (!out.fSpendable) {
25462546
continue;
@@ -2567,15 +2567,13 @@ bool CWallet::SelectCoins(const std::vector<COutput> &vAvailableCoins,
25672567
const CWalletTx &wtx = it->second;
25682568
// Clearly invalid input, fail
25692569
if (wtx.tx->vout.size() <= outpoint.GetN()) {
2570-
bnb_used = false;
25712570
return false;
25722571
}
25732572
// Just to calculate the marginal byte size
25742573
CInputCoin coin(wtx.tx, outpoint.GetN(),
25752574
wtx.GetSpendSize(outpoint.GetN(), false));
25762575
nValueFromPresetInputs += coin.txout.nValue;
25772576
if (coin.m_input_bytes <= 0) {
2578-
bnb_used = false;
25792577
// Not solvable, can't estimate size for fee
25802578
return false;
25812579
}
@@ -2589,7 +2587,6 @@ bool CWallet::SelectCoins(const std::vector<COutput> &vAvailableCoins,
25892587
}
25902588
setPresetCoins.insert(coin);
25912589
} else {
2592-
bnb_used = false;
25932590
return false; // TODO: Allow non-wallet inputs
25942591
}
25952592
}
@@ -3018,7 +3015,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock &locked_chainIn,
30183015
}
30193016

30203017
// Choose coins to use
3021-
bool bnb_used;
3018+
bool bnb_used = false;
30223019
if (pick_new_inputs) {
30233020
nValueIn = Amount::zero();
30243021
setCoins.clear();

test/functional/rpc_fundrawtransaction.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def run_test(self):
9090
self.test_option_feerate()
9191
self.test_address_reuse()
9292
self.test_option_subtract_fee_from_outputs()
93+
self.test_subtract_fee_with_presets()
9394

9495
def test_change_position(self):
9596
# ensure that setting changePosition in fundraw with an exact match is
@@ -848,6 +849,21 @@ def test_option_subtract_fee_from_outputs(self):
848849
# the total subtracted from the outputs is equal to the fee
849850
assert_equal(share[0] + share[2] + share[3], result[0]['fee'])
850851

852+
def test_subtract_fee_with_presets(self):
853+
self.log.info(
854+
"Test fundrawtxn subtract fee from outputs with preset inputs that are sufficient")
855+
856+
addr = self.nodes[0].getnewaddress()
857+
txid = self.nodes[0].sendtoaddress(addr, 10)
858+
vout = find_vout_for_address(self.nodes[0], txid, addr)
859+
860+
rawtx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], [
861+
{self.nodes[0].getnewaddress(): 5}])
862+
fundedtx = self.nodes[0].fundrawtransaction(
863+
rawtx, {'subtractFeeFromOutputs': [0]})
864+
signedtx = self.nodes[0].signrawtransactionwithwallet(fundedtx['hex'])
865+
self.nodes[0].sendrawtransaction(signedtx['hex'])
866+
851867

852868
if __name__ == '__main__':
853869
RawTransactionsTest().main()

0 commit comments

Comments
 (0)