Merge bitcoin/bitcoin#31490: refactor: inline UndoWriteToDisk and WriteBlockToDisk to reduce serialization calls

223081ece6 scripted-diff: rename block and undo functions for consistency (Lőrinc)
baaa3b2846 refactor,blocks: remove costly asserts and modernize affected logs (Lőrinc)
fa39f27a0f refactor,blocks: deduplicate block's serialized size calculations (Lőrinc)
dfb2f9d004 refactor,blocks: inline `WriteBlockToDisk` (Lőrinc)
42bc491465 refactor,blocks: inline `UndoWriteToDisk` (Lőrinc)
86b85bb11f bench: add SaveBlockBench (Lőrinc)
34f9a0157a refactor,bench: rename bench/readblock.cpp to bench/readwriteblock.cpp (Lőrinc)

Pull request description:

  `UndoWriteToDisk` and `WriteBlockToDisk` were delegating a subset of their functionality to single-use methods that didn't optimally capture a meaningful chunk of the algorithm, resulting in calculating things twice (serialized size, header size).
  This change inlines the awkward methods (asserting that all previous behavior was retained), and in separate commits makes the usages less confusing.
  Besides making the methods slightly more intuitive, the refactorings reduce duplicate calculations as well.

  The speed difference is insignificant for now (~0.5% for the new `SaveBlockToDiskBench`), but are a cleanup for follow-ups such as https://github.com/bitcoin/bitcoin/pull/31539

ACKs for top commit:
  ryanofsky:
    Code review ACK 223081ece6. Since last review, "Save" was renamed to "Write", uint32_t references were dropped, some log statements and comments were improved as suggested, and a lot of tweaks made to commits and commit messages which should make this easier to review.
  hodlinator:
    ACK 223081ece6
  TheCharlatan:
    ACK 223081ece6
  andrewtoth:
    ACK 223081ece6

Tree-SHA512: 951bc8ad3504c510988afd95c561e3e259c6212bd14f6536fe56e8eb5bf5c35c32a368bbdb1d5aea1acc473d7e5bd9cdcde02008a148b05af1f955e413062d5c
This commit is contained in:
Ryan Ofsky 2025-01-22 11:49:36 -05:00
commit 5d6f6fd00d
No known key found for this signature in database
GPG key ID: 46800E30FC748A66
20 changed files with 179 additions and 204 deletions

View file

