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

Code before:
        peer_sender = node.add_outbound_p2p_connection(P2PInterface(), p2p_idx=1, connection_type="outbound-full-relay")

        # 1. Send first parent which will be accepted.
        peer_sender.send_and_ping(msg_tx(parent_high["tx"]))
        assert parent_high["txid"] in node.getrawmempool()

        # 2. Send child.
        peer_sender.send_and_ping(msg_tx(child["tx"]))

        # 3. Node requests parent_low. However, 1p1c fails because package-not-child-with-unconfirmed-parents
        parent_low_txid_int = int(parent_low["txid"], 16)
        peer_sender.wait_for_getdata([parent_low_txid_int])
        peer_sender.send_and_ping(msg_tx(parent_low["tx"]))

        node_mempool = node.getrawmempool()
        assert parent_high["txid"] in node_mempool
        assert parent_low["txid"] not in node_mempool
        assert child["txid"] not in node_mempool

        # Same error if submitted through submitpackage without parent_high
        package_hex_missing_parent = [parent_low["hex"], child["hex"]]
        result_missing_parent = node.submitpackage(package_hex_missing_parent)
        assert_equal(result_missing_parent["package_msg"], "package-not-child-with-unconfirmed-parents")

    def create_small_orphan(self):
        """Create small orphan transaction"""
        tx = CTransaction()
        # Nonexistent UTXO
        tx.vin = [CTxIn(COutPoint(random.randrange(1 << 256), random.randrange(1, 100)))]
        tx.wit.vtxinwit = [CTxInWitness()]
        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_NOP] * 5)]
        tx.vout = [CTxOut(100, CScript([OP_RETURN, b'a' * 3]))]
        return tx

    @cleanup
    def test_orphanage_dos_large(self):
        self.log.info("Test that the node can still resolve orphans when peers use lots of orphanage space")
        node = self.nodes[0]
        node.setmocktime(int(time.time()))

        peer_normal = node.add_p2p_connection(P2PInterface())
        peer_doser = node.add_p2p_connection(P2PInterface())

        self.log.info("Create very large orphans to be sent by DoSy peers (may take a while)")
        large_orphans = [create_large_orphan() for _ in range(100)]
        # Check to make sure these are orphans, within max standard size (to be accepted into the orphanage)
        for large_orphan in large_orphans:
            assert_greater_than_or_equal(100000, large_orphan.get_vsize())
            assert_greater_than(MAX_STANDARD_TX_WEIGHT, large_orphan.get_weight())
            assert_greater_than_or_equal(3 * large_orphan.get_vsize(), 2 * 100000)
            testres = node.testmempoolaccept([large_orphan.serialize().hex()])

