mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-08-04 15:15:37 +02:00
index: remove CBlockIndex access from CustomAppend()
Moved CBlockUndo disk read lookups from child index classes to the base index class. The goal is for child index classes to synchronize only through events, without directly accessing the chain database. This change will enable future parallel synchronization mechanisms, reduce database access (when batched), and contribute toward the goal of running indexes in a separate process (with no chain database access). Besides that, this commit also documents how NextSyncBlock() behaves. It is not immediately clear this function could return the first block after the fork point during a reorg.
This commit is contained in:
@@ -144,9 +144,44 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
|
|||||||
return pindex;
|
return pindex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Since block is not in the chain, return the next block in the chain AFTER the last common ancestor.
|
||||||
|
// Caller will be responsible for rewinding back to the common ancestor.
|
||||||
return chain.Next(chain.FindFork(pindex_prev));
|
return chain.Next(chain.FindFork(pindex_prev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool BaseIndex::ProcessBlock(const CBlockIndex* pindex, const CBlock* block_data)
|
||||||
|
{
|
||||||
|
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block_data);
|
||||||
|
|
||||||
|
CBlock block;
|
||||||
|
if (!block_data) { // disk lookup if block data wasn't provided
|
||||||
|
if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
|
||||||
|
FatalErrorf("%s: Failed to read block %s from disk",
|
||||||
|
__func__, pindex->GetBlockHash().ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block_info.data = █
|
||||||
|
}
|
||||||
|
|
||||||
|
CBlockUndo block_undo;
|
||||||
|
if (CustomOptions().connect_undo_data) {
|
||||||
|
if (pindex->nHeight > 0 && !m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
|
||||||
|
FatalErrorf("%s: Failed to read undo block data %s from disk",
|
||||||
|
__func__, pindex->GetBlockHash().ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
block_info.undo_data = &block_undo;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!CustomAppend(block_info)) {
|
||||||
|
FatalErrorf("%s: Failed to write block %s to index database",
|
||||||
|
__func__, pindex->GetBlockHash().ToString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void BaseIndex::Sync()
|
void BaseIndex::Sync()
|
||||||
{
|
{
|
||||||
const CBlockIndex* pindex = m_best_block_index.load();
|
const CBlockIndex* pindex = m_best_block_index.load();
|
||||||
@@ -192,20 +227,7 @@ void BaseIndex::Sync()
|
|||||||
pindex = pindex_next;
|
pindex = pindex_next;
|
||||||
|
|
||||||
|
|
||||||
CBlock block;
|
if (!ProcessBlock(pindex)) return; // error logged internally
|
||||||
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
|
|
||||||
if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
|
|
||||||
FatalErrorf("%s: Failed to read block %s from disk",
|
|
||||||
__func__, pindex->GetBlockHash().ToString());
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
block_info.data = █
|
|
||||||
}
|
|
||||||
if (!CustomAppend(block_info)) {
|
|
||||||
FatalErrorf("%s: Failed to write block %s to index database",
|
|
||||||
__func__, pindex->GetBlockHash().ToString());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto current_time{std::chrono::steady_clock::now()};
|
auto current_time{std::chrono::steady_clock::now()};
|
||||||
if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
|
if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
|
||||||
@@ -337,17 +359,14 @@ void BaseIndex::BlockConnected(ChainstateRole role, const std::shared_ptr<const
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
|
|
||||||
if (CustomAppend(block_info)) {
|
// Dispatch block to child class; errors are logged internally and abort the node.
|
||||||
|
if (ProcessBlock(pindex, block.get())) {
|
||||||
// Setting the best block index is intentionally the last step of this
|
// Setting the best block index is intentionally the last step of this
|
||||||
// function, so BlockUntilSyncedToCurrentChain callers waiting for the
|
// function, so BlockUntilSyncedToCurrentChain callers waiting for the
|
||||||
// best block index to be updated can rely on the block being fully
|
// best block index to be updated can rely on the block being fully
|
||||||
// processed, and the index object being safe to delete.
|
// processed, and the index object being safe to delete.
|
||||||
SetBestBlockIndex(pindex);
|
SetBestBlockIndex(pindex);
|
||||||
} else {
|
|
||||||
FatalErrorf("%s: Failed to write block %s to index",
|
|
||||||
__func__, pindex->GetBlockHash().ToString());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -93,6 +93,8 @@ private:
|
|||||||
/// Loop over disconnected blocks and call CustomRemove.
|
/// Loop over disconnected blocks and call CustomRemove.
|
||||||
bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
|
bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
|
||||||
|
|
||||||
|
bool ProcessBlock(const CBlockIndex* pindex, const CBlock* block_data = nullptr);
|
||||||
|
|
||||||
virtual bool AllowPrune() const = 0;
|
virtual bool AllowPrune() const = 0;
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
|
@@ -13,7 +13,6 @@
|
|||||||
#include <node/blockstorage.h>
|
#include <node/blockstorage.h>
|
||||||
#include <undo.h>
|
#include <undo.h>
|
||||||
#include <util/fs_helpers.h>
|
#include <util/fs_helpers.h>
|
||||||
#include <validation.h>
|
|
||||||
|
|
||||||
/* The index database stores three items for each block: the disk location of the encoded filter,
|
/* The index database stores three items for each block: the disk location of the encoded filter,
|
||||||
* its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by
|
* its dSHA256 hash, and the header. Those belonging to blocks on the active chain are indexed by
|
||||||
@@ -112,6 +111,13 @@ BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, Blo
|
|||||||
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
|
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interfaces::Chain::NotifyOptions BlockFilterIndex::CustomOptions()
|
||||||
|
{
|
||||||
|
interfaces::Chain::NotifyOptions options;
|
||||||
|
options.connect_undo_data = true;
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockRef>& block)
|
bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockRef>& block)
|
||||||
{
|
{
|
||||||
if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
|
if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
|
||||||
@@ -250,19 +256,7 @@ std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint
|
|||||||
|
|
||||||
bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
|
bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
|
||||||
{
|
{
|
||||||
CBlockUndo block_undo;
|
BlockFilter filter(m_filter_type, *Assert(block.data), *Assert(block.undo_data));
|
||||||
|
|
||||||
if (block.height > 0) {
|
|
||||||
// pindex variable gives indexing code access to node internals. It
|
|
||||||
// will be removed in upcoming commit
|
|
||||||
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
|
|
||||||
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockFilter filter(m_filter_type, *Assert(block.data), block_undo);
|
|
||||||
|
|
||||||
const uint256& header = filter.ComputeHeader(m_last_header);
|
const uint256& header = filter.ComputeHeader(m_last_header);
|
||||||
bool res = Write(filter, block.height, header);
|
bool res = Write(filter, block.height, header);
|
||||||
if (res) m_last_header = header; // update last header
|
if (res) m_last_header = header; // update last header
|
||||||
|
@@ -52,6 +52,8 @@ private:
|
|||||||
std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash);
|
std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
interfaces::Chain::NotifyOptions CustomOptions() override;
|
||||||
|
|
||||||
bool CustomInit(const std::optional<interfaces::BlockRef>& block) override;
|
bool CustomInit(const std::optional<interfaces::BlockRef>& block) override;
|
||||||
|
|
||||||
bool CustomCommit(CDBBatch& batch) override;
|
bool CustomCommit(CDBBatch& batch) override;
|
||||||
|
@@ -114,19 +114,11 @@ CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t
|
|||||||
|
|
||||||
bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
|
bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
|
||||||
{
|
{
|
||||||
CBlockUndo block_undo;
|
|
||||||
const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
|
const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
|
||||||
m_total_subsidy += block_subsidy;
|
m_total_subsidy += block_subsidy;
|
||||||
|
|
||||||
// Ignore genesis block
|
// Ignore genesis block
|
||||||
if (block.height > 0) {
|
if (block.height > 0) {
|
||||||
// pindex variable gives indexing code access to node internals. It
|
|
||||||
// will be removed in upcoming commit
|
|
||||||
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
|
|
||||||
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::pair<uint256, DBVal> read_out;
|
std::pair<uint256, DBVal> read_out;
|
||||||
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
|
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
|
||||||
return false;
|
return false;
|
||||||
@@ -183,7 +175,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
|
|||||||
|
|
||||||
// The coinbase tx has no undo data since no former output is spent
|
// The coinbase tx has no undo data since no former output is spent
|
||||||
if (!tx->IsCoinBase()) {
|
if (!tx->IsCoinBase()) {
|
||||||
const auto& tx_undo{block_undo.vtxundo.at(i - 1)};
|
const auto& tx_undo{Assert(block.undo_data)->vtxundo.at(i - 1)};
|
||||||
|
|
||||||
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
|
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
|
||||||
Coin coin{tx_undo.vprevout[j]};
|
Coin coin{tx_undo.vprevout[j]};
|
||||||
@@ -383,6 +375,7 @@ bool CoinStatsIndex::CustomCommit(CDBBatch& batch)
|
|||||||
interfaces::Chain::NotifyOptions CoinStatsIndex::CustomOptions()
|
interfaces::Chain::NotifyOptions CoinStatsIndex::CustomOptions()
|
||||||
{
|
{
|
||||||
interfaces::Chain::NotifyOptions options;
|
interfaces::Chain::NotifyOptions options;
|
||||||
|
options.connect_undo_data = true;
|
||||||
options.disconnect_data = true;
|
options.disconnect_data = true;
|
||||||
options.disconnect_undo_data = true;
|
options.disconnect_undo_data = true;
|
||||||
return options;
|
return options;
|
||||||
|
@@ -330,6 +330,8 @@ public:
|
|||||||
//! Options specifying which chain notifications are required.
|
//! Options specifying which chain notifications are required.
|
||||||
struct NotifyOptions
|
struct NotifyOptions
|
||||||
{
|
{
|
||||||
|
//! Include undo data with block connected notifications.
|
||||||
|
bool connect_undo_data = false;
|
||||||
//! Include block data with block disconnected notifications.
|
//! Include block data with block disconnected notifications.
|
||||||
bool disconnect_data = false;
|
bool disconnect_data = false;
|
||||||
//! Include undo data with block disconnected notifications.
|
//! Include undo data with block disconnected notifications.
|
||||||
|
Reference in New Issue
Block a user