@ -44,7 +44,7 @@ add_executable(bench_bitcoin
pool.cpp pool.cpp
prevector.cpp prevector.cpp
random.cpp random.cpp
readblock.cpp readwriteblock.cpp
rollingbloom.cpp rollingbloom.cpp
rpc_blockchain.cpp rpc_blockchain.cpp
rpc_mempool.cpp rpc_mempool.cpp

View file

@ -1,60 +0,0 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <bench/data/block413567.raw.h>
#include <flatfile.h>
#include <node/blockstorage.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
#include <test/util/setup_common.h>
#include <validation.h>
#include <cassert>
#include <cstdint>
#include <memory>
#include <vector>
static FlatFilePos WriteBlockToDisk(ChainstateManager& chainman)
{
DataStream stream{benchmark::data::block413567};
CBlock block;
stream >> TX_WITH_WITNESS(block);
return chainman.m_blockman.SaveBlockToDisk(block, 0);
}
static void ReadBlockFromDiskTest(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
ChainstateManager& chainman{*testing_setup->m_node.chainman};
CBlock block;
const auto pos{WriteBlockToDisk(chainman)};
bench.run([&] {
const auto success{chainman.m_blockman.ReadBlockFromDisk(block, pos)};
assert(success);
});
}
static void ReadRawBlockFromDiskTest(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
ChainstateManager& chainman{*testing_setup->m_node.chainman};
std::vector<uint8_t> block_data;
const auto pos{WriteBlockToDisk(chainman)};
bench.run([&] {
const auto success{chainman.m_blockman.ReadRawBlockFromDisk(block_data, pos)};
assert(success);
});
}
BENCHMARK(ReadBlockFromDiskTest, benchmark::PriorityLevel::HIGH);
BENCHMARK(ReadRawBlockFromDiskTest, benchmark::PriorityLevel::HIGH);

View file

@ -0,0 +1,68 @@
// Copyright (c) 2023 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include <bench/bench.h>
#include <bench/data/block413567.raw.h>
#include <flatfile.h>
#include <node/blockstorage.h>
#include <primitives/block.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <span.h>
#include <streams.h>
#include <test/util/setup_common.h>
#include <validation.h>
#include <cassert>
#include <cstdint>
#include <memory>
#include <vector>
static CBlock CreateTestBlock()
{
DataStream stream{benchmark::data::block413567};
CBlock block;
stream >> TX_WITH_WITNESS(block);
return block;
}
static void SaveBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const CBlock block{CreateTestBlock()};
bench.run([&] {
const auto pos{blockman.WriteBlock(block, 413'567)};
assert(!pos.IsNull());
});
}
static void ReadBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const auto pos{blockman.WriteBlock(CreateTestBlock(), 413'567)};
CBlock block;
bench.run([&] {
const auto success{blockman.ReadBlock(block, pos)};
assert(success);
});
}
static void ReadRawBlockBench(benchmark::Bench& bench)
{
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
auto& blockman{testing_setup->m_node.chainman->m_blockman};
const auto pos{blockman.WriteBlock(CreateTestBlock(), 413'567)};
std::vector<uint8_t> block_data;
blockman.ReadRawBlock(block_data, pos); // warmup
bench.run([&] {
const auto success{blockman.ReadRawBlock(block_data, pos)};
assert(success);
});
}
BENCHMARK(SaveBlockBench, benchmark::PriorityLevel::HIGH);
BENCHMARK(ReadBlockBench, benchmark::PriorityLevel::HIGH);
BENCHMARK(ReadRawBlockBench, benchmark::PriorityLevel::HIGH);

View file

@ -188,7 +188,7 @@ void BaseIndex::Sync()
CBlock block; CBlock block;
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex); interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *pindex)) { if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
FatalErrorf("%s: Failed to read block %s from disk", FatalErrorf("%s: Failed to read block %s from disk",
__func__, pindex->GetBlockHash().ToString()); __func__, pindex->GetBlockHash().ToString());
return; return;
@ -256,7 +256,7 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
// In the case of a reorg, ensure persisted block locator is not stale. // In the case of a reorg, ensure persisted block locator is not stale.
// Pruning has a minimum of 288 blocks-to-keep and getting the index // Pruning has a minimum of 288 blocks-to-keep and getting the index
// out of sync may be possible but a users fault. // out of sync may be possible but a users fault.
// In case we reorg beyond the pruned depth, ReadBlockFromDisk would // In case we reorg beyond the pruned depth, ReadBlock would
// throw and lead to a graceful shutdown // throw and lead to a graceful shutdown
SetBestBlockIndex(new_tip); SetBestBlockIndex(new_tip);
if (!Commit()) { if (!Commit()) {

View file

@ -256,7 +256,7 @@ bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It // pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit // will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash)); const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) { if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false; return false;
} }
} }

View file

@ -123,7 +123,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
// pindex variable gives indexing code access to node internals. It // pindex variable gives indexing code access to node internals. It
// will be removed in upcoming commit // will be removed in upcoming commit
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash)); const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) { if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false; return false;
} }
@ -287,7 +287,7 @@ bool CoinStatsIndex::CustomRewind(const interfaces::BlockRef& current_tip, const
do { do {
CBlock block; CBlock block;
if (!m_chainstate->m_blockman.ReadBlockFromDisk(block, *iter_tip)) { if (!m_chainstate->m_blockman.ReadBlock(block, *iter_tip)) {
LogError("%s: Failed to read block %s from disk\n", LogError("%s: Failed to read block %s from disk\n",
__func__, iter_tip->GetBlockHash().ToString()); __func__, iter_tip->GetBlockHash().ToString());
return false; return false;
@ -415,7 +415,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
// Ignore genesis block // Ignore genesis block
if (pindex->nHeight > 0) { if (pindex->nHeight > 0) {
if (!m_chainstate->m_blockman.UndoReadFromDisk(block_undo, *pindex)) { if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
return false; return false;
} }

View file

@ -1587,7 +1587,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
g_zmq_notification_interface = CZMQNotificationInterface::Create( g_zmq_notification_interface = CZMQNotificationInterface::Create(
[&chainman = node.chainman](std::vector<uint8_t>& block, const CBlockIndex& index) { [&chainman = node.chainman](std::vector<uint8_t>& block, const CBlockIndex& index) {
assert(chainman); assert(chainman);
return chainman->m_blockman.ReadRawBlockFromDisk(block, WITH_LOCK(cs_main, return index.GetBlockPos())); return chainman->m_blockman.ReadRawBlock(block, WITH_LOCK(cs_main, return index.GetBlockPos()));
}); });
if (g_zmq_notification_interface) { if (g_zmq_notification_interface) {

View file

@ -2268,7 +2268,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
// Fast-path: in this case it is possible to serve the block directly from disk, // Fast-path: in this case it is possible to serve the block directly from disk,
// as the network format matches the format on disk // as the network format matches the format on disk
std::vector<uint8_t> block_data; std::vector<uint8_t> block_data;
if (!m_chainman.m_blockman.ReadRawBlockFromDisk(block_data, block_pos)) { if (!m_chainman.m_blockman.ReadRawBlock(block_data, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) { if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs)); LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else { } else {
@ -2282,7 +2282,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
} else { } else {
// Send block from disk // Send block from disk
std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
if (!m_chainman.m_blockman.ReadBlockFromDisk(*pblockRead, block_pos)) { if (!m_chainman.m_blockman.ReadBlock(*pblockRead, block_pos)) {
if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) { if (WITH_LOCK(m_chainman.GetMutex(), return m_chainman.m_blockman.IsBlockPruned(*pindex))) {
LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs)); LogDebug(BCLog::NET, "Block was pruned before it could be read, %s\n", pfrom.DisconnectMsg(fLogIPs));
} else { } else {
@ -4096,7 +4096,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
if (!block_pos.IsNull()) { if (!block_pos.IsNull()) {
CBlock block; CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, block_pos)}; const bool ret{m_chainman.m_blockman.ReadBlock(block, block_pos)};
// If height is above MAX_BLOCKTXN_DEPTH then this block cannot get // If height is above MAX_BLOCKTXN_DEPTH then this block cannot get
// pruned after we release cs_main above, so this read should never fail. // pruned after we release cs_main above, so this read should never fail.
assert(ret); assert(ret);
@ -5599,7 +5599,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
PushMessage(*pto, std::move(cached_cmpctblock_msg.value())); PushMessage(*pto, std::move(cached_cmpctblock_msg.value()));
} else { } else {
CBlock block; CBlock block;
const bool ret{m_chainman.m_blockman.ReadBlockFromDisk(block, *pBestIndex)}; const bool ret{m_chainman.m_blockman.ReadBlock(block, *pBestIndex)};
assert(ret); assert(ret);
CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()}; CBlockHeaderAndShortTxIDs cmpctblock{block, m_rng.rand64()};
MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock); MakeAndPushMessage(*pto, NetMsgType::CMPCTBLOCK, cmpctblock);

View file

@ -669,41 +669,14 @@ CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
return &m_blockfile_info.at(n); return &m_blockfile_info.at(n);
} }
bool BlockManager::UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const bool BlockManager::ReadBlockUndo(CBlockUndo& blockundo, const CBlockIndex& index) const
{
// Open history file to append
AutoFile fileout{OpenUndoFile(pos)};
if (fileout.IsNull()) {
LogError("%s: OpenUndoFile failed\n", __func__);
return false;
}
// Write index header
unsigned int nSize = GetSerializeSize(blockundo);
fileout << GetParams().MessageStart() << nSize;
// Write undo data
long fileOutPos = fileout.tell();
pos.nPos = (unsigned int)fileOutPos;
fileout << blockundo;
// calculate & write checksum
HashWriter hasher{};
hasher << hashBlock;
hasher << blockundo;
fileout << hasher.GetHash();
return true;
}
bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const
{ {
const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())}; const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())};
// Open history file to read // Open history file to read
AutoFile filein{OpenUndoFile(pos, true)}; AutoFile filein{OpenUndoFile(pos, true)};
if (filein.IsNull()) { if (filein.IsNull()) {
LogError("%s: OpenUndoFile failed for %s\n", __func__, pos.ToString()); LogError("OpenUndoFile failed for %s", pos.ToString());
return false; return false;
} }
@ -963,28 +936,7 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
return true; return true;
} }
bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const bool BlockManager::WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
{
// Open history file to append
AutoFile fileout{OpenBlockFile(pos)};
if (fileout.IsNull()) {
LogError("%s: OpenBlockFile failed\n", __func__);
return false;
}
// Write index header
unsigned int nSize = GetSerializeSize(TX_WITH_WITNESS(block));
fileout << GetParams().MessageStart() << nSize;
// Write block
long fileOutPos = fileout.tell();
pos.nPos = (unsigned int)fileOutPos;
fileout << TX_WITH_WITNESS(block);
return true;
}
bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
{ {
AssertLockHeld(::cs_main); AssertLockHeld(::cs_main);
const BlockfileType type = BlockfileTypeForHeight(block.nHeight); const BlockfileType type = BlockfileTypeForHeight(block.nHeight);
@ -992,33 +944,50 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
// Write undo information to disk // Write undo information to disk
if (block.GetUndoPos().IsNull()) { if (block.GetUndoPos().IsNull()) {
FlatFilePos _pos; FlatFilePos pos;
if (!FindUndoPos(state, block.nFile, _pos, ::GetSerializeSize(blockundo) + 40)) { const unsigned int blockundo_size{static_cast<unsigned int>(GetSerializeSize(blockundo))};
LogError("%s: FindUndoPos failed\n", __func__); if (!FindUndoPos(state, block.nFile, pos, blockundo_size + UNDO_DATA_DISK_OVERHEAD)) {
LogError("FindUndoPos failed");
return false; return false;
} }
if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash())) { // Open history file to append
AutoFile fileout{OpenUndoFile(pos)};
if (fileout.IsNull()) {
LogError("OpenUndoFile failed");
return FatalError(m_opts.notifications, state, _("Failed to write undo data.")); return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
} }
// Write index header
fileout << GetParams().MessageStart() << blockundo_size;
// Write undo data
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
fileout << blockundo;
// Calculate & write checksum
HashWriter hasher{};
hasher << block.pprev->GetBlockHash();
hasher << blockundo;
fileout << hasher.GetHash();
// rev files are written in block height order, whereas blk files are written as blocks come in (often out of order) // rev files are written in block height order, whereas blk files are written as blocks come in (often out of order)
// we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height // we want to flush the rev (undo) file once we've written the last block, which is indicated by the last height
// in the block file info as below; note that this does not catch the case where the undo writes are keeping up // in the block file info as below; note that this does not catch the case where the undo writes are keeping up
// with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in // with the block writes (usually when a synced up node is getting newly mined blocks) -- this case is caught in
// the FindNextBlockPos function // the FindNextBlockPos function
if (_pos.nFile < cursor.file_num && static_cast<uint32_t>(block.nHeight) == m_blockfile_info[_pos.nFile].nHeightLast) { if (pos.nFile < cursor.file_num && static_cast<uint32_t>(block.nHeight) == m_blockfile_info[pos.nFile].nHeightLast) {
// Do not propagate the return code, a failed flush here should not // Do not propagate the return code, a failed flush here should not
// be an indication for a failed write. If it were propagated here, // be an indication for a failed write. If it were propagated here,
// the caller would assume the undo data not to be written, when in // the caller would assume the undo data not to be written, when in
// fact it is. Note though, that a failed flush might leave the data // fact it is. Note though, that a failed flush might leave the data
// file untrimmed. // file untrimmed.
if (!FlushUndoFile(_pos.nFile, true)) { if (!FlushUndoFile(pos.nFile, true)) {
LogPrintLevel(BCLog::BLOCKSTORAGE, BCLog::Level::Warning, "Failed to flush undo file %05i\n", _pos.nFile); LogPrintLevel(BCLog::BLOCKSTORAGE, BCLog::Level::Warning, "Failed to flush undo file %05i\n", pos.nFile);
} }
} else if (_pos.nFile == cursor.file_num && block.nHeight > cursor.undo_height) { } else if (pos.nFile == cursor.file_num && block.nHeight > cursor.undo_height) {
cursor.undo_height = block.nHeight; cursor.undo_height = block.nHeight;
} }
// update nUndoPos in block index // update nUndoPos in block index
block.nUndoPos = _pos.nPos; block.nUndoPos = pos.nPos;
block.nStatus |= BLOCK_HAVE_UNDO; block.nStatus |= BLOCK_HAVE_UNDO;
m_dirty_blockindex.insert(&block); m_dirty_blockindex.insert(&block);
} }
@ -1026,7 +995,7 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
return true; return true;
} }
bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const bool BlockManager::ReadBlock(CBlock& block, const FlatFilePos& pos) const
{ {
block.SetNull(); block.SetNull();
@ -1060,11 +1029,11 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) cons
return true; return true;
} }
bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const bool BlockManager::ReadBlock(CBlock& block, const CBlockIndex& index) const
{ {
const FlatFilePos block_pos{WITH_LOCK(cs_main, return index.GetBlockPos())}; const FlatFilePos block_pos{WITH_LOCK(cs_main, return index.GetBlockPos())};
if (!ReadBlockFromDisk(block, block_pos)) { if (!ReadBlock(block, block_pos)) {
return false; return false;
} }
if (block.GetHash() != index.GetBlockHash()) { if (block.GetHash() != index.GetBlockHash()) {
@ -1074,7 +1043,7 @@ bool BlockManager::ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) co
return true; return true;
} }
bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const bool BlockManager::ReadRawBlock(std::vector<uint8_t>& block, const FlatFilePos& pos) const
{ {
FlatFilePos hpos = pos; FlatFilePos hpos = pos;
// If nPos is less than 8 the pos is null and we don't have the block data // If nPos is less than 8 the pos is null and we don't have the block data
@ -1119,22 +1088,27 @@ bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatF
return true; return true;
} }
FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight) FlatFilePos BlockManager::WriteBlock(const CBlock& block, int nHeight)
{ {
unsigned int nBlockSize = ::GetSerializeSize(TX_WITH_WITNESS(block)); const unsigned int block_size{static_cast<unsigned int>(GetSerializeSize(TX_WITH_WITNESS(block)))};
// Account for the 4 magic message start bytes + the 4 length bytes (8 bytes total, FlatFilePos pos{FindNextBlockPos(block_size + BLOCK_SERIALIZATION_HEADER_SIZE, nHeight, block.GetBlockTime())};
// defined as BLOCK_SERIALIZATION_HEADER_SIZE) if (pos.IsNull()) {
nBlockSize += static_cast<unsigned int>(BLOCK_SERIALIZATION_HEADER_SIZE); LogError("FindNextBlockPos failed");
FlatFilePos blockPos{FindNextBlockPos(nBlockSize, nHeight, block.GetBlockTime())};
if (blockPos.IsNull()) {
LogError("%s: FindNextBlockPos failed\n", __func__);
return FlatFilePos(); return FlatFilePos();
} }
if (!WriteBlockToDisk(block, blockPos)) { AutoFile fileout{OpenBlockFile(pos)};
if (fileout.IsNull()) {
LogError("OpenBlockFile failed");
m_opts.notifications.fatalError(_("Failed to write block.")); m_opts.notifications.fatalError(_("Failed to write block."));
return FlatFilePos(); return FlatFilePos();
} }
return blockPos;
// Write index header
fileout << GetParams().MessageStart() << block_size;
// Write block
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
fileout << TX_WITH_WITNESS(block);
return pos;
} }
static auto InitBlocksdirXorKey(const BlockManager::Options& opts) static auto InitBlocksdirXorKey(const BlockManager::Options& opts)

