@@ -146,6 +146,30 @@ struct SimTxGraph
146146 if (oversized.has_value () && *oversized) oversized = std::nullopt ;
147147 }
148148
149+ /* * Destroy the transaction from the graph, including from the removed set. This will
150+ * trigger TxGraph::Ref::~Ref. reset_oversize controls whether the cached oversized
151+ * value is cleared (destroying does not clear oversizedness in TxGraph of the main
152+ * graph while staging exists). */
153+ void DestroyTransaction (TxGraph::Ref* ref, bool reset_oversize)
154+ {
155+ auto pos = Find (ref);
156+ if (pos == MISSING) {
157+ // Wipe the ref, if it exists, from the removed vector. Use std::partition rather
158+ // than std::erase because we don't care about the order of the entries that
159+ // remain.
160+ auto remove = std::partition (removed.begin (), removed.end (), [&](auto & arg) { return arg.get () != ref; });
161+ removed.erase (remove, removed.end ());
162+ } else {
163+ graph.RemoveTransactions (SetType::Singleton (pos));
164+ simrevmap.erase (simmap[pos].get ());
165+ simmap[pos].reset ();
166+ // This may invalidate our cached oversized value.
167+ if (reset_oversize && oversized.has_value () && *oversized) {
168+ oversized = std::nullopt ;
169+ }
170+ }
171+ }
172+
149173 /* * Construct the set with all positions in this graph corresponding to the specified
150174 * TxGraph::Refs. All of them must occur in this graph and not be removed. */
151175 SetType MakeSet (std::span<TxGraph::Ref* const > arg)
@@ -327,9 +351,9 @@ FUZZ_TARGET(txgraph)
327351 }
328352 break ;
329353 } else if (sel_sim.removed .size () > 0 && command-- == 0 ) {
330- // ~Ref. Destroying a TxGraph::Ref has an observable effect on the TxGraph it
331- // refers to, so this simulation permits doing so separately from other actions on
332- // TxGraph.
354+ // ~Ref (of an already-removed transaction) . Destroying a TxGraph::Ref has an
355+ // observable effect on the TxGraph it refers to, so this simulation permits doing
356+ // so separately from other actions on TxGraph.
333357
334358 // Pick a Ref of sel_sim.removed to destroy. Note that the same Ref may still occur
335359 // in the other graph, and thus not actually trigger ~Ref yet (which is exactly
@@ -341,6 +365,28 @@ FUZZ_TARGET(txgraph)
341365 }
342366 sel_sim.removed .pop_back ();
343367 break ;
368+ } else if (command-- == 0 ) {
369+ // ~Ref (of any transaction).
370+ std::vector<TxGraph::Ref*> to_destroy;
371+ to_destroy.push_back (pick_fn ());
372+ while (true ) {
373+ // Keep adding either the ancestors or descendants the already picked
374+ // transactions have in both graphs (main and staging) combined. Destroying
375+ // will trigger deletions in both, so to have consistent TxGraph behavior, the
376+ // set must be closed under ancestors, or descendants, in both graphs.
377+ auto old_size = to_destroy.size ();
378+ for (auto & sim : sims) sim.IncludeAncDesc (to_destroy, alt);
379+ if (to_destroy.size () == old_size) break ;
380+ }
381+ // The order in which these ancestors/descendants are destroyed should not matter;
382+ // randomly shuffle them.
383+ std::shuffle (to_destroy.begin (), to_destroy.end (), rng);
384+ for (TxGraph::Ref* ptr : to_destroy) {
385+ for (size_t level = 0 ; level < sims.size (); ++level) {
386+ sims[level].DestroyTransaction (ptr, level == sims.size () - 1 );
387+ }
388+ }
389+ break ;
344390 } else if (command-- == 0 ) {
345391 // SetTransactionFee.
346392 int64_t fee;
@@ -457,6 +503,10 @@ FUZZ_TARGET(txgraph)
457503 // AbortStaging.
458504 real->AbortStaging ();
459505 sims.pop_back ();
506+ // Reset the cached oversized value (if TxGraph::Ref destructions triggered
507+ // removals of main transactions while staging was active, then aborting will
508+ // cause it to be re-evaluated in TxGraph).
509+ sims.back ().oversized = std::nullopt ;
460510 break ;
461511 }
462512 }
@@ -537,13 +587,4 @@ FUZZ_TARGET(txgraph)
537587
538588 // Sanity check again (because invoking inspectors may modify internal unobservable state).
539589 real->SanityCheck ();
540-
541- // Remove all remaining transactions, because Refs cannot be destroyed otherwise (this will be
542- // addressed in a follow-up commit).
543- for (auto & sim : sims) {
544- for (auto i : sim.graph .Positions ()) {
545- auto ref = sim.GetRef (i);
546- real->RemoveTransaction (*ref);
547- }
548- }
549590}
0 commit comments