mirror of
https://github.com/ElementsProject/elements.git
synced 2026-08-15 12:51:00 +02:00
Merge a7f3479ba3 into merged_master (Bitcoin PR bitcoin/bitcoin#25353)
This commit is contained in:
commit
dbab4c012c
10 changed files with 55 additions and 2 deletions
|
|
@ -15,6 +15,8 @@ other consensus and policy rules, each of the following conditions are met:
|
|||
|
||||
*Rationale*: See [BIP125
|
||||
explanation](https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#motivation).
|
||||
The Bitcoin Core implementation offers a node setting (`mempoolfullrbf`) to allow transaction
|
||||
replacement without enforcement of the opt-in signaling rule.
|
||||
|
||||
2. The replacement transaction only include an unconfirmed input if that input was included in
|
||||
one of the directly conflicting transactions. An unconfirmed input spends an output from a
|
||||
|
|
@ -74,3 +76,6 @@ This set of rules is similar but distinct from BIP125.
|
|||
|
||||
* RBF enabled by default in the wallet GUI as of **v0.18.1** ([PR
|
||||
#11605](https://github.com/bitcoin/bitcoin/pull/11605)).
|
||||
|
||||
* Full replace-by-fee enabled as a configurable mempool policy as of **v24.0** ([PR
|
||||
#25353](https://github.com/bitcoin/bitcoin/pull/25353)).
|
||||
|
|
|
|||
|
|
@ -86,6 +86,10 @@ Changes to GUI or wallet related settings can be found in the GUI or Wallet sect
|
|||
New settings
|
||||
------------
|
||||
|
||||
- A new `mempoolfullrbf` option has been added, which enables the mempool to
|
||||
accept transaction replacement without enforcing the opt-in replaceability
|
||||
signal. (#25353)
|
||||
|
||||
Tools and Utilities
|
||||
-------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -571,6 +571,7 @@ void SetupServerArgs(ArgsManager& argsman)
|
|||
argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
|
||||
CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@ class CBlockPolicyEstimator;
|
|||
static constexpr unsigned int DEFAULT_MAX_MEMPOOL_SIZE_MB{300};
|
||||
/** Default for -mempoolexpiry, expiration time for mempool transactions in hours */
|
||||
static constexpr unsigned int DEFAULT_MEMPOOL_EXPIRY_HOURS{336};
|
||||
/** Default for -mempoolfullrbf, if the transaction replaceability signaling is ignored */
|
||||
static constexpr bool DEFAULT_MEMPOOL_FULL_RBF{false};
|
||||
|
||||
namespace kernel {
|
||||
/**
|
||||
|
|
@ -31,6 +33,7 @@ struct MemPoolOptions {
|
|||
int check_ratio{0};
|
||||
int64_t max_size_bytes{DEFAULT_MAX_MEMPOOL_SIZE_MB * 1'000'000};
|
||||
std::chrono::seconds expiry{std::chrono::hours{DEFAULT_MEMPOOL_EXPIRY_HOURS}};
|
||||
bool full_rbf{DEFAULT_MEMPOOL_FULL_RBF};
|
||||
MemPoolLimits limits{};
|
||||
};
|
||||
} // namespace kernel
|
||||
|
|
|
|||
|
|
@ -33,5 +33,7 @@ void ApplyArgsManOptions(const ArgsManager& argsman, MemPoolOptions& mempool_opt
|
|||
|
||||
if (auto hours = argsman.GetIntArg("-mempoolexpiry")) mempool_opts.expiry = std::chrono::hours{*hours};
|
||||
|
||||
mempool_opts.full_rbf = argsman.GetBoolArg("-mempoolfullrbf", mempool_opts.full_rbf);
|
||||
|
||||
ApplyArgsManOptions(argsman, mempool_opts.limits);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -673,6 +673,7 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
|
|||
ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
|
||||
ret.pushKV("incrementalrelayfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
|
||||
ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
|
||||
ret.pushKV("fullrbf", pool.m_full_rbf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -694,6 +695,7 @@ static RPCHelpMan getmempoolinfo()
|
|||
{RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
|
||||
{RPCResult::Type::NUM, "incrementalrelayfee", "minimum fee rate increment for mempool limiting or BIP 125 replacement in " + CURRENCY_UNIT + "/kvB"},
|
||||
{RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"},
|
||||
{RPCResult::Type::BOOL, "fullrbf", "True if the mempool accepts RBF without replaceability signaling inspection"},
|
||||
}},
|
||||
RPCExamples{
|
||||
HelpExampleCli("getmempoolinfo", "")
|
||||
|
|
|
|||
|
|
@ -482,6 +482,7 @@ CTxMemPool::CTxMemPool(const Options& opts)
|
|||
minerPolicyEstimator{opts.estimator},
|
||||
m_max_size_bytes{opts.max_size_bytes},
|
||||
m_expiry{opts.expiry},
|
||||
m_full_rbf{opts.full_rbf},
|
||||
m_limits{opts.limits}
|
||||
{
|
||||
_clear(); //lock free clear
|
||||
|
|
|
|||
|
|
@ -632,6 +632,7 @@ public:
|
|||
|
||||
const int64_t m_max_size_bytes;
|
||||
const std::chrono::seconds m_expiry;
|
||||
const bool m_full_rbf;
|
||||
|
||||
using Limits = kernel::MemPoolLimits;
|
||||
|
||||
|
|
|
|||
|
|
@ -768,7 +768,10 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
|
|||
// Applications relying on first-seen mempool behavior should
|
||||
// check all unconfirmed ancestors; otherwise an opt-in ancestor
|
||||
// might be replaced, causing removal of this descendant.
|
||||
if (!SignalsOptInRBF(*ptxConflicting)) {
|
||||
//
|
||||
// If replaceability signaling is ignored due to node setting,
|
||||
// replacement is always allowed.
|
||||
if (!m_pool.m_full_rbf && !SignalsOptInRBF(*ptxConflicting)) {
|
||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,10 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
# self.log.info("Running test replacement relay fee...")
|
||||
# self.test_replacement_relay_fee()
|
||||
|
||||
# self.log.info("Passed")
|
||||
self.log.info("Running test full replace by fee...")
|
||||
self.test_fullrbf()
|
||||
|
||||
self.log.info("Passed")
|
||||
|
||||
def make_utxo(self, node, amount, *, confirmed=True, scriptPubKey=None):
|
||||
"""Create a txout with a given amount and scriptPubKey
|
||||
|
|
@ -707,5 +710,33 @@ class ReplaceByFeeTest(BitcoinTestFramework):
|
|||
tx.vout[1].nValue = CTxOutValue(tx.vout[1].nValue.getAmount() + 1)
|
||||
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, tx.serialize().hex())
|
||||
|
||||
def test_fullrbf(self):
|
||||
txid = self.wallet.send_self_transfer(from_node=self.nodes[0])['txid']
|
||||
self.generate(self.nodes[0], 1)
|
||||
confirmed_utxo = self.wallet.get_utxo(txid=txid)
|
||||
|
||||
self.restart_node(0, extra_args=["-mempoolfullrbf=1"])
|
||||
|
||||
# Create an explicitly opt-out transaction
|
||||
optout_tx = self.wallet.send_self_transfer(
|
||||
from_node=self.nodes[0],
|
||||
utxo_to_spend=confirmed_utxo,
|
||||
sequence=SEQUENCE_FINAL,
|
||||
fee_rate=Decimal('0.01'),
|
||||
)
|
||||
assert_equal(False, self.nodes[0].getmempoolentry(optout_tx['txid'])['bip125-replaceable'])
|
||||
|
||||
conflicting_tx = self.wallet.create_self_transfer(
|
||||
utxo_to_spend=confirmed_utxo,
|
||||
sequence=SEQUENCE_FINAL,
|
||||
fee_rate=Decimal('0.02'),
|
||||
)
|
||||
|
||||
# Send the replacement transaction, conflicting with the optout_tx.
|
||||
self.nodes[0].sendrawtransaction(conflicting_tx['hex'], 0)
|
||||
|
||||
# Optout_tx is not anymore in the mempool.
|
||||
assert optout_tx['txid'] not in self.nodes[0].getrawmempool()
|
||||
|
||||
if __name__ == '__main__':
|
||||
ReplaceByFeeTest().main()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue