From 852f201e09cb98e98ad7418ae11933203cd57896 Mon Sep 17 00:00:00 2001 From: stickies-v Date: Fri, 4 Sep 2026 02:21:57 +0200 Subject: [PATCH] validation: refactor: encapsulate Chainstate::m_target_blockhash m_target_blockhash is paired with a mutable m_cached_target_block that must be kept in sync whenever the hash changes. --- src/validation.cpp | 6 +++--- src/validation.h | 27 ++++++++++++++++++--------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/validation.cpp b/src/validation.cpp index e1b3c4fe23c..c85a3af7303 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -5993,8 +5993,8 @@ SnapshotCompletionResult ChainstateManager::MaybeValidateSnapshot(Chainstate& va validated_cs.m_assumeutxo != Assumeutxo::VALIDATED || !validated_cs.m_chain.Tip() || // Or the validated chainstate is not targeting the snapshot block... - !validated_cs.m_target_blockhash || - *validated_cs.m_target_blockhash != *unvalidated_cs.m_from_snapshot_blockhash || + !validated_cs.TargetBlockHash() || + *validated_cs.TargetBlockHash() != *unvalidated_cs.m_from_snapshot_blockhash || // Or the validated chainstate has not reached the snapshot block yet... !validated_cs.ReachedTarget()) { // Then the snapshot cannot be validated and there is nothing to do. @@ -6190,7 +6190,7 @@ Chainstate& ChainstateManager::AddChainstate(std::unique_ptr chainst Chainstate& prev_chainstate{CurrentChainstate()}; assert(prev_chainstate.m_assumeutxo == Assumeutxo::VALIDATED); // Set target block for historical chainstate to snapshot block. - assert(!prev_chainstate.m_target_blockhash); + assert(!prev_chainstate.TargetBlockHash()); prev_chainstate.SetTargetBlockHash(*Assert(chainstate->m_from_snapshot_blockhash)); m_chainstates.push_back(std::move(chainstate)); Chainstate& curr_chainstate{CurrentChainstate()}; diff --git a/src/validation.h b/src/validation.h index 1137089fe35..43cc086ad30 100644 --- a/src/validation.h +++ b/src/validation.h @@ -566,6 +566,12 @@ protected: //! Cached result of LookupBlockIndex(*m_from_snapshot_blockhash) mutable const CBlockIndex* m_cached_snapshot_base GUARDED_BY(::cs_main){nullptr}; + //! Target block for this chainstate. If this is not set, chainstate will + //! target the most-work, valid block. If this is set, ChainstateManager + //! considers this a "historical" chainstate since it will only contain old + //! blocks up to the target block, not newer blocks. + std::optional m_target_blockhash GUARDED_BY(::cs_main); + //! Cached result of LookupBlockIndex(*m_target_blockhash) mutable const CBlockIndex* m_cached_target_block GUARDED_BY(::cs_main){nullptr}; @@ -635,12 +641,6 @@ public: */ const std::optional m_from_snapshot_blockhash; - //! Target block for this chainstate. If this is not set, chainstate will - //! target the most-work, valid block. If this is set, ChainstateManager - //! considers this a "historical" chainstate since it will only contain old - //! blocks up to the target block, not newer blocks. - std::optional m_target_blockhash GUARDED_BY(::cs_main); - //! Hash of the UTXO set at the target block, computed when the chainstate //! reaches the target block, and null before then. std::optional m_target_utxohash GUARDED_BY(::cs_main); @@ -654,8 +654,17 @@ public: //! Return target block which chainstate tip is expected to reach, if this //! is a historic chainstate being used to validate a snapshot, or null if - //! chainstate targets the most-work block. + //! chainstate targets the most-work block. Requires the block index to be + //! loaded, so prefer TargetBlockHash() when the block itself is not needed. const CBlockIndex* TargetBlock() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); + //! Return hash of the target block, or nullopt if chainstate targets the + //! most-work block. Unlike TargetBlock(), does not require the block index + //! to be loaded. + std::optional TargetBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) + { + AssertLockHeld(::cs_main); + return m_target_blockhash; + } //! Set target block for this chainstate. If null, chainstate will target //! the most-work valid block. If non-null chainstate will be a historic //! chainstate and target the specified block. @@ -1123,7 +1132,7 @@ public: Chainstate& CurrentChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { for (auto& cs : m_chainstates) { - if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && !cs->m_target_blockhash) return *cs; + if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && !cs->TargetBlockHash()) return *cs; } abort(); } @@ -1132,7 +1141,7 @@ public: Chainstate* HistoricalChainstate() const EXCLUSIVE_LOCKS_REQUIRED(GetMutex()) { for (auto& cs : m_chainstates) { - if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && cs->m_target_blockhash && !cs->m_target_utxohash) return cs.get(); + if (cs && cs->m_assumeutxo != Assumeutxo::INVALID && cs->TargetBlockHash() && !cs->m_target_utxohash) return cs.get(); } return nullptr; }