Repository: bitcoin/bitcoin
File: test/functional/mempool_limit.py (Python)

Code before:
            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_vsize = 10001  # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1
        tx_C = self.wallet.create_self_transfer(
            target_vsize=non_cpfp_carveout_vsize,
            fee_rate=mempoolmin_feerate,
            utxo_to_spend=tx_B["new_utxo"],
            confirmed_only=True
        )
        res = node.submitpackage([tx_B["hex"], tx_C["hex"]])
        assert_equal(res["package_msg"], "transaction failed")
        assert "too-long-mempool-chain" in res["tx-results"][tx_C["wtxid"]]["error"]

    def test_mid_package_eviction_success(self):
        node = self.nodes[0]
        self.log.info("Check a package where each parent passes the current mempoolminfee but a parent could be evicted before getting child's descendant feerate")

        # Clear mempool so it can be filled with minrelay txns
        self.restart_node(0, extra_args=self.extra_args[0] + ["-persistmempool=0"])
        assert_equal(node.getrawmempool(), [])

        # Restarting the node resets mempool minimum feerate
        assert_equal(node.getmempoolinfo()['minrelaytxfee'], Decimal('0.00001000'))
        assert_equal(node.getmempoolinfo()['mempoolminfee'], Decimal('0.00001000'))

        fill_mempool(self, node)
        current_info = node.getmempoolinfo()
        mempoolmin_feerate = current_info["mempoolminfee"]

        mempool_txids = node.getrawmempool()
        mempool_entries = [node.getmempoolentry(entry) for entry in mempool_txids]
        fees_btc_per_kvb = [entry["fees"]["base"] / (Decimal(entry["vsize"]) / 1000) for entry in mempool_entries]
        mempool_entry_minrate = min(fees_btc_per_kvb)
        mempool_entry_minrate = mempool_entry_minrate.quantize(Decimal("0.00000000"))

        # There is a gap, our parents will be minrate, with child bringing up descendant fee sufficiently to avoid
        # eviction even though parents cause eviction on their own
        assert_greater_than(mempool_entry_minrate, mempoolmin_feerate)

        package_hex = []
        # UTXOs to be spent by the ultimate child transaction
        parent_utxos = []

        # Series of parents that don't need CPFP and are submitted individually. Each one is large
        # which means in aggregate they could trigger eviction, but child submission should result
        # in them not being evicted
        parent_vsize = 25000
        num_big_parents = 3

Review comment (suggestion):
If you need to update, perhaps you could also use the approach with

`FEERATE_100SAT_KVB = Decimal("0.00000100")`

in `test/functional/mempool_limit.py`.

Code after:
            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_vsize = 10001  # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1
        tx_C = self.wallet.create_self_transfer(
            target_vsize=non_cpfp_carveout_vsize,
            fee_rate=mempoolmin_feerate,
            utxo_to_spend=tx_B["new_utxo"],
            confirmed_only=True
        )
        res = node.submitpackage([tx_B["hex"], tx_C["hex"]])
        assert_equal(res["package_msg"], "transaction failed")
        assert "too-long-mempool-chain" in res["tx-results"][tx_C["wtxid"]]["error"]

    def test_mid_package_eviction_success(self):
        node = self.nodes[0]
        self.log.info("Check a package where each parent passes the current mempoolminfee but a parent could be evicted before getting child's descendant feerate")

        # Clear mempool so it can be filled with minrelay txns
        self.restart_node(0, extra_args=self.extra_args[0] + ["-persistmempool=0"])
        assert_equal(node.getrawmempool(), [])

        # Restarting the node resets mempool minimum feerate
        assert_equal(node.getmempoolinfo()['minrelaytxfee'], node.getmempoolinfo()["mempoolminfee"])

        fill_mempool(self, node)
        current_info = node.getmempoolinfo()
        mempoolmin_feerate = current_info["mempoolminfee"]

        mempool_txids = node.getrawmempool()
        mempool_entries = [node.getmempoolentry(entry) for entry in mempool_txids]
        fees_btc_per_kvb = [entry["fees"]["base"] / (Decimal(entry["vsize"]) / 1000) for entry in mempool_entries]
        mempool_entry_minrate = min(fees_btc_per_kvb)
        mempool_entry_minrate = mempool_entry_minrate.quantize(Decimal("0.00000000"))

        # There is a gap, our parents will be minrate, with child bringing up descendant fee sufficiently to avoid
        # eviction even though parents cause eviction on their own
        assert_greater_than(mempool_entry_minrate, mempoolmin_feerate)

        package_hex = []
        # UTXOs to be spent by the ultimate child transaction
        parent_utxos = []

        # Series of parents that don't need CPFP and are submitted individually. Each one is large
        # which means in aggregate they could trigger eviction, but child submission should result
        # in them not being evicted
        parent_vsize = 25000
        num_big_parents = 3
        # Need to be large enough to trigger eviction