View file

@ -74,8 +74,11 @@ static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
/** The maximum size of a blk?????.dat file (since 0.8) */ /** The maximum size of a blk?????.dat file (since 0.8) */
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
/** Size of header written by WriteBlockToDisk before a serialized CBlock */ /** Size of header written by WriteBlock before a serialized CBlock (8 bytes) */
static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = std::tuple_size_v<MessageStartChars> + sizeof(unsigned int); static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE{std::tuple_size_v<MessageStartChars> + sizeof(unsigned int)};
/** Total overhead when writing undo data: header (8 bytes) plus checksum (32 bytes) */
static constexpr size_t UNDO_DATA_DISK_OVERHEAD{BLOCK_SERIALIZATION_HEADER_SIZE + uint256::size()};
// Because validation code takes pointers to the map's CBlockIndex objects, if // Because validation code takes pointers to the map's CBlockIndex objects, if
// we ever switch to another associative container, we need to either use a // we ever switch to another associative container, we need to either use a
@ -161,7 +164,7 @@ private:
* blockfile info, and checks if there is enough disk space to save the block. * blockfile info, and checks if there is enough disk space to save the block.
* *
* The nAddSize argument passed to this function should include not just the size of the serialized CBlock, but also the size of * The nAddSize argument passed to this function should include not just the size of the serialized CBlock, but also the size of
* separator fields which are written before it by WriteBlockToDisk (BLOCK_SERIALIZATION_HEADER_SIZE). * separator fields (BLOCK_SERIALIZATION_HEADER_SIZE).
*/ */
[[nodiscard]] FlatFilePos FindNextBlockPos(unsigned int nAddSize, unsigned int nHeight, uint64_t nTime); [[nodiscard]] FlatFilePos FindNextBlockPos(unsigned int nAddSize, unsigned int nHeight, uint64_t nTime);
[[nodiscard]] bool FlushChainstateBlockFile(int tip_height); [[nodiscard]] bool FlushChainstateBlockFile(int tip_height);
@ -169,15 +172,6 @@ private:
AutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const; AutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const;
/**
* Write a block to disk. The pos argument passed to this function is modified by this call. Before this call, it should
* point to an unused file location where separator fields will be written, followed by the serialized CBlock data.
* After this call, it will point to the beginning of the serialized CBlock data, after the separator fields
* (BLOCK_SERIALIZATION_HEADER_SIZE)
*/
bool WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const;
bool UndoWriteToDisk(const CBlockUndo& blockundo, FlatFilePos& pos, const uint256& hashBlock) const;
/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
void FindFilesToPruneManual( void FindFilesToPruneManual(
std::set<int>& setFilesToPrune, std::set<int>& setFilesToPrune,
@ -330,7 +324,7 @@ public:
/** Get block file info entry for one block file */ /** Get block file info entry for one block file */
CBlockFileInfo* GetBlockFileInfo(size_t n); CBlockFileInfo* GetBlockFileInfo(size_t n);
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) bool WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main); EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
/** Store block on disk and update block file statistics. /** Store block on disk and update block file statistics.
@ -341,14 +335,13 @@ public:
* @returns in case of success, the position to which the block was written to * @returns in case of success, the position to which the block was written to
* in case of an error, an empty FlatFilePos * in case of an error, an empty FlatFilePos
*/ */
FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight); FlatFilePos WriteBlock(const CBlock& block, int nHeight);
/** Update blockfile info while processing a block during reindex. The block must be available on disk. /** Update blockfile info while processing a block during reindex. The block must be available on disk.
* *
* @param[in] block the block being processed * @param[in] block the block being processed
* @param[in] nHeight the height of the block * @param[in] nHeight the height of the block
* @param[in] pos the position of the serialized CBlock on disk. This is the position returned * @param[in] pos the position of the serialized CBlock on disk
* by WriteBlockToDisk pointing at the CBlock, not the separator fields before it
*/ */
void UpdateBlockInfo(const CBlock& block, unsigned int nHeight, const FlatFilePos& pos); void UpdateBlockInfo(const CBlock& block, unsigned int nHeight, const FlatFilePos& pos);
@ -421,11 +414,11 @@ public:
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const; void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const;
/** Functions for disk access for blocks */ /** Functions for disk access for blocks */
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const; bool ReadBlock(CBlock& block, const FlatFilePos& pos) const;
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const; bool ReadBlock(CBlock& block, const CBlockIndex& index) const;
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const; bool ReadRawBlock(std::vector<uint8_t>& block, const FlatFilePos& pos) const;
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const; bool ReadBlockUndo(CBlockUndo& blockundo, const CBlockIndex& index) const;
void CleanupBlockRevFiles() const; void CleanupBlockRevFiles() const;
}; };

