Skip to content
Bitcoin Roots

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()