From 44b4ee194d3bdccd86cf5e151b2fc1479aabbb6c Mon Sep 17 00:00:00 2001 From: Andrew Toth Date: Sat, 24 Jan 2026 14:02:43 -0500 Subject: [PATCH] validation: reuse same CCoinsViewCache for every ConnectBlock call Add m_connect_block_view to ChainState's CoinsViews. Call CreateResetGuard inside ConnectTip to ensure the view is Reset after each block, avoiding repeated memory allocations. Co-authored-by: l0rinc --- src/validation.cpp | 6 ++++-- src/validation.h | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index b6da6d2d8d6..b505771e532 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -1861,6 +1861,7 @@ void CoinsViews::InitCache() { AssertLockHeld(::cs_main); m_cacheview = std::make_unique(&m_catcherview); + m_connect_block_view = std::make_unique(&*m_cacheview); } Chainstate::Chainstate( @@ -3098,7 +3099,8 @@ bool Chainstate::ConnectTip( LogDebug(BCLog::BENCH, " - Load block from disk: %.2fms\n", Ticks(time_2 - time_1)); { - CCoinsViewCache view(&CoinsTip()); + CCoinsViewCache& view{*m_coins_views->m_connect_block_view}; + const auto reset_guard{view.CreateResetGuard()}; bool rv = ConnectBlock(*block_to_connect, state, pindexNew, view); if (m_chainman.m_options.signals) { m_chainman.m_options.signals->BlockChecked(block_to_connect, state); @@ -3116,7 +3118,7 @@ bool Chainstate::ConnectTip( Ticks(time_3 - time_2), Ticks(m_chainman.time_connect_total), Ticks(m_chainman.time_connect_total) / m_chainman.num_blocks_total); - view.Flush(/*will_reuse_cache=*/false); // local CCoinsViewCache goes out of scope + view.Flush(/*will_reuse_cache=*/false); // No need to reallocate since it only has capacity for 1 block } const auto time_4{SteadyClock::now()}; m_chainman.time_flush += time_4 - time_3; diff --git a/src/validation.h b/src/validation.h index e4b1e555bdd..c5e29ab62f8 100644 --- a/src/validation.h +++ b/src/validation.h @@ -488,6 +488,10 @@ public: //! can fit per the dbcache setting. std::unique_ptr m_cacheview GUARDED_BY(cs_main); + //! Temporary CCoinsViewCache layered on top of m_cacheview and passed to ConnectBlock(). + //! Reset between calls and flushed only on success, so invalid blocks don't pollute the underlying cache. + std::unique_ptr m_connect_block_view GUARDED_BY(cs_main); + //! This constructor initializes CCoinsViewDB and CCoinsViewErrorCatcher instances, but it //! *does not* create a CCoinsViewCache instance by default. This is done separately because the //! presence of the cache has implications on whether or not we're allowed to flush the cache's