From 330022993fb96b3b776e562f1de6696d381e6524 Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Wed, 15 Jul 2026 13:23:51 -0400 Subject: [PATCH] coins: filter coinbase txid from parallel input fetching A non-segwit invalid block could spend its own coinbase output. In that case we would want to skip fetching the coinbase prevout since it would already be in the CoinsViewOverlay's cache and would cause block validation to revert to synchronous fetching. Co-authored-by: Pieter Wuille --- src/coins.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coins.cpp b/src/coins.cpp index 7bb05f68c1a..39c9c12dbee 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -372,12 +372,13 @@ CCoinsViewCache::ResetGuard CoinsViewOverlay::StartFetching(const CBlock& block Assert(m_inputs.empty()); Assert(m_input_head.load(std::memory_order_relaxed) == 0); Assert(m_input_tail == 0); - if (const auto workers_count{m_thread_pool->WorkersCount()}; workers_count > 0) { + if (const auto workers_count{m_thread_pool->WorkersCount()}; workers_count > 0 && block.vtx.size() > 1) { // Loop through the block inputs and set their prevouts in the queue. // Filter inputs that spend outputs created earlier in the same block. These outputs will be created // directly in the cache from the tx that creates them, so they will not be requested from a base view. std::unordered_set earlier_txids; earlier_txids.reserve(block.vtx.size()); + earlier_txids.emplace(block.vtx[0]->GetHash()); for (const auto& tx : block.vtx | std::views::drop(1)) { for (const auto& input : tx->vin) { if (!earlier_txids.contains(input.prevout.hash)) m_inputs.emplace_back(input.prevout);