mempool_accept_v3.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2024 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 from decimal import Decimal 6 7 from test_framework.messages import ( 8 MAX_BIP125_RBF_SEQUENCE, 9 ) 10 from test_framework.test_framework import BitcoinTestFramework 11 from test_framework.util import ( 12 assert_equal, 13 assert_greater_than, 14 assert_greater_than_or_equal, 15 assert_raises_rpc_error, 16 ) 17 from test_framework.wallet import ( 18 COIN, 19 DEFAULT_FEE, 20 MiniWallet, 21 ) 22 23 MAX_REPLACEMENT_CANDIDATES = 100 24 25 def cleanup(extra_args=None): 26 def decorator(func): 27 def wrapper(self): 28 try: 29 if extra_args is not None: 30 self.restart_node(0, extra_args=extra_args) 31 func(self) 32 finally: 33 # Clear mempool again after test 34 self.generate(self.nodes[0], 1) 35 if extra_args is not None: 36 self.restart_node(0) 37 return wrapper 38 return decorator 39 40 class MempoolAcceptV3(BitcoinTestFramework): 41 def set_test_params(self): 42 self.num_nodes = 1 43 self.extra_args = [["-acceptnonstdtxn=1"]] 44 self.setup_clean_chain = True 45 46 def check_mempool(self, txids): 47 """Assert exact contents of the node's mempool (by txid).""" 48 mempool_contents = self.nodes[0].getrawmempool() 49 assert_equal(len(txids), len(mempool_contents)) 50 assert all([txid in txids for txid in mempool_contents]) 51 52 @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) 53 def test_v3_acceptance(self): 54 node = self.nodes[0] 55 self.log.info("Test a child of a v3 transaction cannot be more than 1000vB") 56 tx_v3_parent_normal = self.wallet.send_self_transfer(from_node=node, version=3) 57 self.check_mempool([tx_v3_parent_normal["txid"]]) 58 tx_v3_child_heavy = self.wallet.create_self_transfer( 59 utxo_to_spend=tx_v3_parent_normal["new_utxo"], 60 target_weight=4004, 61 version=3 62 ) 63 assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), 1000) 64 expected_error_child_heavy = f"v3-rule-violation, v3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big" 65 assert_raises_rpc_error(-26, expected_error_child_heavy, node.sendrawtransaction, tx_v3_child_heavy["hex"]) 66 self.check_mempool([tx_v3_parent_normal["txid"]]) 67 # tx has no descendants 68 assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 1) 69 70 self.log.info("Test that, during replacements, only the new transaction counts for v3 descendant limit") 71 tx_v3_child_almost_heavy = self.wallet.send_self_transfer( 72 from_node=node, 73 fee_rate=DEFAULT_FEE, 74 utxo_to_spend=tx_v3_parent_normal["new_utxo"], 75 target_weight=3987, 76 version=3 77 ) 78 assert_greater_than_or_equal(1000, tx_v3_child_almost_heavy["tx"].get_vsize()) 79 self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy["txid"]]) 80 assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2) 81 tx_v3_child_almost_heavy_rbf = self.wallet.send_self_transfer( 82 from_node=node, 83 fee_rate=DEFAULT_FEE * 2, 84 utxo_to_spend=tx_v3_parent_normal["new_utxo"], 85 target_weight=3500, 86 version=3 87 ) 88 assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(), 1000) 89 self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy_rbf["txid"]]) 90 assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2) 91 92 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 93 def test_v3_replacement(self): 94 node = self.nodes[0] 95 self.log.info("Test v3 transactions may be replaced by v3 transactions") 96 utxo_v3_bip125 = self.wallet.get_utxo() 97 tx_v3_bip125 = self.wallet.send_self_transfer( 98 from_node=node, 99 fee_rate=DEFAULT_FEE, 100 utxo_to_spend=utxo_v3_bip125, 101 sequence=MAX_BIP125_RBF_SEQUENCE, 102 version=3 103 ) 104 self.check_mempool([tx_v3_bip125["txid"]]) 105 106 tx_v3_bip125_rbf = self.wallet.send_self_transfer( 107 from_node=node, 108 fee_rate=DEFAULT_FEE * 2, 109 utxo_to_spend=utxo_v3_bip125, 110 version=3 111 ) 112 self.check_mempool([tx_v3_bip125_rbf["txid"]]) 113 114 self.log.info("Test v3 transactions may be replaced by V2 transactions") 115 tx_v3_bip125_rbf_v2 = self.wallet.send_self_transfer( 116 from_node=node, 117 fee_rate=DEFAULT_FEE * 3, 118 utxo_to_spend=utxo_v3_bip125, 119 version=2 120 ) 121 self.check_mempool([tx_v3_bip125_rbf_v2["txid"]]) 122 123 self.log.info("Test that replacements cannot cause violation of inherited v3") 124 utxo_v3_parent = self.wallet.get_utxo() 125 tx_v3_parent = self.wallet.send_self_transfer( 126 from_node=node, 127 fee_rate=DEFAULT_FEE, 128 utxo_to_spend=utxo_v3_parent, 129 version=3 130 ) 131 tx_v3_child = self.wallet.send_self_transfer( 132 from_node=node, 133 fee_rate=DEFAULT_FEE, 134 utxo_to_spend=tx_v3_parent["new_utxo"], 135 version=3 136 ) 137 self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]]) 138 139 tx_v3_child_rbf_v2 = self.wallet.create_self_transfer( 140 fee_rate=DEFAULT_FEE * 2, 141 utxo_to_spend=tx_v3_parent["new_utxo"], 142 version=2 143 ) 144 expected_error_v2_v3 = f"v3-rule-violation, non-v3 tx {tx_v3_child_rbf_v2['txid']} (wtxid={tx_v3_child_rbf_v2['wtxid']}) cannot spend from v3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})" 145 assert_raises_rpc_error(-26, expected_error_v2_v3, node.sendrawtransaction, tx_v3_child_rbf_v2["hex"]) 146 self.check_mempool([tx_v3_bip125_rbf_v2["txid"], tx_v3_parent["txid"], tx_v3_child["txid"]]) 147 148 149 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 150 def test_v3_bip125(self): 151 node = self.nodes[0] 152 self.log.info("Test v3 transactions that don't signal BIP125 are replaceable") 153 assert_equal(node.getmempoolinfo()["fullrbf"], False) 154 utxo_v3_no_bip125 = self.wallet.get_utxo() 155 tx_v3_no_bip125 = self.wallet.send_self_transfer( 156 from_node=node, 157 fee_rate=DEFAULT_FEE, 158 utxo_to_spend=utxo_v3_no_bip125, 159 sequence=MAX_BIP125_RBF_SEQUENCE + 1, 160 version=3 161 ) 162 163 self.check_mempool([tx_v3_no_bip125["txid"]]) 164 assert not node.getmempoolentry(tx_v3_no_bip125["txid"])["bip125-replaceable"] 165 tx_v3_no_bip125_rbf = self.wallet.send_self_transfer( 166 from_node=node, 167 fee_rate=DEFAULT_FEE * 2, 168 utxo_to_spend=utxo_v3_no_bip125, 169 version=3 170 ) 171 self.check_mempool([tx_v3_no_bip125_rbf["txid"]]) 172 173 @cleanup(extra_args=["-datacarriersize=40000", "-acceptnonstdtxn=1"]) 174 def test_v3_reorg(self): 175 node = self.nodes[0] 176 self.log.info("Test that, during a reorg, v3 rules are not enforced") 177 tx_v2_block = self.wallet.send_self_transfer(from_node=node, version=2) 178 tx_v3_block = self.wallet.send_self_transfer(from_node=node, version=3) 179 tx_v3_block2 = self.wallet.send_self_transfer(from_node=node, version=3) 180 self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"]]) 181 182 block = self.generate(node, 1) 183 self.check_mempool([]) 184 tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2) 185 tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3) 186 tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_weight=5000, version=3) 187 assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], 1000) 188 self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) 189 node.invalidateblock(block[0]) 190 self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]]) 191 # This is needed because generate() will create the exact same block again. 192 node.reconsiderblock(block[0]) 193 194 195 @cleanup(extra_args=["-limitdescendantsize=10", "-datacarriersize=40000", "-acceptnonstdtxn=1"]) 196 def test_nondefault_package_limits(self): 197 """ 198 Max standard tx size + v3 rules imply the ancestor/descendant rules (at their default 199 values), but those checks must not be skipped. Ensure both sets of checks are done by 200 changing the ancestor/descendant limit configurations. 201 """ 202 node = self.nodes[0] 203 self.log.info("Test that a decreased limitdescendantsize also applies to v3 child") 204 tx_v3_parent_large1 = self.wallet.send_self_transfer(from_node=node, target_weight=99900, version=3) 205 tx_v3_child_large1 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent_large1["new_utxo"], version=3) 206 # Child is within v3 limits, but parent's descendant limit is exceeded 207 assert_greater_than(1000, tx_v3_child_large1["tx"].get_vsize()) 208 assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds descendant size limit for tx {tx_v3_parent_large1['txid']}", node.sendrawtransaction, tx_v3_child_large1["hex"]) 209 self.check_mempool([tx_v3_parent_large1["txid"]]) 210 assert_equal(node.getmempoolentry(tx_v3_parent_large1["txid"])["descendantcount"], 1) 211 self.generate(node, 1) 212 213 self.log.info("Test that a decreased limitancestorsize also applies to v3 parent") 214 self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000", "-acceptnonstdtxn=1"]) 215 tx_v3_parent_large2 = self.wallet.send_self_transfer(from_node=node, target_weight=99900, version=3) 216 tx_v3_child_large2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent_large2["new_utxo"], version=3) 217 # Child is within v3 limits 218 assert_greater_than_or_equal(1000, tx_v3_child_large2["tx"].get_vsize()) 219 assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"]) 220 self.check_mempool([tx_v3_parent_large2["txid"]]) 221 222 @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) 223 def test_v3_ancestors_package(self): 224 self.log.info("Test that v3 ancestor limits are checked within the package") 225 node = self.nodes[0] 226 tx_v3_parent_normal = self.wallet.create_self_transfer( 227 fee_rate=0, 228 target_weight=4004, 229 version=3 230 ) 231 tx_v3_parent_2_normal = self.wallet.create_self_transfer( 232 fee_rate=0, 233 target_weight=4004, 234 version=3 235 ) 236 tx_v3_child_multiparent = self.wallet.create_self_transfer_multi( 237 utxos_to_spend=[tx_v3_parent_normal["new_utxo"], tx_v3_parent_2_normal["new_utxo"]], 238 fee_per_output=10000, 239 version=3 240 ) 241 tx_v3_child_heavy = self.wallet.create_self_transfer_multi( 242 utxos_to_spend=[tx_v3_parent_normal["new_utxo"]], 243 target_weight=4004, 244 fee_per_output=10000, 245 version=3 246 ) 247 248 self.check_mempool([]) 249 result = node.submitpackage([tx_v3_parent_normal["hex"], tx_v3_parent_2_normal["hex"], tx_v3_child_multiparent["hex"]]) 250 assert_equal(result['package_msg'], f"v3-violation, tx {tx_v3_child_multiparent['txid']} (wtxid={tx_v3_child_multiparent['wtxid']}) would have too many ancestors") 251 self.check_mempool([]) 252 253 self.check_mempool([]) 254 result = node.submitpackage([tx_v3_parent_normal["hex"], tx_v3_child_heavy["hex"]]) 255 # tx_v3_child_heavy is heavy based on weight, not sigops. 256 assert_equal(result['package_msg'], f"v3-violation, v3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big: {tx_v3_child_heavy['tx'].get_vsize()} > 1000 virtual bytes") 257 self.check_mempool([]) 258 259 tx_v3_parent = self.wallet.create_self_transfer(version=3) 260 tx_v3_child = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxo"], version=3) 261 tx_v3_grandchild = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_child["new_utxo"], version=3) 262 result = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child["hex"], tx_v3_grandchild["hex"]]) 263 assert all([txresult["package-error"] == f"v3-violation, tx {tx_v3_grandchild['txid']} (wtxid={tx_v3_grandchild['wtxid']}) would have too many ancestors" for txresult in result]) 264 265 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 266 def test_v3_ancestors_package_and_mempool(self): 267 """ 268 A v3 transaction in a package cannot have 2 v3 parents. 269 Test that if we have a transaction graph A -> B -> C, where A, B, C are 270 all v3 transactions, that we cannot use submitpackage to get the 271 transactions all into the mempool. 272 273 Verify, in particular, that if A is already in the mempool, then 274 submitpackage(B, C) will fail. 275 """ 276 node = self.nodes[0] 277 self.log.info("Test that v3 ancestor limits include transactions within the package and all in-mempool ancestors") 278 # This is our transaction "A": 279 tx_in_mempool = self.wallet.send_self_transfer(from_node=node, version=3) 280 281 # Verify that A is in the mempool 282 self.check_mempool([tx_in_mempool["txid"]]) 283 284 # tx_0fee_parent is our transaction "B"; just create it. 285 tx_0fee_parent = self.wallet.create_self_transfer(utxo_to_spend=tx_in_mempool["new_utxo"], fee=0, fee_rate=0, version=3) 286 287 # tx_child_violator is our transaction "C"; create it: 288 tx_child_violator = self.wallet.create_self_transfer_multi(utxos_to_spend=[tx_0fee_parent["new_utxo"]], version=3) 289 290 # submitpackage(B, C) should fail 291 result = node.submitpackage([tx_0fee_parent["hex"], tx_child_violator["hex"]]) 292 assert_equal(result['package_msg'], f"v3-violation, tx {tx_child_violator['txid']} (wtxid={tx_child_violator['wtxid']}) would have too many ancestors") 293 self.check_mempool([tx_in_mempool["txid"]]) 294 295 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 296 def test_sibling_eviction_package(self): 297 """ 298 When a transaction has a mempool sibling, it may be eligible for sibling eviction. 299 However, this option is only available in single transaction acceptance. It doesn't work in 300 a multi-testmempoolaccept (where RBF is disabled) or when doing package CPFP. 301 """ 302 self.log.info("Test v3 sibling eviction in submitpackage and multi-testmempoolaccept") 303 node = self.nodes[0] 304 # Add a parent + child to mempool 305 tx_mempool_parent = self.wallet.send_self_transfer_multi( 306 from_node=node, 307 utxos_to_spend=[self.wallet.get_utxo()], 308 num_outputs=2, 309 version=3 310 ) 311 tx_mempool_sibling = self.wallet.send_self_transfer( 312 from_node=node, 313 utxo_to_spend=tx_mempool_parent["new_utxos"][0], 314 version=3 315 ) 316 self.check_mempool([tx_mempool_parent["txid"], tx_mempool_sibling["txid"]]) 317 318 tx_sibling_1 = self.wallet.create_self_transfer( 319 utxo_to_spend=tx_mempool_parent["new_utxos"][1], 320 version=3, 321 fee_rate=DEFAULT_FEE*100, 322 ) 323 tx_has_mempool_uncle = self.wallet.create_self_transfer(utxo_to_spend=tx_sibling_1["new_utxo"], version=3) 324 325 tx_sibling_2 = self.wallet.create_self_transfer( 326 utxo_to_spend=tx_mempool_parent["new_utxos"][0], 327 version=3, 328 fee_rate=DEFAULT_FEE*200, 329 ) 330 331 tx_sibling_3 = self.wallet.create_self_transfer( 332 utxo_to_spend=tx_mempool_parent["new_utxos"][1], 333 version=3, 334 fee_rate=0, 335 ) 336 tx_bumps_parent_with_sibling = self.wallet.create_self_transfer( 337 utxo_to_spend=tx_sibling_3["new_utxo"], 338 version=3, 339 fee_rate=DEFAULT_FEE*300, 340 ) 341 342 # Fails with another non-related transaction via testmempoolaccept 343 tx_unrelated = self.wallet.create_self_transfer(version=3) 344 result_test_unrelated = node.testmempoolaccept([tx_sibling_1["hex"], tx_unrelated["hex"]]) 345 assert_equal(result_test_unrelated[0]["reject-reason"], "v3-rule-violation") 346 347 # Fails in a package via testmempoolaccept 348 result_test_1p1c = node.testmempoolaccept([tx_sibling_1["hex"], tx_has_mempool_uncle["hex"]]) 349 assert_equal(result_test_1p1c[0]["reject-reason"], "v3-rule-violation") 350 351 # Allowed when tx is submitted in a package and evaluated individually. 352 # Note that the child failed since it would be the 3rd generation. 353 result_package_indiv = node.submitpackage([tx_sibling_1["hex"], tx_has_mempool_uncle["hex"]]) 354 self.check_mempool([tx_mempool_parent["txid"], tx_sibling_1["txid"]]) 355 expected_error_gen3 = f"v3-rule-violation, tx {tx_has_mempool_uncle['txid']} (wtxid={tx_has_mempool_uncle['wtxid']}) would have too many ancestors" 356 357 assert_equal(result_package_indiv["tx-results"][tx_has_mempool_uncle['wtxid']]['error'], expected_error_gen3) 358 359 # Allowed when tx is submitted in a package with in-mempool parent (which is deduplicated). 360 node.submitpackage([tx_mempool_parent["hex"], tx_sibling_2["hex"]]) 361 self.check_mempool([tx_mempool_parent["txid"], tx_sibling_2["txid"]]) 362 363 # Child cannot pay for sibling eviction for parent, as it violates v3 topology limits 364 result_package_cpfp = node.submitpackage([tx_sibling_3["hex"], tx_bumps_parent_with_sibling["hex"]]) 365 self.check_mempool([tx_mempool_parent["txid"], tx_sibling_2["txid"]]) 366 expected_error_cpfp = f"v3-rule-violation, tx {tx_mempool_parent['txid']} (wtxid={tx_mempool_parent['wtxid']}) would exceed descendant count limit" 367 368 assert_equal(result_package_cpfp["tx-results"][tx_sibling_3['wtxid']]['error'], expected_error_cpfp) 369 370 371 @cleanup(extra_args=["-datacarriersize=1000", "-acceptnonstdtxn=1"]) 372 def test_v3_package_inheritance(self): 373 self.log.info("Test that v3 inheritance is checked within package") 374 node = self.nodes[0] 375 tx_v3_parent = self.wallet.create_self_transfer( 376 fee_rate=0, 377 target_weight=4004, 378 version=3 379 ) 380 tx_v2_child = self.wallet.create_self_transfer_multi( 381 utxos_to_spend=[tx_v3_parent["new_utxo"]], 382 fee_per_output=10000, 383 version=2 384 ) 385 self.check_mempool([]) 386 result = node.submitpackage([tx_v3_parent["hex"], tx_v2_child["hex"]]) 387 assert_equal(result['package_msg'], f"v3-violation, non-v3 tx {tx_v2_child['txid']} (wtxid={tx_v2_child['wtxid']}) cannot spend from v3 tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']})") 388 self.check_mempool([]) 389 390 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 391 def test_v3_in_testmempoolaccept(self): 392 node = self.nodes[0] 393 394 self.log.info("Test that v3 inheritance is accurately assessed in testmempoolaccept") 395 tx_v2 = self.wallet.create_self_transfer(version=2) 396 tx_v2_from_v2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v2["new_utxo"], version=2) 397 tx_v3_from_v2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v2["new_utxo"], version=3) 398 tx_v3 = self.wallet.create_self_transfer(version=3) 399 tx_v2_from_v3 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3["new_utxo"], version=2) 400 tx_v3_from_v3 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3["new_utxo"], version=3) 401 402 # testmempoolaccept paths don't require child-with-parents topology. Ensure that topology 403 # assumptions aren't made in inheritance checks. 404 test_accept_v2_and_v3 = node.testmempoolaccept([tx_v2["hex"], tx_v3["hex"]]) 405 assert all([result["allowed"] for result in test_accept_v2_and_v3]) 406 407 test_accept_v3_from_v2 = node.testmempoolaccept([tx_v2["hex"], tx_v3_from_v2["hex"]]) 408 expected_error_v3_from_v2 = f"v3-violation, v3 tx {tx_v3_from_v2['txid']} (wtxid={tx_v3_from_v2['wtxid']}) cannot spend from non-v3 tx {tx_v2['txid']} (wtxid={tx_v2['wtxid']})" 409 assert all([result["package-error"] == expected_error_v3_from_v2 for result in test_accept_v3_from_v2]) 410 411 test_accept_v2_from_v3 = node.testmempoolaccept([tx_v3["hex"], tx_v2_from_v3["hex"]]) 412 expected_error_v2_from_v3 = f"v3-violation, non-v3 tx {tx_v2_from_v3['txid']} (wtxid={tx_v2_from_v3['wtxid']}) cannot spend from v3 tx {tx_v3['txid']} (wtxid={tx_v3['wtxid']})" 413 assert all([result["package-error"] == expected_error_v2_from_v3 for result in test_accept_v2_from_v3]) 414 415 test_accept_pairs = node.testmempoolaccept([tx_v2["hex"], tx_v3["hex"], tx_v2_from_v2["hex"], tx_v3_from_v3["hex"]]) 416 assert all([result["allowed"] for result in test_accept_pairs]) 417 418 self.log.info("Test that descendant violations are caught in testmempoolaccept") 419 tx_v3_independent = self.wallet.create_self_transfer(version=3) 420 tx_v3_parent = self.wallet.create_self_transfer_multi(num_outputs=2, version=3) 421 tx_v3_child_1 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxos"][0], version=3) 422 tx_v3_child_2 = self.wallet.create_self_transfer(utxo_to_spend=tx_v3_parent["new_utxos"][1], version=3) 423 test_accept_2children = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_child_2["hex"]]) 424 expected_error_2children = f"v3-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" 425 assert all([result["package-error"] == expected_error_2children for result in test_accept_2children]) 426 427 # Extra v3 transaction does not get incorrectly marked as extra descendant 428 test_accept_1child_with_exra = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_independent["hex"]]) 429 assert all([result["allowed"] for result in test_accept_1child_with_exra]) 430 431 # Extra v3 transaction does not make us ignore the extra descendant 432 test_accept_2children_with_exra = node.testmempoolaccept([tx_v3_parent["hex"], tx_v3_child_1["hex"], tx_v3_child_2["hex"], tx_v3_independent["hex"]]) 433 expected_error_extra = f"v3-violation, tx {tx_v3_parent['txid']} (wtxid={tx_v3_parent['wtxid']}) would exceed descendant count limit" 434 assert all([result["package-error"] == expected_error_extra for result in test_accept_2children_with_exra]) 435 # Same result if the parent is already in mempool 436 node.sendrawtransaction(tx_v3_parent["hex"]) 437 test_accept_2children_with_in_mempool_parent = node.testmempoolaccept([tx_v3_child_1["hex"], tx_v3_child_2["hex"]]) 438 assert all([result["package-error"] == expected_error_extra for result in test_accept_2children_with_in_mempool_parent]) 439 440 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 441 def test_reorg_2child_rbf(self): 442 node = self.nodes[0] 443 self.log.info("Test that children of a v3 transaction can be replaced individually, even if there are multiple due to reorg") 444 445 ancestor_tx = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2, version=3) 446 self.check_mempool([ancestor_tx["txid"]]) 447 448 block = self.generate(node, 1)[0] 449 self.check_mempool([]) 450 451 child_1 = self.wallet.send_self_transfer(from_node=node, version=3, utxo_to_spend=ancestor_tx["new_utxos"][0]) 452 child_2 = self.wallet.send_self_transfer(from_node=node, version=3, utxo_to_spend=ancestor_tx["new_utxos"][1]) 453 self.check_mempool([child_1["txid"], child_2["txid"]]) 454 455 self.generate(node, 1) 456 self.check_mempool([]) 457 458 # Create a reorg, causing ancestor_tx to exceed the 1-child limit 459 node.invalidateblock(block) 460 self.check_mempool([ancestor_tx["txid"], child_1["txid"], child_2["txid"]]) 461 assert_equal(node.getmempoolentry(ancestor_tx["txid"])["descendantcount"], 3) 462 463 # Create a replacement of child_1. It does not conflict with child_2. 464 child_1_conflict = self.wallet.send_self_transfer(from_node=node, version=3, utxo_to_spend=ancestor_tx["new_utxos"][0], fee_rate=Decimal("0.01")) 465 466 # Ensure child_1 and child_1_conflict are different transactions 467 assert (child_1_conflict["txid"] != child_1["txid"]) 468 self.check_mempool([ancestor_tx["txid"], child_1_conflict["txid"], child_2["txid"]]) 469 assert_equal(node.getmempoolentry(ancestor_tx["txid"])["descendantcount"], 3) 470 471 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 472 def test_v3_sibling_eviction(self): 473 self.log.info("Test sibling eviction for v3") 474 node = self.nodes[0] 475 tx_v3_parent = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2, version=3) 476 # This is the sibling to replace 477 tx_v3_child_1 = self.wallet.send_self_transfer( 478 from_node=node, utxo_to_spend=tx_v3_parent["new_utxos"][0], fee_rate=DEFAULT_FEE * 2, version=3 479 ) 480 assert tx_v3_child_1["txid"] in node.getrawmempool() 481 482 self.log.info("Test tx must be higher feerate than sibling to evict it") 483 tx_v3_child_2_rule6 = self.wallet.create_self_transfer( 484 utxo_to_spend=tx_v3_parent["new_utxos"][1], fee_rate=DEFAULT_FEE, version=3 485 ) 486 rule6_str = f"insufficient fee (including sibling eviction), rejecting replacement {tx_v3_child_2_rule6['txid']}; new feerate" 487 assert_raises_rpc_error(-26, rule6_str, node.sendrawtransaction, tx_v3_child_2_rule6["hex"]) 488 self.check_mempool([tx_v3_parent['txid'], tx_v3_child_1['txid']]) 489 490 self.log.info("Test tx must meet absolute fee rules to evict sibling") 491 tx_v3_child_2_rule4 = self.wallet.create_self_transfer( 492 utxo_to_spend=tx_v3_parent["new_utxos"][1], fee_rate=2 * DEFAULT_FEE + Decimal("0.00000001"), version=3 493 ) 494 rule4_str = f"insufficient fee (including sibling eviction), rejecting replacement {tx_v3_child_2_rule4['txid']}, not enough additional fees to relay" 495 assert_raises_rpc_error(-26, rule4_str, node.sendrawtransaction, tx_v3_child_2_rule4["hex"]) 496 self.check_mempool([tx_v3_parent['txid'], tx_v3_child_1['txid']]) 497 498 self.log.info("Test tx cannot cause more than 100 evictions including RBF and sibling eviction") 499 # First add 4 groups of 25 transactions. 500 utxos_for_conflict = [] 501 txids_v2_100 = [] 502 for _ in range(4): 503 confirmed_utxo = self.wallet.get_utxo(confirmed_only=True) 504 utxos_for_conflict.append(confirmed_utxo) 505 # 25 is within descendant limits 506 chain_length = int(MAX_REPLACEMENT_CANDIDATES / 4) 507 chain = self.wallet.create_self_transfer_chain(chain_length=chain_length, utxo_to_spend=confirmed_utxo) 508 for item in chain: 509 txids_v2_100.append(item["txid"]) 510 node.sendrawtransaction(item["hex"]) 511 self.check_mempool(txids_v2_100 + [tx_v3_parent["txid"], tx_v3_child_1["txid"]]) 512 513 # Replacing 100 transactions is fine 514 tx_v3_replacement_only = self.wallet.create_self_transfer_multi(utxos_to_spend=utxos_for_conflict, fee_per_output=4000000) 515 # Override maxfeerate - it costs a lot to replace these 100 transactions. 516 assert node.testmempoolaccept([tx_v3_replacement_only["hex"]], maxfeerate=0)[0]["allowed"] 517 # Adding another one exceeds the limit. 518 utxos_for_conflict.append(tx_v3_parent["new_utxos"][1]) 519 tx_v3_child_2_rule5 = self.wallet.create_self_transfer_multi(utxos_to_spend=utxos_for_conflict, fee_per_output=4000000, version=3) 520 rule5_str = f"too many potential replacements (including sibling eviction), rejecting replacement {tx_v3_child_2_rule5['txid']}; too many potential replacements (101 > 100)" 521 assert_raises_rpc_error(-26, rule5_str, node.sendrawtransaction, tx_v3_child_2_rule5["hex"]) 522 self.check_mempool(txids_v2_100 + [tx_v3_parent["txid"], tx_v3_child_1["txid"]]) 523 524 self.log.info("Test sibling eviction is successful if it meets all RBF rules") 525 tx_v3_child_2 = self.wallet.create_self_transfer( 526 utxo_to_spend=tx_v3_parent["new_utxos"][1], fee_rate=DEFAULT_FEE*10, version=3 527 ) 528 node.sendrawtransaction(tx_v3_child_2["hex"]) 529 self.check_mempool(txids_v2_100 + [tx_v3_parent["txid"], tx_v3_child_2["txid"]]) 530 531 self.log.info("Test that it's possible to do a sibling eviction and RBF at the same time") 532 utxo_unrelated_conflict = self.wallet.get_utxo(confirmed_only=True) 533 tx_unrelated_replacee = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=utxo_unrelated_conflict) 534 assert tx_unrelated_replacee["txid"] in node.getrawmempool() 535 536 fee_to_beat_child2 = int(tx_v3_child_2["fee"] * COIN) 537 538 tx_v3_child_3 = self.wallet.create_self_transfer_multi( 539 utxos_to_spend=[tx_v3_parent["new_utxos"][0], utxo_unrelated_conflict], fee_per_output=fee_to_beat_child2*5, version=3 540 ) 541 node.sendrawtransaction(tx_v3_child_3["hex"]) 542 self.check_mempool(txids_v2_100 + [tx_v3_parent["txid"], tx_v3_child_3["txid"]]) 543 544 @cleanup(extra_args=["-acceptnonstdtxn=1"]) 545 def test_reorg_sibling_eviction_1p2c(self): 546 node = self.nodes[0] 547 self.log.info("Test that sibling eviction is not allowed when multiple siblings exist") 548 549 tx_with_multi_children = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=3, version=3, confirmed_only=True) 550 self.check_mempool([tx_with_multi_children["txid"]]) 551 552 block_to_disconnect = self.generate(node, 1)[0] 553 self.check_mempool([]) 554 555 tx_with_sibling1 = self.wallet.send_self_transfer(from_node=node, version=3, utxo_to_spend=tx_with_multi_children["new_utxos"][0]) 556 tx_with_sibling2 = self.wallet.send_self_transfer(from_node=node, version=3, utxo_to_spend=tx_with_multi_children["new_utxos"][1]) 557 self.check_mempool([tx_with_sibling1["txid"], tx_with_sibling2["txid"]]) 558 559 # Create a reorg, bringing tx_with_multi_children back into the mempool with a descendant count of 3. 560 node.invalidateblock(block_to_disconnect) 561 self.check_mempool([tx_with_multi_children["txid"], tx_with_sibling1["txid"], tx_with_sibling2["txid"]]) 562 assert_equal(node.getmempoolentry(tx_with_multi_children["txid"])["descendantcount"], 3) 563 564 # Sibling eviction is not allowed because there are two siblings 565 tx_with_sibling3 = self.wallet.create_self_transfer( 566 version=3, 567 utxo_to_spend=tx_with_multi_children["new_utxos"][2], 568 fee_rate=DEFAULT_FEE*50 569 ) 570 expected_error_2siblings = f"v3-rule-violation, tx {tx_with_multi_children['txid']} (wtxid={tx_with_multi_children['wtxid']}) would exceed descendant count limit" 571 assert_raises_rpc_error(-26, expected_error_2siblings, node.sendrawtransaction, tx_with_sibling3["hex"]) 572 573 # However, an RBF (with conflicting inputs) is possible even if the resulting cluster size exceeds 2 574 tx_with_sibling3_rbf = self.wallet.send_self_transfer( 575 from_node=node, 576 version=3, 577 utxo_to_spend=tx_with_multi_children["new_utxos"][0], 578 fee_rate=DEFAULT_FEE*50 579 ) 580 self.check_mempool([tx_with_multi_children["txid"], tx_with_sibling3_rbf["txid"], tx_with_sibling2["txid"]]) 581 582 583 def run_test(self): 584 self.log.info("Generate blocks to create UTXOs") 585 node = self.nodes[0] 586 self.wallet = MiniWallet(node) 587 self.generate(self.wallet, 120) 588 self.test_v3_acceptance() 589 self.test_v3_replacement() 590 self.test_v3_bip125() 591 self.test_v3_reorg() 592 self.test_nondefault_package_limits() 593 self.test_v3_ancestors_package() 594 self.test_v3_ancestors_package_and_mempool() 595 self.test_sibling_eviction_package() 596 self.test_v3_package_inheritance() 597 self.test_v3_in_testmempoolaccept() 598 self.test_reorg_2child_rbf() 599 self.test_v3_sibling_eviction() 600 self.test_reorg_sibling_eviction_1p2c() 601 602 603 if __name__ == "__main__": 604 MempoolAcceptV3().main()