Skip to content

Commit 06439a1

Browse files
committed
Merge bitcoin/bitcoin#31953: rpc: Allow fullrbf fee bump in (psbt)bumpfee
fa86190 rpc: Allow fullrbf fee bump (MarcoFalke) Pull request description: The RPCs (psbt)bumpfee, and the GUI, reject fee bumps when BIP 125 signalling is absent in the transaction even when the mempool and other RPCs allow them. Fix the confusion by allowing the fee bump. This is done after fullrbf is always on (bitcoin/bitcoin#30592) ACKs for top commit: 1440000bytes: reACK bitcoin/bitcoin@fa86190 achow101: ACK fa86190 w0xlt: ACK bitcoin/bitcoin@fa86190 rkrux: reACK fa86190 glozow: ACK fa86190 Tree-SHA512: b2ffe8dcadbe71e9be767a16cf8aa0bf383c2de7aa1aee9438d125f444e24f3f7e4f02ddb28981bd3b8b645b6a24a407b4ad6bb0b21946ae637e78f6386e05bf
2 parents 3e78ac6 + fa86190 commit 06439a1

File tree

6 files changed

+35
-19
lines changed

6 files changed

+35
-19
lines changed

doc/release-notes-31953.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# RPC
2+
3+
- The RPCs psbtbumpfee and bumpfee allow a replacement under fullrbf and no
4+
longer require BIP-125 signalling. (#31953)
5+
6+
# GUI
7+
8+
- A transaction's fee bump is allowed under fullrbf and no longer requires
9+
BIP-125 signalling. (#31953)

src/qt/test/wallettests.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ void TestGUI(interfaces::Node& node, const std::shared_ptr<CWallet>& wallet)
300300
QVERIFY(FindTx(*transactionTableModel, txid1).isValid());
301301
QVERIFY(FindTx(*transactionTableModel, txid2).isValid());
302302

303-
// Call bumpfee. Test disabled, canceled, enabled, then failing cases.
304-
BumpFee(transactionView, txid1, /*expectDisabled=*/true, /*expectError=*/"not BIP 125 replaceable", /*cancel=*/false);
303+
// Call bumpfee. Test canceled fullrbf bump, canceled bip-125-rbf bump, passing bump, and then failing bump.
304+
BumpFee(transactionView, txid1, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
305305
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/true);
306306
BumpFee(transactionView, txid2, /*expectDisabled=*/false, /*expectError=*/{}, /*cancel=*/false);
307307
BumpFee(transactionView, txid2, /*expectDisabled=*/true, /*expectError=*/"already bumped", /*cancel=*/false);

src/wallet/feebumper.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,6 @@ static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWallet
4040
return feebumper::Result::WALLET_ERROR;
4141
}
4242

43-
if (!SignalsOptInRBF(*wtx.tx)) {
44-
errors.emplace_back(Untranslated("Transaction is not BIP 125 replaceable"));
45-
return feebumper::Result::WALLET_ERROR;
46-
}
47-
4843
if (wtx.mapValue.count("replaced_by_txid")) {
4944
errors.push_back(Untranslated(strprintf("Cannot bump transaction %s which was already bumped by transaction %s", wtx.GetHash().ToString(), wtx.mapValue.at("replaced_by_txid"))));
5045
return feebumper::Result::WALLET_ERROR;

src/wallet/rpc/spend.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -995,9 +995,9 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
995995
const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)};
996996

997997
return RPCHelpMan{method_name,
998-
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
998+
"Bumps the fee of a transaction T, replacing it with a new transaction B.\n"
999999
+ std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
1000-
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
1000+
"A transaction with the given txid must be in the wallet.\n"
10011001
"The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n"
10021002
"It may add a new change output if one does not already exist.\n"
10031003
"All inputs in the original transaction will be included in the replacement transaction.\n"
@@ -1017,10 +1017,11 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
10171017
"\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
10181018
"Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
10191019
"WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
1020-
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
1020+
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true},
1021+
"Whether the new transaction should be\n"
10211022
"marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
1022-
"be left unchanged from the original. If false, any input sequence numbers in the\n"
1023-
"original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
1023+
"be set to 0xfffffffd. If false, any input sequence numbers in the\n"
1024+
"transaction will be set to 0xfffffffe\n"
10241025
"so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
10251026
"still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
10261027
"are replaceable).\n"},