View file

@ -442,7 +442,7 @@ bool FillBlock(const CBlockIndex* index, const FoundBlock& block, UniqueLock<Rec
if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active, blockman); if (block.m_next_block) FillBlock(active[index->nHeight] == index ? active[index->nHeight + 1] : nullptr, *block.m_next_block, lock, active, blockman);
if (block.m_data) { if (block.m_data) {
REVERSE_LOCK(lock); REVERSE_LOCK(lock);
if (!blockman.ReadBlockFromDisk(*block.m_data, *index)) block.m_data->SetNull(); if (!blockman.ReadBlock(*block.m_data, *index)) block.m_data->SetNull();
} }
block.found = true; block.found = true;
return true; return true;

View file

@ -144,7 +144,7 @@ CTransactionRef GetTransaction(const CBlockIndex* const block_index, const CTxMe
} }
if (block_index) { if (block_index) {
CBlock block; CBlock block;
if (blockman.ReadBlockFromDisk(block, *block_index)) { if (blockman.ReadBlock(block, *block_index)) {
for (const auto& tx : block.vtx) { for (const auto& tx : block.vtx) {
if (tx->GetHash() == hash) { if (tx->GetHash() == hash) {
hashBlock = block_index->GetBlockHash(); hashBlock = block_index->GetBlockHash();

View file

@ -319,7 +319,7 @@ static bool rest_block(const std::any& context,
} }
std::vector<uint8_t> block_data{}; std::vector<uint8_t> block_data{};
if (!chainman.m_blockman.ReadRawBlockFromDisk(block_data, pos)) { if (!chainman.m_blockman.ReadRawBlock(block_data, pos)) {
return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found"); return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
} }

View file

@ -196,7 +196,7 @@ UniValue blockToJSON(BlockManager& blockman, const CBlock& block, const CBlockIn
CBlockUndo blockUndo; CBlockUndo blockUndo;
const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))}; const bool is_not_pruned{WITH_LOCK(::cs_main, return !blockman.IsBlockPruned(blockindex))};
bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)}; bool have_undo{is_not_pruned && WITH_LOCK(::cs_main, return blockindex.nStatus & BLOCK_HAVE_UNDO)};
if (have_undo && !blockman.UndoReadFromDisk(blockUndo, blockindex)) { if (have_undo && !blockman.ReadBlockUndo(blockUndo, blockindex)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
} }
for (size_t i = 0; i < block.vtx.size(); ++i) { for (size_t i = 0; i < block.vtx.size(); ++i) {
@ -624,7 +624,7 @@ static CBlock GetBlockChecked(BlockManager& blockman, const CBlockIndex& blockin
CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false); CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/false);
} }
if (!blockman.ReadBlockFromDisk(block, blockindex)) { if (!blockman.ReadBlock(block, blockindex)) {
// Block not found on disk. This shouldn't normally happen unless the block was // Block not found on disk. This shouldn't normally happen unless the block was
// pruned right after we released the lock above. // pruned right after we released the lock above.
throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
@ -643,7 +643,7 @@ static std::vector<uint8_t> GetRawBlockChecked(BlockManager& blockman, const CBl
pos = blockindex.GetBlockPos(); pos = blockindex.GetBlockPos();
} }
if (!blockman.ReadRawBlockFromDisk(data, pos)) { if (!blockman.ReadRawBlock(data, pos)) {
// Block not found on disk. This shouldn't normally happen unless the block was // Block not found on disk. This shouldn't normally happen unless the block was
// pruned right after we released the lock above. // pruned right after we released the lock above.
throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk"); throw JSONRPCError(RPC_MISC_ERROR, "Block not found on disk");
@ -664,7 +664,7 @@ static CBlockUndo GetUndoChecked(BlockManager& blockman, const CBlockIndex& bloc
CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true); CheckBlockDataAvailability(blockman, blockindex, /*check_for_undo=*/true);
} }
if (!blockman.UndoReadFromDisk(blockUndo, blockindex)) { if (!blockman.ReadBlockUndo(blockUndo, blockindex)) {
throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk"); throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
} }

View file

@ -390,10 +390,10 @@ static RPCHelpMan getrawtransaction()
TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate()); TxToJSON(*tx, hash_block, result, chainman.ActiveChainstate());
return result; return result;
} }
if (!chainman.m_blockman.UndoReadFromDisk(blockUndo, *blockindex)) { if (!chainman.m_blockman.ReadBlockUndo(blockUndo, *blockindex)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); throw JSONRPCError(RPC_INTERNAL_ERROR, "Undo data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
} }
if (!chainman.m_blockman.ReadBlockFromDisk(block, *blockindex)) { if (!chainman.m_blockman.ReadBlock(block, *blockindex)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Block data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event."); throw JSONRPCError(RPC_INTERNAL_ERROR, "Block data expected but can't be read. This could be due to disk corruption or a conflict with a pruning event.");
} }

