test: Wrap validation functions with TestChainstateManager
What changed, and why it matters
This commit only changes test infrastructure code. It moves some internal class members from private to protected access and adds test-only wrapper methods so that fuzz tests can reach validation logic without making those functions public in the main codebase. There is no change to how Bitcoin Core behaves in production, and no security bug is being fixed or introduced.
No security action required; treat as ordinary test refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors access modifiers in node::BlockManager and ChainstateManager (private -> protected for m_blockfile_info, m_dirty_blockindex, m_dirty_fileinfo, and m_best_invalid) and introduces TestBlockManager::CleanupForFuzzing plus TestChainstateManager wrappers for InvalidBlockFound, InvalidChainFound, FindMostWorkChain, and ResetBestInvalid. These wrappers use a local TestChainstate subclass to call otherwise inaccessible protected Chainstate methods. The changes are confined to test utilities and header visibility; no consensus or networking logic is modified.
Changed components
src/test/util/validation.cppsrc/test/util/validation.hsrc/node/blockstorage.hsrc/validation.hInspect captured patch +73 / −8
diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h
index c381d1c9..bef99984 100644
--- a/src/node/blockstorage.h
+++ b/src/node/blockstorage.h
@@ -248,7 +248,6 @@ private:
ChainstateManager& chainman);
RecursiveMutex cs_LastBlockFile;
- std::vector<CBlockFileInfo> m_blockfile_info;
//! Since assumedvalid chainstates may be syncing a range of the chain that is very
//! far away from the normal/background validation process, we should segment blockfiles
@@ -283,12 +282,6 @@ private:
const Obfuscation m_obfuscation;
- /** Dirty block index entries. */
- std::set<CBlockIndex*> m_dirty_blockindex;
-
- /** Dirty block file entries. */
- std::set<int> m_dirty_fileinfo;
-
/**
* Map from external index name to oldest block that must not be pruned.
*
@@ -304,6 +297,15 @@ private:
const FlatFileSeq m_block_file_seq;
const FlatFileSeq m_undo_file_seq;
+protected:
+ std::vector<CBlockFileInfo> m_blockfile_info;
+
+ /** Dirty block index entries. */
+ std::set<CBlockIndex*> m_dirty_blockindex;
+
+ /** Dirty block file entries. */
+ std::set<int> m_dirty_fileinfo;
+
public:
using Options = kernel::BlockManagerOpts;
using ReadRawBlockResult = util::Expected<std::vector<std::byte>, ReadRawError>;
diff --git a/src/test/util/validation.cpp b/src/test/util/validation.cpp
index c199d912..b9f79f1d 100644
--- a/src/test/util/validation.cpp
+++ b/src/test/util/validation.cpp
@@ -4,6 +4,7 @@
#include <test/util/validation.h>
+#include <node/blockstorage.h>
#include <util/check.h>
#include <util/time.h>
#include <validation.h>
@@ -11,6 +12,13 @@
using kernel::ChainstateRole;
+void TestBlockManager::CleanupForFuzzing()
+{
+ m_dirty_blockindex.clear();
+ m_dirty_fileinfo.clear();
+ m_blockfile_info.resize(1);
+}
+
void TestChainstateManager::DisableNextWrite()
{
struct TestChainstate : public Chainstate {
@@ -43,3 +51,43 @@ void ValidationInterfaceTest::BlockConnected(
{
obj.BlockConnected(role, block, pindex);
}
+void TestChainstateManager::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state)
+{
+ struct TestChainstate : public Chainstate {
+ void CallInvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ InvalidBlockFound(pindex, state);
+ }
+ };
+
+ static_cast<TestChainstate*>(&ActiveChainstate())->CallInvalidBlockFound(pindex, state);
+}
+
+void TestChainstateManager::InvalidChainFound(CBlockIndex* pindexNew)
+{
+ struct TestChainstate : public Chainstate {
+ void CallInvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ InvalidChainFound(pindexNew);
+ }
+ };
+
+ static_cast<TestChainstate*>(&ActiveChainstate())->CallInvalidChainFound(pindexNew);
+}
+
+CBlockIndex* TestChainstateManager::FindMostWorkChain()
+{
+ struct TestChainstate : public Chainstate {
+ CBlockIndex* CallFindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main)
+ {
+ return FindMostWorkChain();
+ }
+ };
+
+ return static_cast<TestChainstate*>(&ActiveChainstate())->CallFindMostWorkChain();
+}
+
+void TestChainstateManager::ResetBestInvalid()
+{
+ m_best_invalid = nullptr;
+}
diff --git a/src/test/util/validation.h b/src/test/util/validation.h
index 4a24c97e..debad32d 100644
--- a/src/test/util/validation.h
+++ b/src/test/util/validation.h
@@ -7,8 +7,16 @@
#include <validation.h>
+namespace node {
+class BlockManager;
+}
class CValidationInterface;
+struct TestBlockManager : public node::BlockManager {
+ /** Test-only method to clear internal state for fuzzing */
+ void CleanupForFuzzing();
+};
+
struct TestChainstateManager : public ChainstateManager {
/** Disable the next write of all chainstates */
void DisableNextWrite();
@@ -16,6 +24,11 @@ struct TestChainstateManager : public ChainstateManager {
void ResetIbd();
/** Toggle IsInitialBlockDownload from true to false */
void JumpOutOfIbd();
+ /** Wrappers that avoid making chainstatemanager internals public for tests */
+ void InvalidBlockFound(CBlockIndex* pindex, const BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void InvalidChainFound(CBlockIndex* pindexNew) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ResetBestInvalid() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
};
class ValidationInterfaceTest
diff --git a/src/validation.h b/src/validation.h
index 77958b53..e4b1e555 100644
--- a/src/validation.h
+++ b/src/validation.h
@@ -929,7 +929,6 @@ enum class SnapshotCompletionResult {
class ChainstateManager
{
private:
- CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
/** The last header for which a headerTip notification was issued. */
CBlockIndex* m_last_notified_header GUARDED_BY(GetMutex()){nullptr};
@@ -983,6 +982,9 @@ private:
SteadyClock::duration GUARDED_BY(::cs_main) time_chainstate{};
SteadyClock::duration GUARDED_BY(::cs_main) time_post_connect{};
+protected:
+ CBlockIndex* m_best_invalid GUARDED_BY(::cs_main){nullptr};
+
public:
using Options = kernel::ChainstateManagerOpts;
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.