From ee589d4466bb0548a6f2215afe8abd0735768dab Mon Sep 17 00:00:00 2001 From: Greg Sanders Date: Thu, 14 Sep 2023 13:13:57 -0400 Subject: [PATCH] Add regression test for m_limit mutation --- test/functional/mempool_limit.py | 51 ++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/test/functional/mempool_limit.py b/test/functional/mempool_limit.py index 0abebbec025..a1147f70f33 100755 --- a/test/functional/mempool_limit.py +++ b/test/functional/mempool_limit.py @@ -78,6 +78,56 @@ class MempoolLimitTest(BitcoinTestFramework): assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000')) assert_greater_than(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000')) + def test_rbf_carveout_disallowed(self): + node = self.nodes[0] + + self.log.info("Check that individually-evaluated transactions in a package don't increase package limits for other subpackage parts") + + # We set chain limits to 2 ancestors, 1 descendant, then try to get a parents-and-child chain of 2 in mempool + # + # A: Solo transaction to be RBF'd (to bump descendant limit for package later) + # B: First transaction in package, RBFs A by itself under individual evaluation, which would give it +1 descendant limit + # C: Second transaction in package, spends B. If the +1 descendant limit persisted, would make it into mempool + + self.restart_node(0, extra_args=self.extra_args[0] + ["-limitancestorcount=2", "-limitdescendantcount=1"]) + + # Generate a confirmed utxo we will double-spend + rbf_utxo = self.wallet.send_self_transfer( + from_node=node, + confirmed_only=True + )["new_utxo"] + self.generate(node, 1) + + # tx_A needs to be RBF'd, set minfee at set size + A_weight = 1000 + mempoolmin_feerate = node.getmempoolinfo()["mempoolminfee"] + tx_A = self.wallet.send_self_transfer( + from_node=node, + fee=(mempoolmin_feerate / 1000) * (A_weight // 4) + Decimal('0.000001'), + target_weight=A_weight, + utxo_to_spend=rbf_utxo, + confirmed_only=True + ) + + # RBF's tx_A, is not yet submitted + tx_B = self.wallet.create_self_transfer( + fee=tx_A["fee"] * 4, + target_weight=A_weight, + utxo_to_spend=rbf_utxo, + confirmed_only=True + ) + + # Spends tx_B's output, too big for cpfp carveout (because that would also increase the descendant limit by 1) + non_cpfp_carveout_weight = 40001 # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1 + tx_C = self.wallet.create_self_transfer( + target_weight=non_cpfp_carveout_weight, + fee = (mempoolmin_feerate / 1000) * (non_cpfp_carveout_weight // 4) + Decimal('0.000001'), + utxo_to_spend=tx_B["new_utxo"], + confirmed_only=True + ) + + assert_raises_rpc_error(-26, "too-long-mempool-chain", node.submitpackage, [tx_B["hex"], tx_C["hex"]]) + def test_mid_package_eviction(self): node = self.nodes[0] self.log.info("Check a package where each parent passes the current mempoolminfee but would cause eviction before package submission terminates") @@ -324,6 +374,7 @@ class MempoolLimitTest(BitcoinTestFramework): self.test_mid_package_replacement() self.test_mid_package_eviction() + self.test_rbf_carveout_disallowed() if __name__ == '__main__':