From d69a3b20deca56ff8f925d93471d4caeacaa4d21 Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Sat, 7 Mar 2026 13:18:36 -0500 Subject: [PATCH] doc: update CoinsViewOverlay docstring to describe parallel fetching Co-authored-by: l0rinc --- src/coins.h | 59 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/coins.h b/src/coins.h index 5528bde0581..d1b4e0c8a9f 100644 --- a/src/coins.h +++ b/src/coins.h @@ -564,13 +564,62 @@ private: }; /** - * CCoinsViewCache overlay that avoids populating/mutating parent cache layers on cache misses. + * CCoinsViewCache subclass that asynchronously fetches most block input prevouts in parallel during ConnectBlock without + * mutating the base cache. * - * This is achieved by fetching coins from the base view using PeekCoin() instead of GetCoin(), - * so intermediate CCoinsViewCache layers are not filled. + * Only used in ConnectBlock to pass as an ephemeral view that can be reset if the block is invalid. + * It provides the same interface as CCoinsViewCache. + * It adds an additional StartFetching method to provide the block. * - * Used during ConnectBlock() as an ephemeral, resettable top-level view that is flushed only - * on success, so invalid blocks don't pollute the underlying cache. + * When a block is passed to StartFetching, the inputs of the block are flattened into a vector of InputToFetch + * objects. StartFetching then submits worker tasks to a ThreadPool and keeps the returned futures alive until fetching + * is stopped. + * + * ProcessInput() atomically fetches and increments m_input_head, so each thread can only access a single element of the + * m_inputs vector at a time. Workers race to claim inputs, so they may fetch elements in any order. If the fetched + * index is greater than or equal to the size of m_inputs, no more inputs can be fetched and false is returned. + * + * The worker claims the InputToFetch at this index, fetches the coin from the base cache and moves it into the + * InputToFetch object. The ready flag is then set with a release memory order. This allows the ready flag to be + * used as a memory fence, guaranteeing the coin being written to the object will have happened before another + * thread tests the flag with an acquire memory order. + * This assumes all base->PeekCoin() paths are safe for concurrent readers and do not mutate lower cache layers. + * + * When a coin is requested from the cache on the main thread and is not already in cacheCoins map, FetchCoinFromBase + * checks whether the next unconsumed entry in m_inputs has the requested outpoint. On a match, m_input_tail is advanced + * and the entry's ready flag is waited on with an acquire memory order until a worker has finished fetching it. The + * coin is then moved out and returned. Since the main thread is the only consumer of validation results, it blocks + * on the specific input it needs rather than racing workers for other inputs. + * + * StopFetching() is called in Flush() and in Reset() (the per-block teardown) so workers stop before the block they + * reference goes away. It stops fetching by moving m_input_head to the end of m_inputs (so workers quickly exit), + * then waits for all futures to complete and clears the per-block state (m_inputs and the head/tail counters). + * + * Workers advance m_input_head to fetch inputs. Main thread advances m_input_tail to consume. + * + * Before workers start: + * + * m_input_head + * m_input_tail + * │ + * ▼ + * ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐ + * m_inputs: │ waiting │ waiting │ waiting │ waiting │ waiting │ waiting │ waiting │ waiting │ waiting │ + * │ │ │ │ │ │ │ │ │ │ + * └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘ + * + * After workers start: + * + * Worker 2 Worker 0 Worker 3 Worker 1 m_input_head + * │ │ │ │ │ + * ▼ ▼ ▼ ▼ ▼ + * ┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐ + * m_inputs: │ ready │ ready │fetching │ ready │fetching │fetching │fetching │ waiting │ waiting │ + * │consumed │ ✓ │ ● │ ✓ │ ● │ ● │ ● │ │ │ + * └─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘ + * ▲ + * │ + * m_input_tail */ class CoinsViewOverlay : public CCoinsViewCache {