@@ -446,4 +446,130 @@ BOOST_AUTO_TEST_CASE(process_block)
446
446
BOOST_CHECK_EQUAL (orphanage.Size (), 1 );
447
447
BOOST_CHECK (orphanage.HaveTx (control_tx->GetWitnessHash ()));
448
448
}
449
+
450
+ BOOST_AUTO_TEST_CASE (multiple_announcers)
451
+ {
452
+ const NodeId node0{0 };
453
+ const NodeId node1{1 };
454
+ const NodeId node2{2 };
455
+ size_t expected_total_count{0 };
456
+ FastRandomContext det_rand{true };
457
+ TxOrphanageTest orphanage{det_rand};
458
+
459
+ // Check accounting per peer.
460
+ // Check that EraseForPeer works with multiple announcers.
461
+ {
462
+ auto ptx = MakeTransactionSpending ({}, det_rand);
463
+ const auto & wtxid = ptx->GetWitnessHash ();
464
+ BOOST_CHECK (orphanage.AddTx (ptx, node0));
465
+ BOOST_CHECK (orphanage.HaveTx (wtxid));
466
+ expected_total_count += 1 ;
467
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
468
+
469
+ // Adding again should do nothing.
470
+ BOOST_CHECK (!orphanage.AddTx (ptx, node0));
471
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
472
+
473
+ // We can add another tx with the same txid but different witness.
474
+ auto ptx_mutated{MakeMutation (ptx)};
475
+ BOOST_CHECK (orphanage.AddTx (ptx_mutated, node0));
476
+ BOOST_CHECK (orphanage.HaveTx (ptx_mutated->GetWitnessHash ()));
477
+ expected_total_count += 1 ;
478
+
479
+ BOOST_CHECK (!orphanage.AddTx (ptx, node0));
480
+
481
+ // Adding a new announcer should not change overall accounting.
482
+ BOOST_CHECK (orphanage.AddAnnouncer (ptx->GetWitnessHash (), node2));
483
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
484
+
485
+ // If we already have this announcer, AddAnnouncer returns false.
486
+ BOOST_CHECK (orphanage.HaveTxFromPeer (ptx->GetWitnessHash (), node2));
487
+ BOOST_CHECK (!orphanage.AddAnnouncer (ptx->GetWitnessHash (), node2));
488
+
489
+ // Same with using AddTx for an existing tx, which is equivalent to using AddAnnouncer
490
+ BOOST_CHECK (!orphanage.AddTx (ptx, node1));
491
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
492
+
493
+ // if EraseForPeer is called for an orphan with multiple announcers, the orphanage should only
494
+ // erase that peer from the announcers set.
495
+ orphanage.EraseForPeer (node0);
496
+ BOOST_CHECK (orphanage.HaveTx (ptx->GetWitnessHash ()));
497
+ BOOST_CHECK (!orphanage.HaveTxFromPeer (ptx->GetWitnessHash (), node0));
498
+ // node0 is the only one that announced ptx_mutated
499
+ BOOST_CHECK (!orphanage.HaveTx (ptx_mutated->GetWitnessHash ()));
500
+ expected_total_count -= 1 ;
501
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
502
+
503
+ // EraseForPeer should delete the orphan if it's the only announcer left.
504
+ orphanage.EraseForPeer (node1);
505
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
506
+ BOOST_CHECK (orphanage.HaveTx (ptx->GetWitnessHash ()));
507
+ orphanage.EraseForPeer (node2);
508
+ expected_total_count -= 1 ;
509
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
510
+ BOOST_CHECK (!orphanage.HaveTx (ptx->GetWitnessHash ()));
511
+ }
512
+
513
+ // Check that erasure for blocks removes for all peers.
514
+ {
515
+ CBlock block;
516
+ auto tx_block = MakeTransactionSpending ({}, det_rand);
517
+ block.vtx .emplace_back (tx_block);
518
+ BOOST_CHECK (orphanage.AddTx (tx_block, node0));
519
+ BOOST_CHECK (!orphanage.AddTx (tx_block, node1));
520
+
521
+ expected_total_count += 1 ;
522
+
523
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
524
+
525
+ orphanage.EraseForBlock (block);
526
+
527
+ expected_total_count -= 1 ;
528
+
529
+ BOOST_CHECK_EQUAL (orphanage.Size (), expected_total_count);
530
+ }
531
+ }
532
+ BOOST_AUTO_TEST_CASE (peer_worksets)
533
+ {
534
+ const NodeId node0{0 };
535
+ const NodeId node1{1 };
536
+ const NodeId node2{2 };
537
+ FastRandomContext det_rand{true };
538
+ TxOrphanageTest orphanage{det_rand};
539
+ // AddChildrenToWorkSet should pick an announcer randomly
540
+ {
541
+ auto tx_missing_parent = MakeTransactionSpending ({}, det_rand);
542
+ auto tx_orphan = MakeTransactionSpending ({COutPoint{tx_missing_parent->GetHash (), 0 }}, det_rand);
543
+ const auto & orphan_wtxid = tx_orphan->GetWitnessHash ();
544
+
545
+ // All 3 peers are announcers.
546
+ BOOST_CHECK (orphanage.AddTx (tx_orphan, node0));
547
+ BOOST_CHECK (!orphanage.AddTx (tx_orphan, node1));
548
+ BOOST_CHECK (orphanage.AddAnnouncer (orphan_wtxid, node2));
549
+ for (NodeId node = node0; node <= node2; ++node) {
550
+ BOOST_CHECK (orphanage.HaveTxFromPeer (orphan_wtxid, node));
551
+ }
552
+
553
+ // Parent accepted: add child to all 3 worksets.
554
+ orphanage.AddChildrenToWorkSet (*tx_missing_parent);
555
+ BOOST_CHECK_EQUAL (orphanage.GetTxToReconsider (node0), tx_orphan);
556
+ BOOST_CHECK_EQUAL (orphanage.GetTxToReconsider (node1), tx_orphan);
557
+ // Don't call GetTxToReconsider(node2) yet because it mutates the workset.
558
+
559
+ // EraseForPeer also removes that tx from the workset.
560
+ orphanage.EraseForPeer (node0);
561
+ BOOST_CHECK_EQUAL (orphanage.GetTxToReconsider (node0), nullptr );
562
+
563
+ // However, the other peers' worksets are not touched.
564
+ BOOST_CHECK_EQUAL (orphanage.GetTxToReconsider (node2), tx_orphan);
565
+
566
+ // Delete this tx, clearing the orphanage.
567
+ BOOST_CHECK_EQUAL (orphanage.EraseTx (orphan_wtxid), 1 );
568
+ BOOST_CHECK_EQUAL (orphanage.Size (), 0 );
569
+ for (NodeId node = node0; node <= node2; ++node) {
570
+ BOOST_CHECK_EQUAL (orphanage.GetTxToReconsider (node), nullptr );
571
+ BOOST_CHECK (!orphanage.HaveTxFromPeer (orphan_wtxid, node));
572
+ }
573
+ }
574
+ }
449
575
BOOST_AUTO_TEST_SUITE_END ()
0 commit comments