aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorglozow <gloriajzhao@gmail.com>2025-01-30 00:46:01 -0500
committerglozow <gloriajzhao@gmail.com>2025-02-07 13:55:57 -0500
commite107bf78f9d722fcdeb5c1fba5a784dd7747e12f (patch)
tree2e053c7aac88d71df33f900f41f5d0ae1791f29c
parent22dccea553253a83c50b2509b881d1c3ae925bdc (diff)
[fuzz] TxOrphanage::SanityCheck accounting
-rw-r--r--src/test/fuzz/txdownloadman.cpp3
-rw-r--r--src/test/fuzz/txorphan.cpp2
-rw-r--r--src/txorphanage.cpp40
-rw-r--r--src/txorphanage.h4
4 files changed, 48 insertions, 1 deletions
diff --git a/src/test/fuzz/txdownloadman.cpp b/src/test/fuzz/txdownloadman.cpp
index a786068256..06385e7bdd 100644
--- a/src/test/fuzz/txdownloadman.cpp
+++ b/src/test/fuzz/txdownloadman.cpp
@@ -285,6 +285,7 @@ static void CheckInvariants(const node::TxDownloadManagerImpl& txdownload_impl,
// Orphanage usage should never exceed what is allowed
Assert(orphanage.Size() <= max_orphan_count);
+ txdownload_impl.m_orphanage.SanityCheck();
// We should never have more than the maximum in-flight requests out for a peer.
for (NodeId peer = 0; peer < NUM_PEERS; ++peer) {
@@ -437,8 +438,8 @@ FUZZ_TARGET(txdownloadman_impl, .init = initialize)
auto time_skip = fuzzed_data_provider.PickValueInArray(TIME_SKIPS);
if (fuzzed_data_provider.ConsumeBool()) time_skip *= -1;
time += time_skip;
- CheckInvariants(txdownload_impl, max_orphan_count);
}
+ CheckInvariants(txdownload_impl, max_orphan_count);
// Disconnect everybody, check that all data structures are empty.
for (NodeId nodeid = 0; nodeid < NUM_PEERS; ++nodeid) {
txdownload_impl.DisconnectedPeer(nodeid);
diff --git a/src/test/fuzz/txorphan.cpp b/src/test/fuzz/txorphan.cpp
index 53f57f5539..9133323449 100644
--- a/src/test/fuzz/txorphan.cpp
+++ b/src/test/fuzz/txorphan.cpp
@@ -204,6 +204,7 @@ FUZZ_TARGET(txorphan, .init = initialize_orphanage)
});
}
+
// Set tx as potential parent to be used for future GetChildren() calls.
if (!ptx_potential_parent || fuzzed_data_provider.ConsumeBool()) {
ptx_potential_parent = tx;
@@ -213,4 +214,5 @@ FUZZ_TARGET(txorphan, .init = initialize_orphanage)
const bool get_tx_nonnull{orphanage.GetTx(tx->GetWitnessHash()) != nullptr};
Assert(have_tx == get_tx_nonnull);
}
+ orphanage.SanityCheck();
}
diff --git a/src/txorphanage.cpp b/src/txorphanage.cpp
index 1f7a198594..5de894e32b 100644
--- a/src/txorphanage.cpp
+++ b/src/txorphanage.cpp
@@ -321,3 +321,43 @@ std::vector<TxOrphanage::OrphanTxBase> TxOrphanage::GetOrphanTransactions() cons
}
return ret;
}
+
+void TxOrphanage::SanityCheck() const
+{
+ // Check that cached m_total_announcements is correct
+ unsigned int counted_total_announcements{0};
+ // Check that m_total_orphan_usage is correct
+ unsigned int counted_total_usage{0};
+
+ // Check that cached PeerOrphanInfo::m_total_size is correct
+ std::map<NodeId, unsigned int> counted_size_per_peer;
+
+ for (const auto& [wtxid, orphan] : m_orphans) {
+ counted_total_announcements += orphan.announcers.size();
+ counted_total_usage += orphan.GetUsage();
+
+ Assume(!orphan.announcers.empty());
+ for (const auto& peer : orphan.announcers) {
+ auto& count_peer_entry = counted_size_per_peer.try_emplace(peer).first->second;
+ count_peer_entry += orphan.GetUsage();
+ }
+ }
+
+ Assume(m_total_announcements >= m_orphans.size());
+ Assume(counted_total_announcements == m_total_announcements);
+ Assume(counted_total_usage == m_total_orphan_usage);
+
+ // There must be an entry in m_peer_orphanage_info for each peer
+ // However, there may be m_peer_orphanage_info entries corresponding to peers for whom we
+ // previously had orphans but no longer do.
+ Assume(counted_size_per_peer.size() <= m_peer_orphanage_info.size());
+
+ for (const auto& [peerid, info] : m_peer_orphanage_info) {
+ auto it_counted = counted_size_per_peer.find(peerid);
+ if (it_counted == counted_size_per_peer.end()) {
+ Assume(info.m_total_usage == 0);
+ } else {
+ Assume(it_counted->second == info.m_total_usage);
+ }
+ }
+}
diff --git a/src/txorphanage.h b/src/txorphanage.h
index 386408e7ea..50b8d732b2 100644
--- a/src/txorphanage.h
+++ b/src/txorphanage.h
@@ -105,6 +105,10 @@ public:
return peer_it == m_peer_orphanage_info.end() ? 0 : peer_it->second.m_total_usage;
}
+ /** Check consistency between PeerOrphanInfo and m_orphans. Recalculate counters and ensure they
+ * match what is cached. */
+ void SanityCheck() const;
+
protected:
struct OrphanTx : public OrphanTxBase {
size_t list_pos;