Skip to content

Commit fa86190

Browse files
author
MarcoFalke
committed
rpc: Allow fullrbf fee bump
Also, fix the incorrect documention of the 'replaceable' RPC argument with respect to sequence number handling. The docs were incorrect before, so the fix could be extracted, but it seems fine to include here as well.
1 parent 6876e50 commit fa86190

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
@@ -990,9 +990,9 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
990990
const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)};
991991

992992
return RPCHelpMan{method_name,
993-
"\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
993+
"Bumps the fee of a transaction T, replacing it with a new transaction B.\n"
994994
+ std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
995-
"An opt-in RBF transaction with the given txid must be in the wallet.\n"
995+
"A transaction with the given txid must be in the wallet.\n"
996996
"The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n"
997997
"It may add a new change output if one does not already exist.\n"
998998
"All inputs in the original transaction will be included in the replacement transaction.\n"
@@ -1012,10 +1012,11 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
10121012
"\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
10131013
"Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
10141014
"WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
1015-
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
1015+
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true},
1016+
"Whether the new transaction should be\n"
10161017
"marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
1017-
"be left unchanged from the original. If false, any input sequence numbers in the\n"
1018-
"original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
1018+
"be set to 0xfffffffd. If false, any input sequence numbers in the\n"
1019+
"transaction will be set to 0xfffffffe\n"
10191020
"so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
10201021
"still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
10211022
"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 (
@@ -93,7 +94,7 @@ def run_test(self):
9394
test_simple_bumpfee_succeeds(self, mode, rbf_node, peer_node, dest_address)
9495
self.test_invalid_parameters(rbf_node, peer_node, dest_address)
9596
test_segwit_bumpfee_succeeds(self, rbf_node, dest_address)
96-
test_nonrbf_bumpfee_fails(self, peer_node, dest_address)
97+
test_nonrbf_bumpfee_succeeds(self, peer_node, dest_address)
9798
test_notmine_bumpfee(self, rbf_node, peer_node, dest_address)
9899
test_bumpfee_with_descendant_fails(self, rbf_node, rbf_node_address, dest_address)
99100
test_bumpfee_with_abandoned_descendant_succeeds(self, rbf_node, rbf_node_address, dest_address)
@@ -371,10 +372,10 @@ def test_segwit_bumpfee_succeeds(self, rbf_node, dest_address):
371372
self.clear_mempool()
372373

373374

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

380381

@@ -677,11 +678,20 @@ def test_rebumping(self, rbf_node, dest_address):
677678

678679

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

687697

0 commit comments

Comments
 (0)