Review comment (suggestion):
can expand this test case to be a little more interesting with a grandparent as well:
```
diff --git a/test/functional/p2p_opportunistic_1p1c.py b/test/functional/p2p_opportunistic_1p1c.py
index 00b94d1a71..8aa5b43a53 100755
--- a/test/functional/p2p_opportunistic_1p1c.py
+++ b/test/functional/p2p_opportunistic_1p1c.py
@@ -62,18 +62,18 @@ class PackageRelayTest(BitcoinTestFramework):
             "-datacarriersize=100000",
             "-maxmempool=5",
         ]]
         self.supports_cli = False
 
-    def create_tx_below_mempoolminfee(self, wallet):
+    def create_tx_below_mempoolminfee(self, wallet, utxo_to_spend=None):
         """Create a 1-input 1sat/vB transaction using a confirmed UTXO. Decrement and use
         self.sequence so that subsequent calls to this function result in unique transactions."""
 
         self.sequence -= 1
         assert_greater_than(self.nodes[0].getmempoolinfo()["mempoolminfee"], FEERATE_1SAT_VB)
 
-        return wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, sequence=self.sequence, confirmed_only=True)
+        return wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB, sequence=self.sequence, utxo_to_spend=utxo_to_spend, confirmed_only=True)
 
     @cleanup
     def test_basic_child_then_parent(self):
         node = self.nodes[0]
         self.log.info("Check that opportunistic 1p1c logic works when child is received before parent")
@@ -341,34 +341,42 @@ class PackageRelayTest(BitcoinTestFramework):
     @cleanup
     def test_other_parent_in_mempool(self):
         self.log.info("Check opportunistic 1p1c works even if child already has another parent in mempool")
         node = self.nodes[0]
 
+        # Grandparent will enter mempool by itself
+        grandparent_high = self.wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*10, confirmed_only=True)
+
         # This parent needs CPFP
-        parent_low = self.create_tx_below_mempoolminfee(self.wallet)
+        parent_low = self.create_tx_below_mempoolminfee(self.wallet, utxo_to_spend=grandparent_high["new_utxo"])
         # This parent does not need CPFP and can be submitted alone ahead of time
         parent_high = self.wallet.create_self_transfer(fee_rate=FEERATE_1SAT_VB*10, confirmed_only=True)
         child = self.wallet.create_self_transfer_multi(
             utxos_to_spend=[parent_high["new_utxo"], parent_low["new_utxo"]],
             fee_per_output=999*parent_low["tx"].get_vsize(),
         )
 
         peer_sender = node.add_outbound_p2p_connection(P2PInterface(), p2p_idx=1, connection_type="outbound-full-relay")
 
-        # 1. Send first parent which will be accepted.
+        # 1. Send grandparent which will be accepted
+        peer_sender.send_and_ping(msg_tx(grandparent_high["tx"]))
+        assert grandparent_high["txid"] in node.getrawmempool()
+
+        # 2. Send first parent which will be accepted.
         peer_sender.send_and_ping(msg_tx(parent_high["tx"]))
         assert parent_high["txid"] in node.getrawmempool()
 
-        # 2. Send child.
+        # 3. Send child.
         peer_sender.send_and_ping(msg_tx(child["tx"]))
 
-        # 3. Node requests parent_low.
+        # 4. Node requests parent_low.
         parent_low_txid_int = int(parent_low["txid"], 16)
         peer_sender.wait_for_getdata([parent_low_txid_int])
         peer_sender.send_and_ping(msg_tx(parent_low["tx"]))
 
         node_mempool = node.getrawmempool()
+        assert grandparent_high["txid"] in node_mempool
         assert parent_high["txid"] in node_mempool
         assert parent_low["txid"] in node_mempool
         assert child["txid"] in node_mempool
 
     def run_test(self):
```

Code after:
            fee_per_output=999*parent_low["tx"].get_vsize(),
        )

        peer_sender = node.add_outbound_p2p_connection(P2PInterface(), p2p_idx=1, connection_type="outbound-full-relay")

        # 1. Send grandparent which is accepted
        peer_sender.send_and_ping(msg_tx(grandparent_high["tx"]))
        assert grandparent_high["txid"] in node.getrawmempool()

        # 2. Send first parent which is accepted.
        peer_sender.send_and_ping(msg_tx(parent_high["tx"]))
        assert parent_high["txid"] in node.getrawmempool()

        # 3. Send child which is handled as an orphan.
        peer_sender.send_and_ping(msg_tx(child["tx"]))

        # 4. Node requests parent_low.
        parent_low_txid_int = int(parent_low["txid"], 16)
        peer_sender.wait_for_getdata([parent_low_txid_int])
        peer_sender.send_and_ping(msg_tx(parent_low["tx"]))

        node_mempool = node.getrawmempool()
        assert grandparent_high["txid"] in node_mempool
        assert parent_high["txid"] in node_mempool
        assert parent_low["txid"] in node_mempool
        assert child["txid"] in node_mempool

    def create_small_orphan(self):
        """Create small orphan transaction"""
        tx = CTransaction()
        # Nonexistent UTXO
        tx.vin = [CTxIn(COutPoint(random.randrange(1 << 256), random.randrange(1, 100)))]
        tx.wit.vtxinwit = [CTxInWitness()]
        tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_NOP] * 5)]
        tx.vout = [CTxOut(100, CScript([OP_RETURN, b'a' * 3]))]
        return tx

    @cleanup
    def test_orphanage_dos_large(self):
        self.log.info("Test that the node can still resolve orphans when peers use lots of orphanage space")
        node = self.nodes[0]
        node.setmocktime(int(time.time()))

        peer_normal = node.add_p2p_connection(P2PInterface())
        peer_doser = node.add_p2p_connection(P2PInterface())

        self.log.info("Create very large orphans to be sent by DoSy peers (may take a while)")
        large_orphans = [create_large_orphan() for _ in range(100)]
        # Check to make sure these are orphans, within max standard size (to be accepted into the orphanage)
        for large_orphan in large_orphans:
            assert_greater_than_or_equal(100000, large_orphan.get_vsize())