7
7
8
8
from test_framework .messages import (
9
9
CInv ,
10
+ CTxInWitness ,
10
11
MSG_TX ,
11
12
MSG_WITNESS_TX ,
12
13
MSG_WTX ,
21
22
NONPREF_PEER_TX_DELAY ,
22
23
OVERLOADED_PEER_TX_DELAY ,
23
24
p2p_lock ,
25
+ P2PInterface ,
24
26
P2PTxInvStore ,
25
27
TXID_RELAY_DELAY ,
26
28
)
@@ -127,6 +129,22 @@ def relay_transaction(self, peer, tx):
127
129
peer .wait_for_getdata ([wtxid ])
128
130
peer .send_and_ping (msg_tx (tx ))
129
131
132
+ def create_malleated_version (self , tx ):
133
+ """
134
+ Create a malleated version of the tx where the witness is replaced with garbage data.
135
+ Returns a CTransaction object.
136
+ """
137
+ tx_bad_wit = tx_from_hex (tx ["hex" ])
138
+ tx_bad_wit .wit .vtxinwit = [CTxInWitness ()]
139
+ # Add garbage data to witness 0. We cannot simply strip the witness, as the node would
140
+ # classify it as a transaction in which the witness was missing rather than wrong.
141
+ tx_bad_wit .wit .vtxinwit [0 ].scriptWitness .stack = [b'garbage' ]
142
+
143
+ assert_equal (tx ["txid" ], tx_bad_wit .rehash ())
144
+ assert tx ["wtxid" ] != tx_bad_wit .getwtxid ()
145
+
146
+ return tx_bad_wit
147
+
130
148
@cleanup
131
149
def test_arrival_timing_orphan (self ):
132
150
self .log .info ("Test missing parents that arrive during delay are not requested" )
@@ -284,8 +302,8 @@ def test_orphan_multiple_parents(self):
284
302
# doesn't give up on the orphan. Once all of the missing parents are received, it should be
285
303
# submitted to mempool.
286
304
peer .send_message (msg_notfound (vec = [CInv (MSG_WITNESS_TX , int (txid_conf_old , 16 ))]))
305
+ # Sync with ping to ensure orphans are reconsidered
287
306
peer .send_and_ping (msg_tx (missing_tx ["tx" ]))
288
- peer .sync_with_ping ()
289
307
assert_equal (node .getmempoolentry (orphan ["txid" ])["ancestorcount" ], 3 )
290
308
291
309
@cleanup
@@ -394,10 +412,161 @@ def test_orphan_inherit_rejection(self):
394
412
peer2 .assert_never_requested (child ["tx" ].getwtxid ())
395
413
396
414
# The child should never be requested, even if announced again with potentially different witness.
415
+ # Sync with ping to ensure orphans are reconsidered
397
416
peer3 .send_and_ping (msg_inv ([CInv (t = MSG_TX , h = int (child ["txid" ], 16 ))]))
398
417
self .nodes [0 ].bumpmocktime (TXREQUEST_TIME_SKIP )
399
418
peer3 .assert_never_requested (child ["txid" ])
400
419
420
+ @cleanup
421
+ def test_same_txid_orphan (self ):
422
+ self .log .info ("Check what happens when orphan with same txid is already in orphanage" )
423
+ node = self .nodes [0 ]
424
+
425
+ tx_parent = self .wallet .create_self_transfer ()
426
+
427
+ # Create the real child
428
+ tx_child = self .wallet .create_self_transfer (utxo_to_spend = tx_parent ["new_utxo" ])
429
+
430
+ # Create a fake version of the child
431
+ tx_orphan_bad_wit = self .create_malleated_version (tx_child )
432
+
433
+ bad_peer = node .add_p2p_connection (P2PInterface ())
434
+ honest_peer = node .add_p2p_connection (P2PInterface ())
435
+
436
+ # 1. Fake orphan is received first. It is missing an input.
437
+ bad_peer .send_and_ping (msg_tx (tx_orphan_bad_wit ))
438
+
439
+ # 2. Node requests the missing parent by txid.
440
+ parent_txid_int = int (tx_parent ["txid" ], 16 )
441
+ node .bumpmocktime (NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY )
442
+ bad_peer .wait_for_getdata ([parent_txid_int ])
443
+
444
+ # 3. Honest peer relays the real child, which is also missing parents and should be placed
445
+ # in the orphanage.
446
+ with node .assert_debug_log (["missingorspent" , "stored orphan tx" ]):
447
+ honest_peer .send_and_ping (msg_tx (tx_child ["tx" ]))
448
+
449
+ # Time out the previous request for the parent (node will not request the same transaction
450
+ # from multiple nodes at the same time)
451
+ node .bumpmocktime (GETDATA_TX_INTERVAL )
452
+
453
+ # 4. The parent is requested. Honest peer sends it.
454
+ honest_peer .wait_for_getdata ([parent_txid_int ])
455
+ # Sync with ping to ensure orphans are reconsidered
456
+ honest_peer .send_and_ping (msg_tx (tx_parent ["tx" ]))
457
+
458
+ # 5. After parent is accepted, orphans should be reconsidered.
459
+ # The real child should be accepted and the fake one rejected.
460
+ node_mempool = node .getrawmempool ()
461
+ assert tx_parent ["txid" ] in node_mempool
462
+ assert tx_child ["txid" ] in node_mempool
463
+ assert_equal (node .getmempoolentry (tx_child ["txid" ])["wtxid" ], tx_child ["wtxid" ])
464
+
465
+ @cleanup
466
+ def test_same_txid_orphan_of_orphan (self ):
467
+ self .log .info ("Check what happens when orphan's parent with same txid is already in orphanage" )
468
+ node = self .nodes [0 ]
469
+
470
+ tx_grandparent = self .wallet .create_self_transfer ()
471
+
472
+ # Create middle tx (both parent and child) which will be in orphanage.
473
+ tx_middle = self .wallet .create_self_transfer (utxo_to_spend = tx_grandparent ["new_utxo" ])
474
+
475
+ # Create a fake version of the middle tx
476
+ tx_orphan_bad_wit = self .create_malleated_version (tx_middle )
477
+
478
+ # Create grandchild spending from tx_middle (and spending from tx_orphan_bad_wit since they
479
+ # have the same txid).
480
+ tx_grandchild = self .wallet .create_self_transfer (utxo_to_spend = tx_middle ["new_utxo" ])
481
+
482
+ bad_peer = node .add_p2p_connection (P2PInterface ())
483
+ honest_peer = node .add_p2p_connection (P2PInterface ())
484
+
485
+ # 1. Fake orphan is received first. It is missing an input.
486
+ bad_peer .send_and_ping (msg_tx (tx_orphan_bad_wit ))
487
+
488
+ # 2. Node requests missing tx_grandparent by txid.
489
+ grandparent_txid_int = int (tx_grandparent ["txid" ], 16 )
490
+ node .bumpmocktime (NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY )
491
+ bad_peer .wait_for_getdata ([grandparent_txid_int ])
492
+
493
+ # 3. Honest peer relays the grandchild, which is missing a parent. The parent by txid already
494
+ # exists in orphanage, but should be re-requested because the node shouldn't assume that the
495
+ # witness data is the same. In this case, a same-txid-different-witness transaction exists!
496
+ with node .assert_debug_log (["stored orphan tx" ]):
497
+ honest_peer .send_and_ping (msg_tx (tx_grandchild ["tx" ]))
498
+ middle_txid_int = int (tx_middle ["txid" ], 16 )
499
+ node .bumpmocktime (NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY )
500
+ honest_peer .wait_for_getdata ([middle_txid_int ])
501
+
502
+ # 4. Honest peer relays the real child, which is also missing parents and should be placed
503
+ # in the orphanage.
504
+ with node .assert_debug_log (["stored orphan tx" ]):
505
+ honest_peer .send_and_ping (msg_tx (tx_middle ["tx" ]))
506
+ assert_equal (len (node .getrawmempool ()), 0 )
507
+
508
+ # 5. Honest peer sends tx_grandparent
509
+ honest_peer .send_and_ping (msg_tx (tx_grandparent ["tx" ]))
510
+
511
+ # 6. After parent is accepted, orphans should be reconsidered.
512
+ # The real child should be accepted and the fake one rejected.
513
+ node_mempool = node .getrawmempool ()
514
+ assert tx_grandparent ["txid" ] in node_mempool
515
+ assert tx_middle ["txid" ] in node_mempool
516
+ assert tx_grandchild ["txid" ] in node_mempool
517
+ assert_equal (node .getmempoolentry (tx_middle ["txid" ])["wtxid" ], tx_middle ["wtxid" ])
518
+
519
+ @cleanup
520
+ def test_orphan_txid_inv (self ):
521
+ self .log .info ("Check node does not ignore announcement with same txid as tx in orphanage" )
522
+ node = self .nodes [0 ]
523
+
524
+ tx_parent = self .wallet .create_self_transfer ()
525
+
526
+ # Create the real child and fake version
527
+ tx_child = self .wallet .create_self_transfer (utxo_to_spend = tx_parent ["new_utxo" ])
528
+ tx_orphan_bad_wit = self .create_malleated_version (tx_child )
529
+
530
+ bad_peer = node .add_p2p_connection (PeerTxRelayer ())
531
+ # Must not send wtxidrelay because otherwise the inv(TX) will be ignored later
532
+ honest_peer = node .add_p2p_connection (P2PInterface (wtxidrelay = False ))
533
+
534
+ # 1. Fake orphan is received first. It is missing an input.
535
+ bad_peer .send_and_ping (msg_tx (tx_orphan_bad_wit ))
536
+
537
+ # 2. Node requests the missing parent by txid.
538
+ parent_txid_int = int (tx_parent ["txid" ], 16 )
539
+ node .bumpmocktime (NONPREF_PEER_TX_DELAY + TXID_RELAY_DELAY )
540
+ bad_peer .wait_for_getdata ([parent_txid_int ])
541
+
542
+ # 3. Honest peer announces the real child, by txid (this isn't common but the node should
543
+ # still keep track of it).
544
+ child_txid_int = int (tx_child ["txid" ], 16 )
545
+ honest_peer .send_and_ping (msg_inv ([CInv (t = MSG_TX , h = child_txid_int )]))
546
+
547
+ # 4. The child is requested. Honest peer sends it.
548
+ node .bumpmocktime (TXREQUEST_TIME_SKIP )
549
+ honest_peer .wait_for_getdata ([child_txid_int ])
550
+ with node .assert_debug_log (["stored orphan tx" ]):
551
+ honest_peer .send_and_ping (msg_tx (tx_child ["tx" ]))
552
+
553
+ # 5. After first parent request times out, the node sends another one for the missing parent
554
+ # of the real orphan child.
555
+ node .bumpmocktime (GETDATA_TX_INTERVAL )
556
+ honest_peer .wait_for_getdata ([parent_txid_int ])
557
+ honest_peer .send_and_ping (msg_tx (tx_parent ["tx" ]))
558
+
559
+ # 6. After parent is accepted, orphans should be reconsidered.
560
+ # The real child should be accepted and the fake one rejected. This may happen in either
561
+ # order since the message-processing is randomized. If tx_orphan_bad_wit is validated first,
562
+ # its consensus error leads to disconnection of bad_peer. If tx_child is validated first,
563
+ # tx_orphan_bad_wit is rejected for txn-same-nonwitness-data-in-mempool (no punishment).
564
+ node_mempool = node .getrawmempool ()
565
+ assert tx_parent ["txid" ] in node_mempool
566
+ assert tx_child ["txid" ] in node_mempool
567
+ assert_equal (node .getmempoolentry (tx_child ["txid" ])["wtxid" ], tx_child ["wtxid" ])
568
+
569
+
401
570
def run_test (self ):
402
571
self .nodes [0 ].setmocktime (int (time .time ()))
403
572
self .wallet_nonsegwit = MiniWallet (self .nodes [0 ], mode = MiniWalletMode .RAW_P2PK )
@@ -410,6 +579,9 @@ def run_test(self):
410
579
self .test_orphans_overlapping_parents ()
411
580
self .test_orphan_of_orphan ()
412
581
self .test_orphan_inherit_rejection ()
582
+ self .test_same_txid_orphan ()
583
+ self .test_same_txid_orphan_of_orphan ()
584
+ self .test_orphan_txid_inv ()
413
585
414
586
415
587
if __name__ == '__main__' :
0 commit comments