test/functional/test_framework/messages.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
MAX_MONEY = 21000000 * COIN
4343

4444
MAX_BIP125_RBF_SEQUENCE = 0xfffffffd # Sequence number that is rbf-opt-in (BIP 125) and csv-opt-out (BIP 68)
45+
MAX_SEQUENCE_NONFINAL = 0xfffffffe # Sequence number that is csv-opt-out (BIP 68)
4546
SEQUENCE_FINAL = 0xffffffff # Sequence number that disables nLockTime if set for every input of a tx
4647

4748
MAX_PROTOCOL_MESSAGE_LENGTH = 4000000 # Maximum length of incoming protocol messages

test/functional/wallet_bumpfee.py

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
)
2121
from test_framework.messages import (
2222
MAX_BIP125_RBF_SEQUENCE,
23+
MAX_SEQUENCE_NONFINAL,
2324
)
2425
from test_framework.test_framework import BitcoinTestFramework
2526
from test_framework.util import (
@@ -94,7 +95,7 @@ def run_test(self):
9495
test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address)
9596
self.test_invalid_parameters(rbf_node, peer_node, dest_address)
9697
test_segwit_bumpfee_succeeds(self, rbf_node, dest_address)
97-
test_nonrbf_bumpfee_fails(self, peer_node, dest_address)
98+
test_nonrbf_bumpfee_succeeds(self, peer_node, dest_address)
9899
test_notmine_bumpfee(self, rbf_node, peer_node, dest_address)
99100
test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address)
100101
test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address)
@@ -372,10 +373,10 @@ def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address):
372373
self.clear_mempool()
373374

374375

375-
def test_nonrbf_bumpfee_fails(self, peer_node, dest_address):
376-
self.log.info('Test that we cannot replace a non RBF transaction')
376+
def test_nonrbf_bumpfee_succeeds(self, peer_node, dest_address):
377+
self.log.info("Test that we can replace a non RBF transaction")
377378
not_rbfid = peer_node.sendtoaddress(dest_address, Decimal("0.00090000"))
378-
assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", peer_node.bumpfee, not_rbfid)
379+
peer_node.bumpfee(not_rbfid)
379380
self.clear_mempool()
380381

381382

@@ -678,11 +679,20 @@ def test_rebumping(self, rbf_node, dest_address):
678679

679680

680681
def test_rebumping_not_replaceable(self, rbf_node, dest_address):
681-
self.log.info('Test that re-bumping non-replaceable fails')
682+
self.log.info("Test that re-bumping non-replaceable passes")
682683
rbfid = spend_one_input(rbf_node, dest_address)
684+
685+
def check_sequence(tx, seq_in):
686+
tx = rbf_node.getrawtransaction(tx["txid"])
687+
tx = rbf_node.decoderawtransaction(tx)
688+
seq = [i["sequence"] for i in tx["vin"]]
689+
assert_equal(seq, [seq_in])
690+
683691
bumped = rbf_node.bumpfee(rbfid, fee_rate=ECONOMICAL, replaceable=False)
684-
assert_raises_rpc_error(-4, "Transaction is not BIP 125 replaceable", rbf_node.bumpfee, bumped["txid"],
685-
{"fee_rate": NORMAL})
692+
check_sequence(bumped, MAX_SEQUENCE_NONFINAL)
693+
bumped = rbf_node.bumpfee(bumped["txid"], {"fee_rate": NORMAL})
694+
check_sequence(bumped, MAX_BIP125_RBF_SEQUENCE)
695+
686696
self.clear_mempool()
687697

688698

0 commit comments

Comments
 (0)