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

Code before:
        # clear mempool
        deterministic_address = node.get_deterministic_priv_key().address
        self.generatetoaddress(node, 1, deterministic_address)

        self.log.info("Submitpackage maxfeerate arg testing")
        chained_txns = self.wallet.create_self_transfer_chain(chain_length=2)
        minrate_btc_kvb = min([chained_txn["fee"] / chained_txn["tx"].get_vsize() * 1000 for chained_txn in chained_txns])
        chain_hex = [t["hex"] for t in chained_txns]
        pkg_result = node.submitpackage(chain_hex, maxfeerate=minrate_btc_kvb - Decimal("0.00000001"))
        assert_equal(pkg_result["tx-results"][chained_txns[0]["wtxid"]]["error"], "max feerate exceeded")
        assert_equal(pkg_result["tx-results"][chained_txns[1]["wtxid"]]["error"], "bad-txns-inputs-missingorspent")
        assert_equal(node.getrawmempool(), [])

        self.log.info("Submitpackage maxburnamount arg testing")
        tx = tx_from_hex(chain_hex[1])
        tx.vout[-1].scriptPubKey = b'a' * 10001 # scriptPubKey bigger than 10k IsUnspendable
        chain_hex = [chain_hex[0], tx.serialize().hex()]
        # burn test is run before any package evaluation; nothing makes it in and we get broader exception
        assert_raises_rpc_error(-25, "Unspendable output exceeds maximum configured by user", node.submitpackage, chain_hex, 0, chained_txns[1]["new_utxo"]["value"] - Decimal("0.00000001"))
        assert_equal(node.getrawmempool(), [])

        # Relax the restrictions for both and send it; parent gets through as own subpackage
        pkg_result = node.submitpackage(chain_hex, maxfeerate=minrate_btc_kvb, maxburnamount=chained_txns[1]["new_utxo"]["value"])
        assert "error" not in pkg_result["tx-results"][chained_txns[0]["wtxid"]]
        assert_equal(pkg_result["tx-results"][tx.getwtxid()]["error"], "scriptpubkey")
        assert_equal(node.getrawmempool(), [chained_txns[0]["txid"]])

if __name__ == "__main__":
    RPCPackagesTest().main()


Review comment (bug):
In "AcceptMultipleTransactions: Fix workspace not being set as client_max…

…feerate failure" (271599af6d84c871154dc16c7abcadbe5ac08163): 

If these node parameters generally are needed for `fill_mempool` to work, would it perhaps make sense to move them to the `fill_mempool` function?

Alternatively, the comment should perhaps be "Lower mempool limit to make it easier to `fill_mempool`"

Code after:
    def test_maxfeerate_submitpackage(self):
        node = self.nodes[0]
        # clear mempool
        deterministic_address = node.get_deterministic_priv_key().address
        self.generatetoaddress(node, 1, deterministic_address)

        self.log.info("Submitpackage maxfeerate arg testing")
        chained_txns = self.wallet.create_self_transfer_chain(chain_length=2)
        minrate_btc_kvb = min([chained_txn["fee"] / chained_txn["tx"].get_vsize() * 1000 for chained_txn in chained_txns])
        chain_hex = [t["hex"] for t in chained_txns]
        pkg_result = node.submitpackage(chain_hex, maxfeerate=minrate_btc_kvb - Decimal("0.00000001"))

        # First tx failed in single transaction evaluation, so package message is generic
        assert_equal(pkg_result["package_msg"], "transaction failed")
        assert_equal(pkg_result["tx-results"][chained_txns[0]["wtxid"]]["error"], "max feerate exceeded")
        assert_equal(pkg_result["tx-results"][chained_txns[1]["wtxid"]]["error"], "bad-txns-inputs-missingorspent")
        assert_equal(node.getrawmempool(), [])

        # Make chain of two transactions where parent doesn't make minfee threshold
        # but child is too high fee
        # Lower mempool limit to make it easier to fill_mempool
        self.restart_node(0, extra_args=[
            "-datacarriersize=100000",
            "-maxmempool=5",
            "-persistmempool=0",
        ])

        fill_mempool(self, node, self.wallet)

        minrelay = node.getmempoolinfo()["minrelaytxfee"]
        parent = self.wallet.create_self_transfer(
            fee_rate=minrelay,
        )

        child = self.wallet.create_self_transfer(
            fee_rate=DEFAULT_FEE,
            utxo_to_spend=parent["new_utxo"],
        )

        pkg_result = node.submitpackage([parent["hex"], child["hex"]], maxfeerate=DEFAULT_FEE - Decimal("0.00000001"))

        # Child is connected even though parent is invalid and still reports fee exceeded
        # this implies sub-package evaluation of both entries together.
        assert_equal(pkg_result["package_msg"], "transaction failed")
        assert "mempool min fee not met" in pkg_result["tx-results"][parent["wtxid"]]["error"]
        assert_equal(pkg_result["tx-results"][child["wtxid"]]["error"], "max feerate exceeded")
        assert parent["txid"] not in node.getrawmempool()
        assert child["txid"] not in node.getrawmempool()

        # Reset maxmempool, datacarriersize, reset dynamic mempool minimum feerate, and empty mempool.
        self.restart_node(0)