validation: remove ConnectTrace wrapper class
What changed, and why it matters
This commit is a simple internal code cleanup in Bitcoin Core. It removes a small wrapper class called ConnectTrace and replaces it with a plain list (std::vector) of connected blocks, renaming some variables for clarity. There is no change to network rules, transaction validation, wallet behavior, or any user-facing feature. It does not fix a bug or introduce a known security issue.
No security action required. Treat as ordinary refactoring code review.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors ConnectTrace/PerBlockConnectTrace into a plain std::vector
Changed components
src/validation.cppsrc/validation.hInspect captured patch +15 / −36
diff --git a/src/validation.cpp b/src/validation.cpp
index b462b7f0..83c16867 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -2987,42 +2987,22 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
return true;
}
-struct PerBlockConnectTrace {
- CBlockIndex* pindex = nullptr;
+struct ConnectedBlock {
+ const CBlockIndex* pindex;
std::shared_ptr<const CBlock> pblock;
};
-/**
- * Used to track blocks whose transactions were applied to the UTXO state as a
- * part of a single ActivateBestChainStep call.
- */
-class ConnectTrace {
-private:
- std::vector<PerBlockConnectTrace> blocksConnected;
-
-public:
- void BlockConnected(CBlockIndex* pindex, std::shared_ptr<const CBlock> pblock) {
- assert(pindex);
- assert(pblock);
- blocksConnected.emplace_back(pindex, std::move(pblock));
- }
-
- const std::vector<PerBlockConnectTrace>& GetBlocksConnected() const
- {
- 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<const CBlock> block_to_connect,
- ConnectTrace& connectTrace,
+ std::vector<ConnectedBlock>& connected_blocks,
DisconnectedBlockTransactions& disconnectpool)
{
AssertLockHeld(cs_main);
@@ -3119,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;
}
@@ -3204,7 +3184,7 @@ void Chainstate::PruneBlockIndexCandidates() {
*
* @returns true unless a system error occurred
*/
-bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace)
+bool Chainstate::ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, std::vector<ConnectedBlock>& connected_blocks)
{
AssertLockHeld(cs_main);
if (m_mempool) AssertLockHeld(m_mempool->cs);
@@ -3249,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<const CBlock>(), connectTrace, disconnectpool)) {
+ if (!ConnectTip(state, pindexConnect, pindexConnect == pindexMostWork ? pblock : std::shared_ptr<const CBlock>(), connected_blocks, disconnectpool)) {
if (state.IsInvalid()) {
// The block violates a consensus rule.
if (state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
@@ -3374,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();
@@ -3382,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<ConnectedBlock> connected_blocks; // Destructed before cs_main is unlocked
if (pindexMostWork == nullptr) {
pindexMostWork = FindMostWorkChain();
@@ -3399,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;
}
@@ -3411,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 482772c0..d65d61ce 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"};
@@ -847,12 +847,12 @@ public:
std::pair<int, int> GetPruneRange(int last_height_can_prune) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
protected:
- bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
+ bool ActivateBestChainStep(BlockValidationState& state, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, std::vector<ConnectedBlock>& connected_blocks) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
bool ConnectTip(
BlockValidationState& state,
CBlockIndex* pindexNew,
std::shared_ptr<const CBlock> block_to_connect,
- ConnectTrace& connectTrace,
+ std::vector<ConnectedBlock>& connected_blocks,
DisconnectedBlockTransactions& disconnectpool) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_mempool->cs);
void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.