View file

@ -102,7 +102,7 @@ static RPCHelpMan gettxoutproof()
CheckBlockDataAvailability(chainman.m_blockman, *pblockindex, /*check_for_undo=*/false); CheckBlockDataAvailability(chainman.m_blockman, *pblockindex, /*check_for_undo=*/false);
} }
CBlock block; CBlock block;
if (!chainman.m_blockman.ReadBlockFromDisk(block, *pblockindex)) { if (!chainman.m_blockman.ReadBlock(block, *pblockindex)) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk"); throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
} }

View file

@ -36,7 +36,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
}; };
BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts}; BlockManager blockman{*Assert(m_node.shutdown_signal), blockman_opts};
// simulate adding a genesis block normally // simulate adding a genesis block normally
BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0).nPos, BLOCK_SERIALIZATION_HEADER_SIZE); BOOST_CHECK_EQUAL(blockman.WriteBlock(params->GenesisBlock(), 0).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);
// simulate what happens during reindex // simulate what happens during reindex
// simulate a well-formed genesis block being found at offset 8 in the blk00000.dat file // simulate a well-formed genesis block being found at offset 8 in the blk00000.dat file
// the block is found at offset 8 because there is an 8 byte serialization header // the block is found at offset 8 because there is an 8 byte serialization header
@ -49,7 +49,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
// this is a check to make sure that https://github.com/bitcoin/bitcoin/issues/21379 does not recur // this is a check to make sure that https://github.com/bitcoin/bitcoin/issues/21379 does not recur
// 8 bytes (for serialization header) + 285 (for serialized genesis block) = 293 // 8 bytes (for serialization header) + 285 (for serialized genesis block) = 293
// add another 8 bytes for the second block's serialization header and we get 293 + 8 = 301 // add another 8 bytes for the second block's serialization header and we get 293 + 8 = 301
FlatFilePos actual{blockman.SaveBlockToDisk(params->GenesisBlock(), 1)}; FlatFilePos actual{blockman.WriteBlock(params->GenesisBlock(), 1)};
BOOST_CHECK_EQUAL(actual.nPos, BLOCK_SERIALIZATION_HEADER_SIZE + ::GetSerializeSize(TX_WITH_WITNESS(params->GenesisBlock())) + BLOCK_SERIALIZATION_HEADER_SIZE); BOOST_CHECK_EQUAL(actual.nPos, BLOCK_SERIALIZATION_HEADER_SIZE + ::GetSerializeSize(TX_WITH_WITNESS(params->GenesisBlock())) + BLOCK_SERIALIZATION_HEADER_SIZE);
} }
@ -158,10 +158,10 @@ BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), 0); BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), 0);
// Write the first block to a new location. // Write the first block to a new location.
FlatFilePos pos1{blockman.SaveBlockToDisk(block1, /*nHeight=*/1)}; FlatFilePos pos1{blockman.WriteBlock(block1, /*nHeight=*/1)};
// Write second block // Write second block
FlatFilePos pos2{blockman.SaveBlockToDisk(block2, /*nHeight=*/2)}; FlatFilePos pos2{blockman.WriteBlock(block2, /*nHeight=*/2)};
// Two blocks in the file // Two blocks in the file
BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), (TEST_BLOCK_SIZE + BLOCK_SERIALIZATION_HEADER_SIZE) * 2); BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), (TEST_BLOCK_SIZE + BLOCK_SERIALIZATION_HEADER_SIZE) * 2);
@ -171,13 +171,13 @@ BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
CBlock read_block; CBlock read_block;
BOOST_CHECK_EQUAL(read_block.nVersion, 0); BOOST_CHECK_EQUAL(read_block.nVersion, 0);
{ {
ASSERT_DEBUG_LOG("ReadBlockFromDisk: Errors in block header"); ASSERT_DEBUG_LOG("ReadBlock: Errors in block header");
BOOST_CHECK(!blockman.ReadBlockFromDisk(read_block, pos1)); BOOST_CHECK(!blockman.ReadBlock(read_block, pos1));
BOOST_CHECK_EQUAL(read_block.nVersion, 1); BOOST_CHECK_EQUAL(read_block.nVersion, 1);
} }
{ {
ASSERT_DEBUG_LOG("ReadBlockFromDisk: Errors in block header"); ASSERT_DEBUG_LOG("ReadBlock: Errors in block header");
BOOST_CHECK(!blockman.ReadBlockFromDisk(read_block, pos2)); BOOST_CHECK(!blockman.ReadBlock(read_block, pos2));
BOOST_CHECK_EQUAL(read_block.nVersion, 2); BOOST_CHECK_EQUAL(read_block.nVersion, 2);
} }
@ -194,7 +194,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_flush_block_file)
BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), (TEST_BLOCK_SIZE + BLOCK_SERIALIZATION_HEADER_SIZE) * 2); BOOST_CHECK_EQUAL(blockman.CalculateCurrentUsage(), (TEST_BLOCK_SIZE + BLOCK_SERIALIZATION_HEADER_SIZE) * 2);
// Block 2 was not overwritten: // Block 2 was not overwritten:
blockman.ReadBlockFromDisk(read_block, pos2); blockman.ReadBlock(read_block, pos2);
BOOST_CHECK_EQUAL(read_block.nVersion, 2); BOOST_CHECK_EQUAL(read_block.nVersion, 2);
} }

