[optimization] Maintain at most 1 reconsiderable announcement per wtxid

This introduces an invariant that TxOrphanageImpl never holds more than one
announcement with m_reconsider=true for a given wtxid. This avoids duplicate
work, both in the caller might otherwise reconsider the same transaction multiple
times before it is ready, and internally in AddChildrenToWorkSet, which might
otherwise iterate over all announcements multiple times.
This commit is contained in:
Pieter Wuille
2025-06-26 14:56:16 -04:00
committed by glozow
parent af7402ccfa
commit ed24e01696
2 changed files with 38 additions and 16 deletions

View File

@@ -626,11 +626,11 @@ FUZZ_TARGET(txorphanage_sim)
auto tx = read_tx_fn();
FastRandomContext rand_ctx(rng.rand256());
auto added = real->AddChildrenToWorkSet(*txn[tx], rand_ctx);
/** Map of all child wtxids, with value whether they already have a reconsiderable
announcement from some peer. */
std::map<Wtxid, bool> child_wtxids;
/** Set of not-already-reconsiderable child wtxids. */
std::set<Wtxid> child_wtxids;
for (unsigned child_tx = 0; child_tx < NUM_TX; ++child_tx) {
if (!have_tx_fn(child_tx)) continue;
if (have_reconsiderable_fn(child_tx)) continue;
bool child_of = false;
for (auto& txin : txn[child_tx]->vin) {
if (txin.prevout.hash == txn[tx]->GetHash()) {
@@ -639,11 +639,11 @@ FUZZ_TARGET(txorphanage_sim)
}
}
if (child_of) {
child_wtxids[txn[child_tx]->GetWitnessHash()] = have_reconsiderable_fn(child_tx);
child_wtxids.insert(txn[child_tx]->GetWitnessHash());
}
}
for (auto& [wtxid, peer] : added) {
// Wtxid must be a child of tx.
// Wtxid must be a child of tx that is not yet reconsiderable.
auto child_wtxid_it = child_wtxids.find(wtxid);
assert(child_wtxid_it != child_wtxids.end());
// Announcement must exist.
@@ -653,18 +653,13 @@ FUZZ_TARGET(txorphanage_sim)
assert(sim_ann_it->reconsider == false);
// Make reconsiderable.
sim_ann_it->reconsider = true;
}
for (auto& [wtxid, peer] : added) {
// Remove from child_wtxids map, so we can check that only already-reconsiderable
// ones are missing from the result.
// Remove from child_wtxids map, to disallow it being reported a second time in added.
child_wtxids.erase(wtxid);
}
// Verify that AddChildrenToWorkSet does not select announcements that were already reconsiderable:
// Check all child wtxids which did not occur at least once in the result were already reconsiderable
// due to a previous AddChildrenToWorkSet.
for (auto& [wtxid, already_reconsider] : child_wtxids) {
assert(already_reconsider);
}
assert(child_wtxids.empty());
break;
} else if (command-- == 0) {
// GetTxToReconsider.