mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-24 18:23:26 -03:00
Merge 1f736fbdb4
into 66aa6a47bd
This commit is contained in:
commit
5707851c3a
7 changed files with 183 additions and 165 deletions
|
@ -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
|
||||||
|
|
|
@ -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);
|
|
79
src/bench/readwriteblock.cpp
Normal file
79
src/bench/readwriteblock.cpp
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
// 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>
|
||||||
|
|
||||||
|
CBlock CreateTestBlock()
|
||||||
|
{
|
||||||
|
DataStream stream{benchmark::data::block413567};
|
||||||
|
CBlock block;
|
||||||
|
stream >> TX_WITH_WITNESS(block);
|
||||||
|
return block;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void GetSerializeSizeBench(benchmark::Bench& bench)
|
||||||
|
{
|
||||||
|
const auto testing_setup{MakeNoLogFileContext<const TestingSetup>(ChainType::MAIN)};
|
||||||
|
const CBlock block{CreateTestBlock()};
|
||||||
|
bench.run([&] {
|
||||||
|
const uint32_t block_size{static_cast<uint32_t>(GetSerializeSize(TX_WITH_WITNESS(block)))};
|
||||||
|
assert(block_size == benchmark::data::block413567.size());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SaveBlockToDiskBench(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.SaveBlock(block, 413'567)};
|
||||||
|
assert(!pos.IsNull());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReadBlockFromDiskBench(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.SaveBlock(CreateTestBlock(), 413'567)};
|
||||||
|
CBlock block;
|
||||||
|
bench.run([&] {
|
||||||
|
const auto success{blockman.ReadBlockFromDisk(block, pos)};
|
||||||
|
assert(success);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ReadRawBlockFromDiskBench(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.SaveBlock(CreateTestBlock(), 413'567)};
|
||||||
|
std::vector<uint8_t> block_data;
|
||||||
|
blockman.ReadRawBlockFromDisk(block_data, pos); // warmup
|
||||||
|
bench.run([&] {
|
||||||
|
const auto success{blockman.ReadRawBlockFromDisk(block_data, pos)};
|
||||||
|
assert(success);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
BENCHMARK(GetSerializeSizeBench, benchmark::PriorityLevel::HIGH);
|
||||||
|
BENCHMARK(SaveBlockToDiskBench, benchmark::PriorityLevel::HIGH);
|
||||||
|
BENCHMARK(ReadBlockFromDiskBench, benchmark::PriorityLevel::HIGH);
|
||||||
|
BENCHMARK(ReadRawBlockFromDiskBench, benchmark::PriorityLevel::HIGH);
|
|
@ -669,36 +669,12 @@ 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
|
|
||||||
{
|
|
||||||
// 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
|
bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& index) const
|
||||||
{
|
{
|
||||||
const FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())};
|
FlatFilePos pos{WITH_LOCK(::cs_main, return index.GetUndoPos())};
|
||||||
|
if (pos.nPos < BLOCK_SERIALIZATION_HEADER_SIZE) return false;
|
||||||
|
uint32_t undo_size;
|
||||||
|
pos.nPos -= sizeof undo_size;
|
||||||
|
|
||||||
// Open history file to read
|
// Open history file to read
|
||||||
AutoFile filein{OpenUndoFile(pos, true)};
|
AutoFile filein{OpenUndoFile(pos, true)};
|
||||||
|
@ -708,23 +684,29 @@ bool BlockManager::UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex& in
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read block
|
// Read block
|
||||||
uint256 hashChecksum;
|
|
||||||
HashVerifier verifier{filein}; // Use HashVerifier as reserializing may lose data, c.f. commit d342424301013ec47dc146a4beb49d5c9319d80a
|
|
||||||
try {
|
try {
|
||||||
|
filein >> undo_size;
|
||||||
|
if (undo_size > MAX_SIZE) throw std::runtime_error{strprintf("Refusing to read undo data of size: %d", undo_size)};
|
||||||
|
|
||||||
|
std::vector<uint8_t> mem(undo_size);
|
||||||
|
filein >> Span{mem};
|
||||||
|
|
||||||
|
SpanReader reader{mem};
|
||||||
|
HashVerifier verifier{reader}; // Use HashVerifier as reserializing may lose data, c.f. commit d342424301013ec47dc146a4beb49d5c9319d80a
|
||||||
verifier << index.pprev->GetBlockHash();
|
verifier << index.pprev->GetBlockHash();
|
||||||
verifier >> blockundo;
|
verifier >> blockundo;
|
||||||
|
|
||||||
|
uint256 hashChecksum;
|
||||||
filein >> hashChecksum;
|
filein >> hashChecksum;
|
||||||
|
if (hashChecksum != verifier.GetHash()) {
|
||||||
|
LogError("%s: Checksum mismatch at %s\n", __func__, pos.ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogError("%s: Deserialize or I/O error - %s at %s\n", __func__, e.what(), pos.ToString());
|
LogError("%s: Deserialize or I/O error - %s at %s\n", __func__, e.what(), pos.ToString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify checksum
|
|
||||||
if (hashChecksum != verifier.GetHash()) {
|
|
||||||
LogError("%s: Checksum mismatch at %s\n", __func__, pos.ToString());
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,62 +945,64 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockManager::WriteBlockToDisk(const CBlock& block, FlatFilePos& pos) const
|
bool BlockManager::SaveBlockUndo(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);
|
||||||
auto& cursor = *Assert(WITH_LOCK(cs_LastBlockFile, return m_blockfile_cursors[type]));
|
auto& cursor = *Assert(WITH_LOCK(cs_LastBlockFile, return m_blockfile_cursors[type]));
|
||||||
|
|
||||||
// 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 uint32_t blockundo_size{static_cast<uint32_t>(GetSerializeSize(blockundo))};
|
||||||
|
if (!FindUndoPos(state, block.nFile, pos, UNDO_DATA_DISK_OVERHEAD + blockundo_size)) {
|
||||||
LogError("%s: FindUndoPos failed\n", __func__);
|
LogError("%s: FindUndoPos failed\n", __func__);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!UndoWriteToDisk(blockundo, _pos, block.pprev->GetBlockHash())) {
|
AutoFile fileout{m_undo_file_seq.Open(pos, false), {}}; // We'll obfuscate ourselves
|
||||||
|
if (fileout.IsNull()) {
|
||||||
|
LogError("%s: OpenUndoFile failed\n", __func__);
|
||||||
return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
|
return FatalError(m_opts.notifications, state, _("Failed to write undo data."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
DataStream header;
|
||||||
|
header.reserve(BLOCK_SERIALIZATION_HEADER_SIZE);
|
||||||
|
header << GetParams().MessageStart() << blockundo_size;
|
||||||
|
util::Xor(header, m_xor_key, pos.nPos);
|
||||||
|
fileout.write(header);
|
||||||
|
}
|
||||||
|
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
|
||||||
|
{
|
||||||
|
HashWriter hasher;
|
||||||
|
hasher << block.pprev->GetBlockHash();
|
||||||
|
hasher << blockundo;
|
||||||
|
|
||||||
|
DataStream undo_data;
|
||||||
|
undo_data.reserve(blockundo_size + sizeof(uint256));
|
||||||
|
undo_data << blockundo << hasher.GetHash();
|
||||||
|
util::Xor(undo_data, m_xor_key, pos.nPos);
|
||||||
|
fileout.write(undo_data);
|
||||||
|
}
|
||||||
|
|
||||||
// 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,20 +1010,26 @@ bool BlockManager::WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValid
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BlockManager::ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos) const
|
bool BlockManager::ReadBlockFromDisk(CBlock& block, FlatFilePos pos) const
|
||||||
{
|
{
|
||||||
block.SetNull();
|
block.SetNull();
|
||||||
|
|
||||||
// Open history file to read
|
if (pos.nPos < BLOCK_SERIALIZATION_HEADER_SIZE) return false;
|
||||||
|
uint32_t blk_size;
|
||||||
|
pos.nPos -= sizeof blk_size;
|
||||||
AutoFile filein{OpenBlockFile(pos, true)};
|
AutoFile filein{OpenBlockFile(pos, true)};
|
||||||
if (filein.IsNull()) {
|
if (filein.IsNull()) {
|
||||||
LogError("%s: OpenBlockFile failed for %s\n", __func__, pos.ToString());
|
LogError("%s: OpenBlockFile failed for %s\n", __func__, pos.ToString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read block
|
|
||||||
try {
|
try {
|
||||||
filein >> TX_WITH_WITNESS(block);
|
filein >> blk_size;
|
||||||
|
if (blk_size > MAX_SIZE) throw std::runtime_error{strprintf("Refusing to read block of size: %d", blk_size)};
|
||||||
|
|
||||||
|
std::vector<uint8_t> mem(blk_size);
|
||||||
|
filein >> Span{mem};
|
||||||
|
SpanReader(mem) >> TX_WITH_WITNESS(block);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LogError("%s: Deserialize or I/O error - %s at %s\n", __func__, e.what(), pos.ToString());
|
LogError("%s: Deserialize or I/O error - %s at %s\n", __func__, e.what(), pos.ToString());
|
||||||
return false;
|
return false;
|
||||||
|
@ -1119,22 +1109,38 @@ bool BlockManager::ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatF
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
FlatFilePos BlockManager::SaveBlockToDisk(const CBlock& block, int nHeight)
|
FlatFilePos BlockManager::SaveBlock(const CBlock& block, int nHeight)
|
||||||
{
|
{
|
||||||
unsigned int nBlockSize = ::GetSerializeSize(TX_WITH_WITNESS(block));
|
const uint32_t block_size{static_cast<uint32_t>(GetSerializeSize(TX_WITH_WITNESS(block)))};
|
||||||
// Account for the 4 magic message start bytes + the 4 length bytes (8 bytes total,
|
FlatFilePos pos{FindNextBlockPos(BLOCK_SERIALIZATION_HEADER_SIZE + block_size, nHeight, block.GetBlockTime())};
|
||||||
// defined as BLOCK_SERIALIZATION_HEADER_SIZE)
|
if (pos.IsNull()) {
|
||||||
nBlockSize += static_cast<unsigned int>(BLOCK_SERIALIZATION_HEADER_SIZE);
|
|
||||||
FlatFilePos blockPos{FindNextBlockPos(nBlockSize, nHeight, block.GetBlockTime())};
|
|
||||||
if (blockPos.IsNull()) {
|
|
||||||
LogError("%s: FindNextBlockPos failed\n", __func__);
|
LogError("%s: FindNextBlockPos failed\n", __func__);
|
||||||
return FlatFilePos();
|
return FlatFilePos();
|
||||||
}
|
}
|
||||||
if (!WriteBlockToDisk(block, blockPos)) {
|
AutoFile fileout{m_block_file_seq.Open(pos, false), {}}; // We'll obfuscate ourselves
|
||||||
|
if (fileout.IsNull()) {
|
||||||
|
LogError("%s: OpenBlockFile failed\n", __func__);
|
||||||
m_opts.notifications.fatalError(_("Failed to write block."));
|
m_opts.notifications.fatalError(_("Failed to write block."));
|
||||||
return FlatFilePos();
|
return FlatFilePos();
|
||||||
}
|
}
|
||||||
return blockPos;
|
|
||||||
|
{
|
||||||
|
DataStream header;
|
||||||
|
header.reserve(BLOCK_SERIALIZATION_HEADER_SIZE);
|
||||||
|
header << GetParams().MessageStart() << block_size;
|
||||||
|
util::Xor(header, m_xor_key, pos.nPos);
|
||||||
|
fileout.write(header);
|
||||||
|
}
|
||||||
|
pos.nPos += BLOCK_SERIALIZATION_HEADER_SIZE;
|
||||||
|
{
|
||||||
|
DataStream block_data;
|
||||||
|
block_data.reserve(block_size);
|
||||||
|
block_data << TX_WITH_WITNESS(block);
|
||||||
|
util::Xor(block_data, m_xor_key, pos.nPos);
|
||||||
|
fileout.write(block_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
|
static auto InitBlocksdirXorKey(const BlockManager::Options& opts)
|
||||||
|
|
|
@ -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 SaveBlock before a serialized CBlock (8 bytes) */
|
||||||
static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = std::tuple_size_v<MessageStartChars> + sizeof(unsigned int);
|
static constexpr uint32_t BLOCK_SERIALIZATION_HEADER_SIZE = std::tuple_size_v<MessageStartChars> + sizeof(uint32_t);
|
||||||
|
|
||||||
|
/** Total overhead when writing undo data: header (8 bytes) plus checksum (32 bytes) */
|
||||||
|
static constexpr uint32_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 SaveBlockUndo(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 SaveBlock(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,7 +414,7 @@ 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 ReadBlockFromDisk(CBlock& block, FlatFilePos pos) const;
|
||||||
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const;
|
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex& index) const;
|
||||||
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const;
|
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos) const;
|
||||||
|
|
||||||
|
|
|
@ -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.SaveBlock(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.SaveBlock(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.SaveBlock(block1, /*nHeight=*/1)};
|
||||||
|
|
||||||
// Write second block
|
// Write second block
|
||||||
FlatFilePos pos2{blockman.SaveBlockToDisk(block2, /*nHeight=*/2)};
|
FlatFilePos pos2{blockman.SaveBlock(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);
|
||||||
|
|
|
@ -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.SaveBlockUndo(blockundo, state, *pindex)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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.SaveBlock(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;
|
||||||
|
@ -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.SaveBlock(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;
|
||||||
|
|
Loading…
Add table
Reference in a new issue