diff --git a/src/validation.cpp b/src/validation.cpp index 4175dc084fe..1efe109b6f6 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2987,57 +2987,22 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra return true; } -struct PerBlockConnectTrace { - CBlockIndex* pindex = nullptr; +struct ConnectedBlock { + const CBlockIndex* pindex; std::shared_ptr pblock; - PerBlockConnectTrace() = default; -}; -/** - * Used to track blocks whose transactions were applied to the UTXO state as a - * part of a single ActivateBestChainStep call. - * - * This class is single-use, once you call GetBlocksConnected() you have to throw - * it away and make a new one. - */ -class ConnectTrace { -private: - std::vector blocksConnected; - -public: - explicit ConnectTrace() : blocksConnected(1) {} - - void BlockConnected(CBlockIndex* pindex, std::shared_ptr pblock) { - assert(!blocksConnected.back().pindex); - assert(pindex); - assert(pblock); - blocksConnected.back().pindex = pindex; - blocksConnected.back().pblock = std::move(pblock); - blocksConnected.emplace_back(); - } - - std::vector& GetBlocksConnected() { - // We always keep one extra block at the end of our list because - // blocks are added after all the conflicted transactions have - // been filled in. Thus, the last entry should always be an empty - // one waiting for the transactions from the next block. We pop - // the last entry here to make sure the list we return is sane. - assert(!blocksConnected.back().pindex); - blocksConnected.pop_back(); - return blocksConnected; - } }; /** * Connect a new block to m_chain. block_to_connect is either nullptr or a pointer to a CBlock * corresponding to pindexNew, to bypass loading it again from disk. * - * The block is added to connectTrace if connection succeeds. + * The block is added to connected_blocks if connection succeeds. */ bool Chainstate::ConnectTip( BlockValidationState& state, CBlockIndex* pindexNew, std::shared_ptr block_to_connect, - ConnectTrace& connectTrace, + std::vector& connected_blocks, DisconnectedBlockTransactions& disconnectpool) { AssertLockHeld(cs_main); @@ -3134,7 +3099,7 @@ bool Chainstate::ConnectTip( Chainstate& current_cs{m_chainman.CurrentChainstate()}; m_chainman.MaybeValidateSnapshot(*this, current_cs); - connectTrace.BlockConnected(pindexNew, std::move(block_to_connect)); + connected_blocks.emplace_back(pindexNew, std::move(block_to_connect)); return true; } @@ -3219,7 +3184,7 @@ void Chainstate::PruneBlockIndexCandidates() { * * @returns true unless a system error occurred */ -bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) +bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, std::vector& connected_blocks) { AssertLockHeld(cs_main); if (m_mempool) AssertLockHeld(m_mempool->cs); @@ -3264,7 +3229,7 @@ bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* // Connect new blocks. for (CBlockIndex* pindexConnect : vpindexToConnect | std::views::reverse) { - if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr(), connectTrace, disconnectpool)) { + if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr(), connected_blocks, disconnectpool)) { if (state.IsInvalid()) { // The block violates a consensus rule. if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { @@ -3389,7 +3354,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< { LOCK(cs_main); { - // Lock transaction pool for at least as long as it takes for connectTrace to be consumed + // Lock transaction pool for at least as long as it takes for connected_blocks to be consumed LOCK(MempoolMutex()); const bool was_in_ibd = m_chainman.IsInitialBlockDownload(); CBlockIndex* starting_tip = m_chain.Tip(); @@ -3397,7 +3362,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< do { // We absolutely may not unlock cs_main until we've made forward progress // (with the exception of shutdown due to hardware issues, low disk space, etc). - ConnectTrace connectTrace; // Destructed before cs_main is unlocked + std::vector connected_blocks; // Destructed before cs_main is unlocked if (pindexMostWork == nullptr) { pindexMostWork = FindMostWorkChain(); @@ -3414,7 +3379,7 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< // in case snapshot validation is completed during ActivateBestChainStep, the // result of GetRole() changes from BACKGROUND to NORMAL. const ChainstateRole chainstate_role{this->GetRole()}; - if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connectTrace)) { + if (!ActivateBestChainStep(state, pindexMostWork, pblock && pblock->GetHash() == pindexMostWork->GetBlockHash() ? pblock : nullBlockPtr, fInvalidFound, connected_blocks)) { // A system error occurred return false; } @@ -3426,10 +3391,9 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr< } pindexNewTip = m_chain.Tip(); - for (const PerBlockConnectTrace& trace : connectTrace.GetBlocksConnected()) { - assert(trace.pblock && trace.pindex); + for (const auto& [index, block] : connected_blocks) { if (m_chainman.m_options.signals) { - m_chainman.m_options.signals->BlockConnected(chainstate_role, trace.pblock, trace.pindex); + m_chainman.m_options.signals->BlockConnected(chainstate_role, Assert(block), Assert(index)); } } diff --git a/src/validation.h b/src/validation.h index 7aeaafe322a..729cdbaa147 100644 --- a/src/validation.h +++ b/src/validation.h @@ -455,7 +455,7 @@ enum DisconnectResult DISCONNECT_FAILED // Something else went wrong. }; -class ConnectTrace; +struct ConnectedBlock; /** @see Chainstate::FlushStateToDisk */ inline constexpr std::array FlushStateModeNames{"NONE", "IF_NEEDED", "PERIODIC", "FORCE_FLUSH", "FORCE_SYNC"}; @@ -851,12 +851,12 @@ public: std::pair GetPruneRange(int last_height_can_prune) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); protected: - bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs); + bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr& pblock, bool& fInvalidFound, std::vector& connected_blocks) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs); bool ConnectTip( BlockValidationState& state, CBlockIndex* pindexNew, std::shared_ptr block_to_connect, - ConnectTrace& connectTrace, + std::vector& connected_blocks, DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs); void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);