Skip to content

Commit 12f48d5

Browse files
instagibbsglozow
authored andcommitted
test: add chained 1p1c propagation test
1 parent 525be56 commit 12f48d5

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

test/functional/p2p_opportunistic_1p1c.py

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,7 +353,7 @@ def test_multiple_parents(self):
353353

354354
@cleanup
355355
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)")
357357
node = self.nodes[0]
358358

359359
# Grandparent will enter mempool by itself
@@ -550,6 +550,46 @@ def test_orphanage_dos_many(self):
550550
assert orphan_tx.txid_hex in node.getrawmempool()
551551
assert_equal(node.getmempoolentry(orphan_tx.txid_hex)["ancestorcount"], 2)
552552

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+
553593
def run_test(self):
554594
node = self.nodes[0]
555595
# To avoid creating transactions with the same txid (can happen if we set the same feerate
@@ -583,6 +623,7 @@ def run_test(self):
583623
self.test_parent_consensus_failure()
584624
self.test_multiple_parents()
585625
self.test_other_parent_in_mempool()
626+
self.test_1p1c_on_1p1c()
586627

587628
self.test_orphanage_dos_large()
588629
self.test_orphanage_dos_many()

test/functional/rpc_packages.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def run_test(self):
8282
self.independent_txns_testres_blank = [{
8383
"txid": res["txid"], "wtxid": res["wtxid"]} for res in self.independent_txns_testres]
8484

85+
self.test_submitpackage_with_ancestors()
8586
self.test_independent(coin)
8687
self.test_chain()
8788
self.test_multiple_children()
@@ -501,5 +502,40 @@ def test_maxburn_submitpackage(self):
501502
assert_equal(pkg_result["tx-results"][tx.wtxid_hex]["error"], "scriptpubkey")
502503
assert_equal(node.getrawmempool(), [chained_txns_burn[0]["txid"]])
503504

505+
def test_submitpackage_with_ancestors(self):
506+
self.log.info("Test that submitpackage can send a package that has in-mempool ancestors")
507+
node = self.nodes[0]
508+
peer = node.add_p2p_connection(P2PTxInvStore())
509+
510+
parent_tx = self.wallet.create_self_transfer()
511+
child_tx = self.wallet.create_self_transfer(utxo_to_spend=parent_tx["new_utxo"])
512+
grandchild_tx = self.wallet.create_self_transfer(utxo_to_spend=child_tx["new_utxo"])
513+
ggrandchild_tx = self.wallet.create_self_transfer(utxo_to_spend=grandchild_tx["new_utxo"])
514+
515+
# Submitting them all together doesn't work, as the topology is not child-with-parents
516+
assert_raises_rpc_error(-25, "package topology disallowed", node.submitpackage, [parent_tx["hex"], child_tx["hex"], grandchild_tx["hex"], ggrandchild_tx["hex"]])
517+
518+
# Submit older package and check acceptance
519+
result_submit_older = node.submitpackage(package=[parent_tx["hex"], child_tx["hex"]])
520+
assert_equal(result_submit_older["package_msg"], "success")
521+
mempool = node.getrawmempool()
522+
assert parent_tx["txid"] in mempool
523+
assert child_tx["txid"] in mempool
524+
525+
# Submit younger package and check acceptance
526+
result_submit_younger = node.submitpackage(package=[grandchild_tx["hex"], ggrandchild_tx["hex"]])
527+
assert_equal(result_submit_younger["package_msg"], "success")
528+
mempool = node.getrawmempool()
529+
530+
assert parent_tx["txid"] in mempool
531+
assert child_tx["txid"] in mempool
532+
assert grandchild_tx["txid"] in mempool
533+
assert ggrandchild_tx["txid"] in mempool
534+
535+
# The node should announce each transaction.
536+
peer.wait_for_broadcast([tx["tx"].wtxid_hex for tx in [parent_tx, child_tx, grandchild_tx, ggrandchild_tx]])
537+
self.generate(node, 1)
538+
539+
504540
if __name__ == "__main__":
505541
RPCPackagesTest(__file__).main()

0 commit comments

Comments
 (0)