[unit test] multiple orphan announcers

This commit is contained in:
glozow 2025-01-03 10:44:36 -05:00
parent 96c1a822a2
commit 22b023b09d

View file

@ -446,4 +446,130 @@ BOOST_AUTO_TEST_CASE(process_block)
BOOST_CHECK_EQUAL(orphanage.Size(), 1);
BOOST_CHECK(orphanage.HaveTx(control_tx->GetWitnessHash()));
}
BOOST_AUTO_TEST_CASE(multiple_announcers)
{
const NodeId node0{0};
const NodeId node1{1};
const NodeId node2{2};
size_t expected_total_count{0};
FastRandomContext det_rand{true};
TxOrphanageTest orphanage{det_rand};
// Check accounting per peer.
// Check that EraseForPeer works with multiple announcers.
{
auto ptx = MakeTransactionSpending({}, det_rand);
const auto& wtxid = ptx->GetWitnessHash();
BOOST_CHECK(orphanage.AddTx(ptx, node0));
BOOST_CHECK(orphanage.HaveTx(wtxid));
expected_total_count += 1;
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
// Adding again should do nothing.
BOOST_CHECK(!orphanage.AddTx(ptx, node0));
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
// We can add another tx with the same txid but different witness.
auto ptx_mutated{MakeMutation(ptx)};
BOOST_CHECK(orphanage.AddTx(ptx_mutated, node0));
BOOST_CHECK(orphanage.HaveTx(ptx_mutated->GetWitnessHash()));
expected_total_count += 1;
BOOST_CHECK(!orphanage.AddTx(ptx, node0));
// Adding a new announcer should not change overall accounting.
BOOST_CHECK(orphanage.AddAnnouncer(ptx->GetWitnessHash(), node2));
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
// If we already have this announcer, AddAnnouncer returns false.
BOOST_CHECK(orphanage.HaveTxFromPeer(ptx->GetWitnessHash(), node2));
BOOST_CHECK(!orphanage.AddAnnouncer(ptx->GetWitnessHash(), node2));
// Same with using AddTx for an existing tx, which is equivalent to using AddAnnouncer
BOOST_CHECK(!orphanage.AddTx(ptx, node1));
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
// if EraseForPeer is called for an orphan with multiple announcers, the orphanage should only
// erase that peer from the announcers set.
orphanage.EraseForPeer(node0);
BOOST_CHECK(orphanage.HaveTx(ptx->GetWitnessHash()));
BOOST_CHECK(!orphanage.HaveTxFromPeer(ptx->GetWitnessHash(), node0));
// node0 is the only one that announced ptx_mutated
BOOST_CHECK(!orphanage.HaveTx(ptx_mutated->GetWitnessHash()));
expected_total_count -= 1;
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
// EraseForPeer should delete the orphan if it's the only announcer left.
orphanage.EraseForPeer(node1);
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
BOOST_CHECK(orphanage.HaveTx(ptx->GetWitnessHash()));
orphanage.EraseForPeer(node2);
expected_total_count -= 1;
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
BOOST_CHECK(!orphanage.HaveTx(ptx->GetWitnessHash()));
}
// Check that erasure for blocks removes for all peers.
{
CBlock block;
auto tx_block = MakeTransactionSpending({}, det_rand);
block.vtx.emplace_back(tx_block);
BOOST_CHECK(orphanage.AddTx(tx_block, node0));
BOOST_CHECK(!orphanage.AddTx(tx_block, node1));
expected_total_count += 1;
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
orphanage.EraseForBlock(block);
expected_total_count -= 1;
BOOST_CHECK_EQUAL(orphanage.Size(), expected_total_count);
}
}
BOOST_AUTO_TEST_CASE(peer_worksets)
{
const NodeId node0{0};
const NodeId node1{1};
const NodeId node2{2};
FastRandomContext det_rand{true};
TxOrphanageTest orphanage{det_rand};
// AddChildrenToWorkSet should pick an announcer randomly
{
auto tx_missing_parent = MakeTransactionSpending({}, det_rand);
auto tx_orphan = MakeTransactionSpending({COutPoint{tx_missing_parent->GetHash(), 0}}, det_rand);
const auto& orphan_wtxid = tx_orphan->GetWitnessHash();
// All 3 peers are announcers.
BOOST_CHECK(orphanage.AddTx(tx_orphan, node0));
BOOST_CHECK(!orphanage.AddTx(tx_orphan, node1));
BOOST_CHECK(orphanage.AddAnnouncer(orphan_wtxid, node2));
for (NodeId node = node0; node <= node2; ++node) {
BOOST_CHECK(orphanage.HaveTxFromPeer(orphan_wtxid, node));
}
// Parent accepted: add child to all 3 worksets.
orphanage.AddChildrenToWorkSet(*tx_missing_parent);
BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node0), tx_orphan);
BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node1), tx_orphan);
// Don't call GetTxToReconsider(node2) yet because it mutates the workset.
// EraseForPeer also removes that tx from the workset.
orphanage.EraseForPeer(node0);
BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node0), nullptr);
// However, the other peers' worksets are not touched.
BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node2), tx_orphan);
// Delete this tx, clearing the orphanage.
BOOST_CHECK_EQUAL(orphanage.EraseTx(orphan_wtxid), 1);
BOOST_CHECK_EQUAL(orphanage.Size(), 0);
for (NodeId node = node0; node <= node2; ++node) {
BOOST_CHECK_EQUAL(orphanage.GetTxToReconsider(node), nullptr);
BOOST_CHECK(!orphanage.HaveTxFromPeer(orphan_wtxid, node));
}
}
}
BOOST_AUTO_TEST_SUITE_END()