View file

@ -17,12 +17,12 @@ bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex& block_index,
LOCK(::cs_main); LOCK(::cs_main);
CBlock block; CBlock block;
if (!blockman.ReadBlockFromDisk(block, block_index.GetBlockPos())) { if (!blockman.ReadBlock(block, block_index.GetBlockPos())) {
return false; return false;
} }
CBlockUndo block_undo; CBlockUndo block_undo;
if (block_index.nHeight > 0 && !blockman.UndoReadFromDisk(block_undo, block_index)) { if (block_index.nHeight > 0 && !blockman.ReadBlockUndo(block_undo, block_index)) {
return false; return false;
} }

View file

@ -88,7 +88,7 @@ BOOST_FIXTURE_TEST_CASE(chainstate_update_tip, TestChain100Setup)
std::shared_ptr<CBlock> pblockone = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblockone = std::make_shared<CBlock>();
{ {
LOCK(::cs_main); LOCK(::cs_main);
chainman.m_blockman.ReadBlockFromDisk(*pblockone, *chainman.ActiveChain()[1]); chainman.m_blockman.ReadBlock(*pblockone, *chainman.ActiveChain()[1]);
} }
BOOST_REQUIRE(CreateAndActivateUTXOSnapshot( BOOST_REQUIRE(CreateAndActivateUTXOSnapshot(

View file

@ -2301,7 +2301,7 @@ DisconnectResult Chainstate::DisconnectBlock(const CBlock& block, const CBlockIn
bool fClean = true; bool fClean = true;
CBlockUndo blockUndo; CBlockUndo blockUndo;
if (!m_blockman.UndoReadFromDisk(blockUndo, *pindex)) { if (!m_blockman.ReadBlockUndo(blockUndo, *pindex)) {
LogError("DisconnectBlock(): failure reading undo data\n"); LogError("DisconnectBlock(): failure reading undo data\n");
return DISCONNECT_FAILED; return DISCONNECT_FAILED;
} }
@ -2747,7 +2747,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state,
return true; return true;
} }
if (!m_blockman.WriteUndoDataForBlock(blockundo, state, *pindex)) { if (!m_blockman.WriteBlockUndo(blockundo, state, *pindex)) {
return false; return false;
} }
@ -3068,7 +3068,7 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
// Read block from disk. // Read block from disk.
std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
CBlock& block = *pblock; CBlock& block = *pblock;
if (!m_blockman.ReadBlockFromDisk(block, *pindexDelete)) { if (!m_blockman.ReadBlock(block, *pindexDelete)) {
LogError("DisconnectTip(): Failed to read block\n"); LogError("DisconnectTip(): Failed to read block\n");
return false; return false;
} }
@ -3179,7 +3179,7 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
std::shared_ptr<const CBlock> pthisBlock; std::shared_ptr<const CBlock> pthisBlock;
if (!pblock) { if (!pblock) {
std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
if (!m_blockman.ReadBlockFromDisk(*pblockNew, *pindexNew)) { if (!m_blockman.ReadBlock(*pblockNew, *pindexNew)) {
return FatalError(m_chainman.GetNotifications(), state, _("Failed to read block.")); return FatalError(m_chainman.GetNotifications(), state, _("Failed to read block."));
} }
pthisBlock = pblockNew; pthisBlock = pblockNew;
@ -4564,7 +4564,7 @@ bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock,
blockPos = *dbp; blockPos = *dbp;
m_blockman.UpdateBlockInfo(block, pindex->nHeight, blockPos); m_blockman.UpdateBlockInfo(block, pindex->nHeight, blockPos);
} else { } else {
blockPos = m_blockman.SaveBlockToDisk(block, pindex->nHeight); blockPos = m_blockman.WriteBlock(block, pindex->nHeight);
if (blockPos.IsNull()) { if (blockPos.IsNull()) {
state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__)); state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
return false; return false;
@ -4797,8 +4797,8 @@ VerifyDBResult CVerifyDB::VerifyDB(
} }
CBlock block; CBlock block;
// check level 0: read from disk // check level 0: read from disk
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) { if (!chainstate.m_blockman.ReadBlock(block, *pindex)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); LogPrintf("Verification error: ReadBlock failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB; return VerifyDBResult::CORRUPTED_BLOCK_DB;
} }
// check level 1: verify block validity // check level 1: verify block validity
@ -4811,7 +4811,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
if (nCheckLevel >= 2 && pindex) { if (nCheckLevel >= 2 && pindex) {
CBlockUndo undo; CBlockUndo undo;
if (!pindex->GetUndoPos().IsNull()) { if (!pindex->GetUndoPos().IsNull()) {
if (!chainstate.m_blockman.UndoReadFromDisk(undo, *pindex)) { if (!chainstate.m_blockman.ReadBlockUndo(undo, *pindex)) {
LogPrintf("Verification error: found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); LogPrintf("Verification error: found bad undo data at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB; return VerifyDBResult::CORRUPTED_BLOCK_DB;
} }
@ -4863,8 +4863,8 @@ VerifyDBResult CVerifyDB::VerifyDB(
m_notifications.progress(_("Verifying blocks…"), percentageDone, false); m_notifications.progress(_("Verifying blocks…"), percentageDone, false);
pindex = chainstate.m_chain.Next(pindex); pindex = chainstate.m_chain.Next(pindex);
CBlock block; CBlock block;
if (!chainstate.m_blockman.ReadBlockFromDisk(block, *pindex)) { if (!chainstate.m_blockman.ReadBlock(block, *pindex)) {
LogPrintf("Verification error: ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); LogPrintf("Verification error: ReadBlock failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB; return VerifyDBResult::CORRUPTED_BLOCK_DB;
} }
if (!chainstate.ConnectBlock(block, state, pindex, coins)) { if (!chainstate.ConnectBlock(block, state, pindex, coins)) {
@ -4892,8 +4892,8 @@ bool Chainstate::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& in
AssertLockHeld(cs_main); AssertLockHeld(cs_main);
// TODO: merge with ConnectBlock // TODO: merge with ConnectBlock
CBlock block; CBlock block;
if (!m_blockman.ReadBlockFromDisk(block, *pindex)) { if (!m_blockman.ReadBlock(block, *pindex)) {
LogError("ReplayBlock(): ReadBlockFromDisk failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString()); LogError("ReplayBlock(): ReadBlock failed at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
return false; return false;
} }
@ -4950,8 +4950,8 @@ bool Chainstate::ReplayBlocks()
while (pindexOld != pindexFork) { while (pindexOld != pindexFork) {
if (pindexOld->nHeight > 0) { // Never disconnect the genesis block. if (pindexOld->nHeight > 0) { // Never disconnect the genesis block.
CBlock block; CBlock block;
if (!m_blockman.ReadBlockFromDisk(block, *pindexOld)) { if (!m_blockman.ReadBlock(block, *pindexOld)) {
LogError("RollbackBlock(): ReadBlockFromDisk() failed at %d, hash=%s\n", pindexOld->nHeight, pindexOld->GetBlockHash().ToString()); LogError("RollbackBlock(): ReadBlock() failed at %d, hash=%s\n", pindexOld->nHeight, pindexOld->GetBlockHash().ToString());
return false; return false;
} }
LogPrintf("Rolling back %s (%i)\n", pindexOld->GetBlockHash().ToString(), pindexOld->nHeight); LogPrintf("Rolling back %s (%i)\n", pindexOld->GetBlockHash().ToString(), pindexOld->nHeight);
@ -5062,7 +5062,7 @@ bool Chainstate::LoadGenesisBlock()
try { try {
const CBlock& block = params.GenesisBlock(); const CBlock& block = params.GenesisBlock();
FlatFilePos blockPos{m_blockman.SaveBlockToDisk(block, 0)}; FlatFilePos blockPos{m_blockman.WriteBlock(block, 0)};
if (blockPos.IsNull()) { if (blockPos.IsNull()) {
LogError("%s: writing genesis block to disk failed\n", __func__); LogError("%s: writing genesis block to disk failed\n", __func__);
return false; return false;
@ -5219,7 +5219,7 @@ void ChainstateManager::LoadExternalBlockFile(
while (range.first != range.second) { while (range.first != range.second) {
std::multimap<uint256, FlatFilePos>::iterator it = range.first; std::multimap<uint256, FlatFilePos>::iterator it = range.first;
std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>(); std::shared_ptr<CBlock> pblockrecursive = std::make_shared<CBlock>();
if (m_blockman.ReadBlockFromDisk(*pblockrecursive, it->second)) { if (m_blockman.ReadBlock(*pblockrecursive, it->second)) {
LogDebug(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(), LogDebug(BCLog::REINDEX, "%s: Processing out of order child %s of %s\n", __func__, pblockrecursive->GetHash().ToString(),
head.ToString()); head.ToString());
LOCK(cs_main); LOCK(cs_main);