@@ -353,7 +353,7 @@ def test_multiple_parents(self):
353
353
354
354
@cleanup
355
355
def test_other_parent_in_mempool (self ):
356
- self .log .info ("Check opportunistic 1p1c works even if child already has another parent in mempool" )
356
+ self .log .info ("Check opportunistic 1p1c works when part of a 2p1c ( child already has another parent in mempool) " )
357
357
node = self .nodes [0 ]
358
358
359
359
# Grandparent will enter mempool by itself
@@ -550,6 +550,46 @@ def test_orphanage_dos_many(self):
550
550
assert orphan_tx .txid_hex in node .getrawmempool ()
551
551
assert_equal (node .getmempoolentry (orphan_tx .txid_hex )["ancestorcount" ], 2 )
552
552
553
+ @cleanup
554
+ def test_1p1c_on_1p1c (self ):
555
+ self .log .info ("Test that opportunistic 1p1c works when part of a 4-generation chain (1p1c chained from a 1p1c)" )
556
+ node = self .nodes [0 ]
557
+
558
+ # Prep 2 generations of 1p1c packages to be relayed
559
+ low_fee_great_grandparent = self .create_tx_below_mempoolminfee (self .wallet )
560
+ high_fee_grandparent = self .wallet .create_self_transfer (utxo_to_spend = low_fee_great_grandparent ["new_utxo" ], fee_rate = 20 * FEERATE_1SAT_VB )
561
+
562
+ low_fee_parent = self .create_tx_below_mempoolminfee (self .wallet , utxo_to_spend = high_fee_grandparent ["new_utxo" ])
563
+ high_fee_child = self .wallet .create_self_transfer (utxo_to_spend = low_fee_parent ["new_utxo" ], fee_rate = 20 * FEERATE_1SAT_VB )
564
+
565
+ peer_sender = node .add_p2p_connection (P2PInterface ())
566
+
567
+ # The 1p1c that spends the confirmed utxo must be received first. Afterwards, the "younger" 1p1c can be received.
568
+ for package in [[low_fee_great_grandparent , high_fee_grandparent ], [low_fee_parent , high_fee_child ]]:
569
+ # Aliases
570
+ parent_relative , child_relative = package
571
+
572
+ # 1. Child is received first (perhaps the low feerate parent didn't meet feefilter or the requests were sent to different nodes). It is missing an input.
573
+ high_child_wtxid_int = child_relative ["tx" ].wtxid_int
574
+ peer_sender .send_and_ping (msg_inv ([CInv (t = MSG_WTX , h = high_child_wtxid_int )]))
575
+ peer_sender .wait_for_getdata ([high_child_wtxid_int ])
576
+ peer_sender .send_and_ping (msg_tx (child_relative ["tx" ]))
577
+
578
+ # 2. Node requests the missing parent by txid.
579
+ parent_txid_int = parent_relative ["tx" ].txid_int
580
+ peer_sender .wait_for_getdata ([parent_txid_int ])
581
+
582
+ # 3. Sender relays the parent. Parent+Child are evaluated as a package and accepted.
583
+ peer_sender .send_and_ping (msg_tx (parent_relative ["tx" ]))
584
+
585
+ # 4. All transactions should now be in mempool.
586
+ node_mempool = node .getrawmempool ()
587
+ assert low_fee_great_grandparent ["txid" ] in node_mempool
588
+ assert high_fee_grandparent ["txid" ] in node_mempool
589
+ assert low_fee_parent ["txid" ] in node_mempool
590
+ assert high_fee_child ["txid" ] in node_mempool
591
+ assert_equal (node .getmempoolentry (low_fee_great_grandparent ["txid" ])["descendantcount" ], 4 )
592
+
553
593
def run_test (self ):
554
594
node = self .nodes [0 ]
555
595
# To avoid creating transactions with the same txid (can happen if we set the same feerate
@@ -583,6 +623,7 @@ def run_test(self):
583
623
self .test_parent_consensus_failure ()
584
624
self .test_multiple_parents ()
585
625
self .test_other_parent_in_mempool ()
626
+ self .test_1p1c_on_1p1c ()
586
627
587
628
self .test_orphanage_dos_large ()
588
629
self .test_orphanage_dos_many ()
0 commit comments