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

Code before:
        self.generate(node, 1)

    def test_submitpackage(self):
        node = self.nodes[0]

        self.log.info("Submitpackage only allows valid hex inputs")
        valid_tx_list = self.wallet.create_self_transfer_chain(chain_length=2)
        hex_list = [valid_tx_list[0]["hex"][:-1] + 'X', valid_tx_list[1]["hex"]]
        txid_list = [valid_tx_list[0]["txid"], valid_tx_list[1]["txid"]]
        assert_raises_rpc_error(-22, "TX decode failed:", node.submitpackage, hex_list)
        assert txid_list[0] not in node.getrawmempool()
        assert txid_list[1] not in node.getrawmempool()

        self.log.info("Submitpackage valid packages with 1 child and some number of parents")
        for num_parents in [1, 2, 24]:
            self.test_submit_child_with_parents(num_parents, False)
            self.test_submit_child_with_parents(num_parents, True)

        self.log.info("Submitpackage only allows packages of 1 child with its parents")
        # Chain of 3 transactions has too many generations
        legacy_pool = node.getrawmempool()
        chain_hex = [t["hex"] for t in self.wallet.create_self_transfer_chain(chain_length=3)]
        assert_raises_rpc_error(-25, "package topology disallowed", node.submitpackage, chain_hex)
        assert_equal(legacy_pool, node.getrawmempool())

        assert_raises_rpc_error(-8, f"Array must contain between 2 and {MAX_PACKAGE_COUNT} transactions.", node.submitpackage, [])
        assert_raises_rpc_error(-8, f"Array must contain between 2 and {MAX_PACKAGE_COUNT} transactions.", node.submitpackage, [chain_hex[0]] * 1)
        assert_raises_rpc_error(
            -8, f"Array must contain between 2 and {MAX_PACKAGE_COUNT} transactions.",
            node.submitpackage, [chain_hex[0]] * (MAX_PACKAGE_COUNT + 1)
        )

        # Create a transaction chain such as only the parent gets accepted (by making the child's
        # version non-standard). Make sure the parent does get broadcast.
        self.log.info("If a package is partially submitted, transactions included in mempool get broadcast")
        peer = node.add_p2p_connection(P2PTxInvStore())
        txs = self.wallet.create_self_transfer_chain(chain_length=2)
        bad_child = tx_from_hex(txs[1]["hex"])
        bad_child.version = 0xffffffff
        hex_partial_acceptance = [txs[0]["hex"], bad_child.serialize().hex()]
        res = node.submitpackage(hex_partial_acceptance)
        assert_equal(res["package_msg"], "transaction failed")
        first_wtxid = txs[0]["tx"].getwtxid()
        assert "error" not in res["tx-results"][first_wtxid]
        sec_wtxid = bad_child.getwtxid()
        assert_equal(res["tx-results"][sec_wtxid]["error"], "version")
        peer.wait_for_broadcast([first_wtxid])

    def test_maxfeerate_submitpackage(self):
        node = self.nodes[0]
        # clear mempool

Review comment (suggestion):
No need to special-case this:

<details>
<summary>git diff on 72872c7073</summary>

```diff
diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py
index d4da0f9b06..ce42bf810e 100755
--- a/test/functional/rpc_packages.py
+++ b/test/functional/rpc_packages.py
@@ -370,7 +370,7 @@ class RPCPackagesTest(BitcoinTestFramework):
         node = self.nodes[0]
 
         self.log.info("Submitpackage valid packages with 1 child and some number of parents")
-        for num_parents in [1, 2, 24]:
+        for num_parents in [0, 1, 2, 24]:
             self.test_submit_child_with_parents(num_parents, False)
             self.test_submit_child_with_parents(num_parents, True)
 
@@ -387,9 +387,6 @@ class RPCPackagesTest(BitcoinTestFramework):
             node.submitpackage, [chain_hex[0]] * (MAX_PACKAGE_COUNT + 1)
         )
 
-        # Singleton is ok
-        node.submitpackage([chain_hex[0]] * 1)
-
         # Create a transaction chain such as only the parent gets accepted (by making the child's
         # version non-standard). Make sure the parent does get broadcast.
         self.log.info("If a package is partially submitted, transactions included in mempool get broadcast")

```
</details>


Code after:
        self.generate(node, 1)

    def test_submitpackage(self):
        node = self.nodes[0]

        self.log.info("Submitpackage only allows valid hex inputs")
        valid_tx_list = self.wallet.create_self_transfer_chain(chain_length=2)
        hex_list = [valid_tx_list[0]["hex"][:-1] + 'X', valid_tx_list[1]["hex"]]
        txid_list = [valid_tx_list[0]["txid"], valid_tx_list[1]["txid"]]
        assert_raises_rpc_error(-22, "TX decode failed:", node.submitpackage, hex_list)
        assert txid_list[0] not in node.getrawmempool()
        assert txid_list[1] not in node.getrawmempool()

        self.log.info("Submitpackage valid packages with 1 child and some number of parents (or none)")
        for num_parents in [0, 1, 2, 24]:
            self.test_submit_child_with_parents(num_parents, False)
            self.test_submit_child_with_parents(num_parents, True)

        self.log.info("Submitpackage only allows packages of 1 child with its parents")
        # Chain of 3 transactions has too many generations
        legacy_pool = node.getrawmempool()
        chain_hex = [t["hex"] for t in self.wallet.create_self_transfer_chain(chain_length=3)]
        assert_raises_rpc_error(-25, "package topology disallowed", node.submitpackage, chain_hex)
        assert_equal(legacy_pool, node.getrawmempool())

        assert_raises_rpc_error(-8, f"Array must contain between 1 and {MAX_PACKAGE_COUNT} transactions.", node.submitpackage, [])
        assert_raises_rpc_error(
            -8, f"Array must contain between 1 and {MAX_PACKAGE_COUNT} transactions.",
            node.submitpackage, [chain_hex[0]] * (MAX_PACKAGE_COUNT + 1)
        )

        # Create a transaction chain such as only the parent gets accepted (by making the child's
        # version non-standard). Make sure the parent does get broadcast.
        self.log.info("If a package is partially submitted, transactions included in mempool get broadcast")
        peer = node.add_p2p_connection(P2PTxInvStore())
        txs = self.wallet.create_self_transfer_chain(chain_length=2)
        bad_child = tx_from_hex(txs[1]["hex"])
        bad_child.version = 0xffffffff
        hex_partial_acceptance = [txs[0]["hex"], bad_child.serialize().hex()]
        res = node.submitpackage(hex_partial_acceptance)
        assert_equal(res["package_msg"], "transaction failed")
        first_wtxid = txs[0]["tx"].getwtxid()
        assert "error" not in res["tx-results"][first_wtxid]
        sec_wtxid = bad_child.getwtxid()
        assert_equal(res["tx-results"][sec_wtxid]["error"], "version")
        peer.wait_for_broadcast([first_wtxid])

    def test_maxfeerate_submitpackage(self):
        node = self.nodes[0]
        # clear mempool
        deterministic_address = node.get_deterministic_priv_key().address