v31.1-roots.1 · Commit 3: [PATCH 03/17] feat(policy): preserve cluster accounting and repair dynamic dust
test/functional/mempool_rbf_policy.py
Before: /dev/null · After: test/functional/mempool_rbf_policy.py
File metadata
new file mode 100644 index 0000000000000000000000000000000000000000..fcb677255533a544a8bdfee625a701c58f406865
Download original patch · Release notes
Diff rows 1–81 of 81. Line numbers refer to the original before/after files.
+ Added− RemovedUnmarked lines are context.
Scroll the code area horizontally to read long lines. Before is on the left; after is on the right. Unified view fits narrow screens more easily.
test/functional/mempool_rbf_policy.py
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
# Copyright (c) 2026 The Bitcoin Roots developers
|
| 3 |
+
# Distributed under the MIT software license, see the accompanying
|
| 4 |
+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
| 5 |
+
"""Test that getmempoolinfo reports the configured replacement policy.
|
| 6 |
+
|
| 7 |
+
-mempoolreplacement and -mempoolfullrbf select whether conflicting
|
| 8 |
+
transactions are never replaced, replaced when the original signals BIP125
|
| 9 |
+
replaceability or is TRUC/v3, or always replaced by fee. The "fullrbf" field
|
| 10 |
+
reports Always, even though OptIn also permits non-signaling TRUC conflicts.
|
| 11 |
+
"""
|
| 12 |
+
|
| 13 |
+
from decimal import Decimal
|
| 14 |
+
|
| 15 |
+
from test_framework.messages import (
|
| 16 |
+
MAX_BIP125_RBF_SEQUENCE,
|
| 17 |
+
SEQUENCE_FINAL,
|
| 18 |
+
)
|
| 19 |
+
from test_framework.test_framework import BitcoinTestFramework
|
| 20 |
+
from test_framework.util import (
|
| 21 |
+
assert_equal,
|
| 22 |
+
assert_raises_rpc_error,
|
| 23 |
+
)
|
| 24 |
+
from test_framework.wallet import MiniWallet
|
| 25 |
+
|
| 26 |
+
# (extra_args, fullrbf, non-signaling v2 replaceable, signaling original replaceable,
|
| 27 |
+
# non-signaling TRUC/v3 replaceable)
|
| 28 |
+
POLICIES = [
|
| 29 |
+
([], True, True, True, True),
|
| 30 |
+
(["-mempoolreplacement=fee,-optin"], True, True, True, True),
|
| 31 |
+
(["-mempoolreplacement=fee,optin"], False, False, True, True),
|
| 32 |
+
(["-mempoolfullrbf=0"], False, False, True, True),
|
| 33 |
+
(["-mempoolfullrbf=1"], True, True, True, True),
|
| 34 |
+
(["-mempoolreplacement=0"], False, False, False, False),
|
| 35 |
+
(["-mempoolreplacement=optin", "-mempoolfullrbf=1"], False, False, True, True),
|
| 36 |
+
(["-mempoolreplacement=0", "-mempoolfullrbf=1"], False, False, False, False),
|
| 37 |
+
(["-mempoolreplacement=fee,-optin", "-mempoolfullrbf=0"], True, True, True, True),
|
| 38 |
+
]
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
class MempoolRBFPolicyTest(BitcoinTestFramework):
|
| 42 |
+
def set_test_params(self):
|
| 43 |
+
self.num_nodes = 1
|
| 44 |
+
|
| 45 |
+
def run_test(self):
|
| 46 |
+
self.wallet = MiniWallet(self.nodes[0])
|
| 47 |
+
|
| 48 |
+
previous_warning = ""
|
| 49 |
+
for extra_args, fullrbf, nonsignaling_replaceable, signaling_replaceable, truc_replaceable in POLICIES:
|
| 50 |
+
self.log.info(f"Check replacement policy with {extra_args or 'default options'}")
|
| 51 |
+
self.restart_node(0, extra_args=extra_args, expected_stderr=previous_warning)
|
| 52 |
+
previous_warning = (
|
| 53 |
+
"Warning: False mempoolreplacement option contradicts true mempoolfullrbf; disallowing all RBF"
|
| 54 |
+
if "-mempoolreplacement=0" in extra_args and "-mempoolfullrbf=1" in extra_args else ""
|
| 55 |
+
)
|
| 56 |
+
assert_equal(self.nodes[0].getmempoolinfo()["fullrbf"], fullrbf)
|
| 57 |
+
for version, nonsignaling in ((2, nonsignaling_replaceable), (3, truc_replaceable)):
|
| 58 |
+
self.check_replacement(version=version, sequence=SEQUENCE_FINAL, replaceable=nonsignaling)
|
| 59 |
+
self.check_replacement(version=version, sequence=MAX_BIP125_RBF_SEQUENCE, replaceable=signaling_replaceable)
|
| 60 |
+
self.generate(self.nodes[0], 1)
|
| 61 |
+
self.wallet.rescan_utxos()
|
| 62 |
+
|
| 63 |
+
def check_replacement(self, *, version, sequence, replaceable):
|
| 64 |
+
node = self.nodes[0]
|
| 65 |
+
utxo = self.wallet.get_utxo()
|
| 66 |
+
original = self.wallet.create_self_transfer(utxo_to_spend=utxo, version=version, sequence=sequence)
|
| 67 |
+
replacement = self.wallet.create_self_transfer(utxo_to_spend=utxo, version=version, sequence=sequence, fee_rate=Decimal("0.01"))
|
| 68 |
+
node.sendrawtransaction(original["hex"])
|
| 69 |
+
if replaceable:
|
| 70 |
+
node.sendrawtransaction(replacement["hex"])
|
| 71 |
+
mempool = node.getrawmempool()
|
| 72 |
+
assert original["txid"] not in mempool
|
| 73 |
+
assert replacement["txid"] in mempool
|
| 74 |
+
else:
|
| 75 |
+
assert_raises_rpc_error(-26, "txn-mempool-conflict", node.sendrawtransaction, replacement["hex"])
|
| 76 |
+
assert original["txid"] in node.getrawmempool()
|
| 77 |
+
assert replacement["txid"] not in node.getrawmempool()
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
if __name__ == '__main__':
|
| 81 |
+
MempoolRBFPolicyTest(__file__).main()
|