diff --git a/src/node/blockstorage.cpp b/src/node/blockstorage.cpp index f8cdd4ce08c..04936ec99da 100644 --- a/src/node/blockstorage.cpp +++ b/src/node/blockstorage.cpp @@ -38,6 +38,7 @@ #include #include +#include #include namespace kernel { @@ -989,7 +990,7 @@ bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationSt return true; } -bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos) const +bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos, const std::optional& expected_hash) const { block.SetNull(); @@ -1007,8 +1008,10 @@ bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos) const return false; } + const auto block_hash{block.GetHash()}; + // Check the header - if (!CheckProofOfWork(block.GetHash(), block.nBits, GetConsensus())) { + if (!CheckProofOfWork(block_hash, block.nBits, GetConsensus())) { LogError("Errors in block header at %s while reading block", pos.ToString()); return false; } @@ -1019,21 +1022,19 @@ bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos) const return false; } + if (expected_hash && block_hash != *expected_hash) { + LogError("GetHash() doesn't match index at %s while reading block (%s != %s)", + pos.ToString(), block_hash.ToString(), expected_hash->ToString()); + return false; + } + return true; } bool BlockManager::ReadBlock(CBlock& block, const CBlockIndex& index) const { const FlatFilePos block_pos{WITH_LOCK(cs_main, return index.GetBlockPos())}; - - if (!ReadBlock(block, block_pos)) { - return false; - } - if (block.GetHash() != index.GetBlockHash()) { - LogError("GetHash() doesn't match index for %s at %s while reading block", index.ToString(), block_pos.ToString()); - return false; - } - return true; + return ReadBlock(block, block_pos, index.GetBlockHash()); } bool BlockManager::ReadRawBlock(std::vector& block, const FlatFilePos& pos) const diff --git a/src/node/blockstorage.h b/src/node/blockstorage.h index 324f8e68605..9405f68c6cf 100644 --- a/src/node/blockstorage.h +++ b/src/node/blockstorage.h @@ -411,7 +411,7 @@ public: void UnlinkPrunedFiles(const std::set& setFilesToPrune) const; /** Functions for disk access for blocks */ - bool ReadBlock(CBlock& block, const FlatFilePos& pos) const; + bool ReadBlock(CBlock& block, const FlatFilePos& pos, const std::optional& expected_hash = {}) const; bool ReadBlock(CBlock& block, const CBlockIndex& index) const; bool ReadRawBlock(std::vector& block, const FlatFilePos& pos) const; diff --git a/src/test/blockmanager_tests.cpp b/src/test/blockmanager_tests.cpp index 49e49b2d536..d1c64e786dc 100644 --- a/src/test/blockmanager_tests.cpp +++ b/src/test/blockmanager_tests.cpp @@ -137,6 +137,16 @@ BOOST_FIXTURE_TEST_CASE(blockmanager_block_data_availability, TestChain100Setup) BOOST_CHECK(!blockman.CheckBlockDataAvailability(tip, *last_pruned_block)); } +BOOST_FIXTURE_TEST_CASE(blockmanager_readblock_hash_mismatch, TestingSetup) +{ + CBlockIndex* fake_index{WITH_LOCK(m_node.chainman->GetMutex(), return m_node.chainman->ActiveChain().Tip())}; + fake_index->phashBlock = &uint256::ONE; // invalid block hash + + ASSERT_DEBUG_LOG("GetHash() doesn't match index"); + CBlock dummy; + BOOST_CHECK(!m_node.chainman->m_blockman.ReadBlock(dummy, *fake_index)); +} + BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file) { KernelNotifications notifications{Assert(m_node.shutdown_request), m_node.exit_status, *Assert(m_node.warnings)};