From 4691ccacad68e42eb35dadf75144cefc63c33319 Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 4 Nov 2026 04:53:06 +0000 Subject: [PATCH 1/2] Merge bitcoin/bitcoin#28604: test: Use feerate higher than minrelay fee in wallet_fundraw 05af4dfa50c229c8533d9a71e046c9387e1cdb27 test: Use feerate higher than minrelay fee in wallet_fundraw (Andrew Chow) Pull request description: The external input weight test in wallet_fundrawtransaction.py made transactions at the minimum relay fee. However due to ECDSA sometimes making a shorter signature than expected, the size estimate (and therefore the funded fee) ends up being a little bit too low, which results in the final transaction being under the min relay fee. We can compensate for this by just using a feerate higher than the minrelayfee as the actual feerate itself does not matter in this test. Fixes #28437 ACKs for top commit: glozow: utACK 05af4dfa50c229c8533d9a71e046c9387e1cdb27, seems right to me Tree-SHA512: 3e08f052db32d891515d32b27b2d7c5bcbfc77d5ea457eefc75e8aa6d40960278e537c1e8bffe7ddc211949c78e14145a671a8d34e7e1bb15438773cb0d9e89d Co-Authored-By: Claude Opus 5.5 --- test/functional/wallet_fundrawtransaction.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index 4530ac92d051..d918e6c0d2c9 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1023,19 +1023,19 @@ def test_external_inputs(self): high_input_weight = input_weight * 2 # Funding should also work if the input weight is provided - funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": input_weight}]) + funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": input_weight}], fee_rate=2) signed_tx = wallet.signrawtransactionwithwallet(funded_tx["hex"]) signed_tx = self.nodes[0].signrawtransactionwithwallet(signed_tx["hex"]) assert_equal(self.nodes[0].testmempoolaccept([signed_tx["hex"]])[0]["allowed"], True) assert_equal(signed_tx["complete"], True) # Reducing the weight should have a lower fee - funded_tx2 = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": low_input_weight}]) + funded_tx2 = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": low_input_weight}], fee_rate=2) assert_greater_than(funded_tx["fee"], funded_tx2["fee"]) # Increasing the weight should have a higher fee - funded_tx2 = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": high_input_weight}]) + funded_tx2 = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": high_input_weight}], fee_rate=2) assert_greater_than(funded_tx2["fee"], funded_tx["fee"]) # The provided weight should override the calculated weight when solving data is provided - funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": high_input_weight}]) + funded_tx3 = wallet.fundrawtransaction(raw_tx, solving_data={"descriptors": [desc]}, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": high_input_weight}], fee_rate=2) assert_equal(funded_tx2["fee"], funded_tx3["fee"]) # The feerate should be met funded_tx4 = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": high_input_weight}], fee_rate=10) @@ -1044,8 +1044,8 @@ def test_external_inputs(self): assert_fee_amount(funded_tx4["fee"], tx4_size, Decimal(0.0001)) # Funding with weight at csuint boundaries should not cause problems - funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": 255}]) - funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": 65539}]) + funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": 255}], fee_rate=2) + funded_tx = wallet.fundrawtransaction(raw_tx, input_sizes=[{"txid": ext_utxo["txid"], "vout": ext_utxo["vout"], "size": 65539}], fee_rate=2) self.nodes[2].unloadwallet("extfund") From 75932fa7742ad7af6922a900bd166d3abadc8cff Mon Sep 17 00:00:00 2001 From: pasta Date: Wed, 4 Nov 2026 04:55:35 +0000 Subject: [PATCH 2/2] test: stop test_22670 failing when a signature comes out short test_22670 restarts the node with -minrelaytxfee=0.1, so the wallet funds its transactions at 0.1 DASH/kB on its size estimate. That is also testmempoolaccept's default maxfeerate. The estimate assumes 71-byte signatures, and about one ECDSA signature in 64 is a byte shorter, so with three inputs the signed transaction is 518 bytes instead of 519 in about 5% of runs, and testmempoolaccept rejects it with max-fee-exceeded. Upstream doesn't hit this, because a byte of witness data rarely changes the vsize. Check only the minimum relay fee, which is what the test is about. Co-Authored-By: Claude Opus 5.5 --- test/functional/wallet_fundrawtransaction.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py index d918e6c0d2c9..8f0577ba739c 100755 --- a/test/functional/wallet_fundrawtransaction.py +++ b/test/functional/wallet_fundrawtransaction.py @@ -1294,7 +1294,9 @@ def do_fund_send(target): assert signed_tx["complete"] decoded_tx = tester.decoderawtransaction(signed_tx["hex"]) assert_equal(len(decoded_tx["vin"]), 3) - assert tester.testmempoolaccept([signed_tx["hex"]])[0]["allowed"] + # The fee pays -minrelaytxfee, which equals the default maxfeerate, on the size the wallet estimates. + # An ECDSA signature can be a byte shorter than estimated, which would exceed maxfeerate. + assert tester.testmempoolaccept([signed_tx["hex"]], maxfeerate=0)[0]["allowed"] # We want to choose more value than is available in 2 inputs when considering the fee, # but not enough to need 3 inputs when not considering the fee.