mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-11-10 22:18:54 +01:00
Merge bitcoin/bitcoin#25610: wallet, rpc: Opt in to RBF by default
ab3c06db1adoc: Release notes for default RBF (Andrew Chow)61d9149e78rpc: Default rbf enabled (Andrew Chow)e3c33637bawallet: Enable -walletrbf by default (Andrew Chow) Pull request description: The GUI currently opts in to RBF by default, but RPCs do not, and `-walletrbf` is default disabled. This PR makes the default in those two places to also opt in. The last time this was proposed (#9527), the primary objections were the novelty at the time, the inability to bump transactions, and the gui not having the option to disable rbf. In the 5 years since, RBF usage has steadily grown, with ~27% of txs opting in. The GUI has the option to enable/disable RBF, and is also defaulted to having it enabled. And we have the ability to bump RBF'd transactions in both the RPC and the GUI. So I think it makes sense to finally change the default to always opt in to RBF. ACKs for top commit: darosior: reACKab3c06db1aaureleoules: ACKab3c06db1a. glozow: utACKab3c06db1aTree-SHA512: 81b012c5033e270f86a87a6a196ccc549eb54b158eebf88e917cc6621d40d7bdcd1566b602688907dd5d364b95a557b29f97dce869cea512e339588262c027b6
This commit is contained in:
12
doc/release-notes-25610.md
Normal file
12
doc/release-notes-25610.md
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
Wallet
|
||||||
|
------
|
||||||
|
|
||||||
|
- The `-walletrbf` startup option will now default to `true`. The
|
||||||
|
wallet will now default to opt-in RBF on transactions that it creates.
|
||||||
|
|
||||||
|
Updated RPCs
|
||||||
|
------------
|
||||||
|
|
||||||
|
- The `replaceable` option for the `createrawtransaction` and
|
||||||
|
`createpsbt` RPCs will now default to `true`. Transactions created
|
||||||
|
with these RPCs will default to having opt-in RBF enabled.
|
||||||
@@ -157,7 +157,7 @@ static std::vector<RPCArg> CreateTxDoc()
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
|
{"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
|
||||||
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{false}, "Marks this transaction as BIP125-replaceable.\n"
|
{"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Marks this transaction as BIP125-replaceable.\n"
|
||||||
"Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
|
"Allows this transaction to be replaced by a transaction with higher fees. If provided, it is an error if explicit sequence numbers are incompatible."},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ static RPCHelpMan createrawtransaction()
|
|||||||
}, true
|
}, true
|
||||||
);
|
);
|
||||||
|
|
||||||
bool rbf = false;
|
std::optional<bool> rbf;
|
||||||
if (!request.params[3].isNull()) {
|
if (!request.params[3].isNull()) {
|
||||||
rbf = request.params[3].isTrue();
|
rbf = request.params[3].isTrue();
|
||||||
}
|
}
|
||||||
@@ -1451,7 +1451,7 @@ static RPCHelpMan createpsbt()
|
|||||||
}, true
|
}, true
|
||||||
);
|
);
|
||||||
|
|
||||||
bool rbf = false;
|
std::optional<bool> rbf;
|
||||||
if (!request.params[3].isNull()) {
|
if (!request.params[3].isNull()) {
|
||||||
rbf = request.params[3].isTrue();
|
rbf = request.params[3].isTrue();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include <util/strencodings.h>
|
#include <util/strencodings.h>
|
||||||
#include <util/translation.h>
|
#include <util/translation.h>
|
||||||
|
|
||||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
|
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf)
|
||||||
{
|
{
|
||||||
if (outputs_in.isNull()) {
|
if (outputs_in.isNull()) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
|
||||||
@@ -60,7 +60,8 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
|
|||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
|
||||||
|
|
||||||
uint32_t nSequence;
|
uint32_t nSequence;
|
||||||
if (rbf) {
|
|
||||||
|
if (rbf.value_or(true)) {
|
||||||
nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
|
nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
|
||||||
} else if (rawTx.nLockTime) {
|
} else if (rawTx.nLockTime) {
|
||||||
nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
|
nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
|
||||||
@@ -132,7 +133,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
|
if (rbf.has_value() && rbf.value() && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
|
||||||
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
|
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
struct bilingual_str;
|
struct bilingual_str;
|
||||||
class FillableSigningProvider;
|
class FillableSigningProvider;
|
||||||
@@ -38,6 +39,6 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
|
|||||||
void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
|
void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
|
||||||
|
|
||||||
/** Create a transaction from univalue parameters */
|
/** Create a transaction from univalue parameters */
|
||||||
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf);
|
CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, std::optional<bool> rbf);
|
||||||
|
|
||||||
#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
|
#endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS{true};
|
|||||||
//! -txconfirmtarget default
|
//! -txconfirmtarget default
|
||||||
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
|
static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
|
||||||
//! -walletrbf default
|
//! -walletrbf default
|
||||||
static const bool DEFAULT_WALLET_RBF = false;
|
static const bool DEFAULT_WALLET_RBF = true;
|
||||||
static const bool DEFAULT_WALLETBROADCAST = true;
|
static const bool DEFAULT_WALLETBROADCAST = true;
|
||||||
static const bool DEFAULT_DISABLE_WALLET = false;
|
static const bool DEFAULT_DISABLE_WALLET = false;
|
||||||
static const bool DEFAULT_WALLETCROSSCHAIN = false;
|
static const bool DEFAULT_WALLETCROSSCHAIN = false;
|
||||||
|
|||||||
@@ -111,7 +111,8 @@ class P2PPermissionsTests(BitcoinTestFramework):
|
|||||||
'vout': 0,
|
'vout': 0,
|
||||||
}], outputs=[{
|
}], outputs=[{
|
||||||
ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
|
ADDRESS_BCRT1_P2WSH_OP_TRUE: 5,
|
||||||
}]),
|
}],
|
||||||
|
replaceable=False),
|
||||||
)
|
)
|
||||||
tx.wit.vtxinwit = [CTxInWitness()]
|
tx.wit.vtxinwit = [CTxInWitness()]
|
||||||
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
|
tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
|
||||||
|
|||||||
@@ -467,7 +467,7 @@ class PSBTTest(BitcoinTestFramework):
|
|||||||
|
|
||||||
# Creator Tests
|
# Creator Tests
|
||||||
for creator in creators:
|
for creator in creators:
|
||||||
created_tx = self.nodes[0].createpsbt(creator['inputs'], creator['outputs'])
|
created_tx = self.nodes[0].createpsbt(inputs=creator['inputs'], outputs=creator['outputs'], replaceable=False)
|
||||||
assert_equal(created_tx, creator['result'])
|
assert_equal(created_tx, creator['result'])
|
||||||
|
|
||||||
# Signer tests
|
# Signer tests
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||||||
self.num_nodes = 3
|
self.num_nodes = 3
|
||||||
# This test isn't testing txn relay/timing, so set whitelist on the
|
# This test isn't testing txn relay/timing, so set whitelist on the
|
||||||
# peers for instant txn relay. This speeds up the test run time 2-3x.
|
# peers for instant txn relay. This speeds up the test run time 2-3x.
|
||||||
self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes
|
self.extra_args = [["-whitelist=noban@127.0.0.1", "-walletrbf=0"]] * self.num_nodes
|
||||||
|
|
||||||
def skip_test_if_missing_module(self):
|
def skip_test_if_missing_module(self):
|
||||||
self.skip_if_no_wallet()
|
self.skip_if_no_wallet()
|
||||||
@@ -146,7 +146,7 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||||||
# Create tx2 using createrawtransaction
|
# Create tx2 using createrawtransaction
|
||||||
inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}]
|
inputs = [{"txid": utxo_to_use["txid"], "vout": utxo_to_use["vout"]}]
|
||||||
outputs = {self.nodes[0].getnewaddress(): 0.999}
|
outputs = {self.nodes[0].getnewaddress(): 0.999}
|
||||||
tx2 = self.nodes[1].createrawtransaction(inputs, outputs)
|
tx2 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
|
||||||
tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"]
|
tx2_signed = self.nodes[1].signrawtransactionwithwallet(tx2)["hex"]
|
||||||
txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)
|
txid_2 = self.nodes[1].sendrawtransaction(tx2_signed)
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ class ListTransactionsTest(BitcoinTestFramework):
|
|||||||
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3)
|
utxo_to_use = get_unconfirmed_utxo_entry(self.nodes[1], txid_3)
|
||||||
inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}]
|
inputs = [{"txid": txid_3, "vout": utxo_to_use["vout"]}]
|
||||||
outputs = {self.nodes[0].getnewaddress(): 0.997}
|
outputs = {self.nodes[0].getnewaddress(): 0.997}
|
||||||
tx4 = self.nodes[1].createrawtransaction(inputs, outputs)
|
tx4 = self.nodes[1].createrawtransaction(inputs=inputs, outputs=outputs, replaceable=False)
|
||||||
tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"]
|
tx4_signed = self.nodes[1].signrawtransactionwithwallet(tx4)["hex"]
|
||||||
txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)
|
txid_4 = self.nodes[1].sendrawtransaction(tx4_signed)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user