Skip to content

Commit 029ba1a

Browse files
committed
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.
1 parent 91b7ab6 commit 029ba1a

File tree

6 files changed

+55
-43
lines changed

6 files changed

+55
-43
lines changed

src/index/base.cpp

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,44 @@ static const CBlockIndex* NextSyncBlock(const CBlockIndex* pindex_prev, CChain&
144144
return pindex;
145145
}
146146

147+
// Since block is not in the chain, return the next block in the chain AFTER the last common ancestor.
148+
// Caller will be responsible for rewinding back to the common ancestor.
147149
return chain.Next(chain.FindFork(pindex_prev));
148150
}
149151

152+
bool BaseIndex::ProcessBlock(const CBlockIndex* pindex, const CBlock* block_data)
153+
{
154+
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block_data);
155+
156+
CBlock block;
157+
if (!block_data) { // disk lookup if block data wasn't provided
158+
if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
159+
FatalErrorf("%s: Failed to read block %s from disk",
160+
__func__, pindex->GetBlockHash().ToString());
161+
return false;
162+
}
163+
block_info.data = █
164+
}
165+
166+
CBlockUndo block_undo;
167+
if (CustomOptions().connect_undo_data) {
168+
if (pindex->nHeight > 0 && !m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
169+
FatalErrorf("%s: Failed to read undo block data %s from disk",
170+
__func__, pindex->GetBlockHash().ToString());
171+
return false;
172+
}
173+
block_info.undo_data = &block_undo;
174+
}
175+
176+
if (!CustomAppend(block_info)) {
177+
FatalErrorf("%s: Failed to write block %s to index database",
178+
__func__, pindex->GetBlockHash().ToString());
179+
return false;
180+
}
181+
182+
return true;
183+
}
184+
150185
void BaseIndex::Sync()
151186
{
152187
const CBlockIndex* pindex = m_best_block_index.load();
@@ -192,20 +227,7 @@ void BaseIndex::Sync()
192227
pindex = pindex_next;
193228

194229

195-
CBlock block;
196-
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
197-
if (!m_chainstate->m_blockman.ReadBlock(block, *pindex)) {
198-
FatalErrorf("%s: Failed to read block %s from disk",
199-
__func__, pindex->GetBlockHash().ToString());
200-
return;
201-
} else {
202-
block_info.data = █
203-
}
204-
if (!CustomAppend(block_info)) {
205-
FatalErrorf("%s: Failed to write block %s to index database",
206-
__func__, pindex->GetBlockHash().ToString());
207-
return;
208-
}
230+
if (!ProcessBlock(pindex)) return; // error logged internally
209231

210232
auto current_time{std::chrono::steady_clock::now()};
211233
if (last_log_time + SYNC_LOG_INTERVAL < current_time) {
@@ -337,17 +359,14 @@ void BaseIndex::BlockConnected(ChainstateRole role, const std::shared_ptr<const
337359
return;
338360
}
339361
}
340-
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
341-
if (CustomAppend(block_info)) {
362+
363+
// Dispatch block to child class; errors are logged internally and abort the node.
364+
if (ProcessBlock(pindex, block.get())) {
342365
// Setting the best block index is intentionally the last step of this
343366
// function, so BlockUntilSyncedToCurrentChain callers waiting for the
344367
// best block index to be updated can rely on the block being fully
345368
// processed, and the index object being safe to delete.
346369
SetBestBlockIndex(pindex);
347-
} else {
348-
FatalErrorf("%s: Failed to write block %s to index",
349-
__func__, pindex->GetBlockHash().ToString());
350-
return;
351370
}
352371
}
353372

src/index/base.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ class BaseIndex : public CValidationInterface
9393
/// Loop over disconnected blocks and call CustomRemove.
9494
bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
9595

96+
bool ProcessBlock(const CBlockIndex* pindex, const CBlock* block_data = nullptr);
97+
9698
virtual bool AllowPrune() const = 0;
9799

98100
template <typename... Args>

src/index/blockfilterindex.cpp

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
#include <node/blockstorage.h>
1414
#include <undo.h>
1515
#include <util/fs_helpers.h>
16-
#include <validation.h>
1716

1817
/* The index database stores three items for each block: the disk location of the encoded filter,
1918
* 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
112111
m_filter_fileseq = std::make_unique<FlatFileSeq>(std::move(path), "fltr", FLTR_FILE_CHUNK_SIZE);
113112
}
114113

114+
interfaces::Chain::NotifyOptions BlockFilterIndex::CustomOptions()
115+
{
116+
interfaces::Chain::NotifyOptions options;
117+
options.connect_undo_data = true;
118+
return options;
119+
}
120+
115121
bool BlockFilterIndex::CustomInit(const std::optional<interfaces::BlockRef>& block)
116122
{
117123
if (!m_db->Read(DB_FILTER_POS, m_next_filter_pos)) {
@@ -250,19 +256,7 @@ std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint
250256

251257
bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
252258
{
253-
CBlockUndo block_undo;
254-
255-
if (block.height > 0) {
256-
// pindex variable gives indexing code access to node internals. It
257-
// will be removed in upcoming commit
258-
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
259-
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
260-
return false;
261-
}
262-
}
263-
264-
BlockFilter filter(m_filter_type, *Assert(block.data), block_undo);
265-
259+
BlockFilter filter(m_filter_type, *Assert(block.data), *Assert(block.undo_data));
266260
const uint256& header = filter.ComputeHeader(m_last_header);
267261
bool res = Write(filter, block.height, header);
268262
if (res) m_last_header = header; // update last header

src/index/blockfilterindex.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ class BlockFilterIndex final : public BaseIndex
5252
std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash);
5353

5454
protected:
55+
interfaces::Chain::NotifyOptions CustomOptions() override;
56+
5557
bool CustomInit(const std::optional<interfaces::BlockRef>& block) override;
5658

5759
bool CustomCommit(CDBBatch& batch) override;

src/index/coinstatsindex.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -114,19 +114,11 @@ CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t
114114

115115
bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
116116
{
117-
CBlockUndo block_undo;
118117
const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
119118
m_total_subsidy += block_subsidy;
120119

121120
// Ignore genesis block
122121
if (block.height > 0) {
123-
// pindex variable gives indexing code access to node internals. It
124-
// will be removed in upcoming commit
125-
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
126-
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
127-
return false;
128-
}
129-
130122
std::pair<uint256, DBVal> read_out;
131123
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
132124
return false;
@@ -183,7 +175,7 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
183175

184176
// The coinbase tx has no undo data since no former output is spent
185177
if (!tx->IsCoinBase()) {
186-
const auto& tx_undo{block_undo.vtxundo.at(i - 1)};
178+
const auto& tx_undo{Assert(block.undo_data)->vtxundo.at(i - 1)};
187179

188180
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
189181
Coin coin{tx_undo.vprevout[j]};
@@ -383,6 +375,7 @@ bool CoinStatsIndex::CustomCommit(CDBBatch& batch)
383375
interfaces::Chain::NotifyOptions CoinStatsIndex::CustomOptions()
384376
{
385377
interfaces::Chain::NotifyOptions options;
378+
options.connect_undo_data = true;
386379
options.disconnect_data = true;
387380
options.disconnect_undo_data = true;
388381
return options;

src/interfaces/chain.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,8 @@ class Chain
330330
//! Options specifying which chain notifications are required.
331331
struct NotifyOptions
332332
{
333+
//! Include undo data with block connected notifications.
334+
bool connect_undo_data = false;
333335
//! Include block data with block disconnected notifications.
334336
bool disconnect_data = false;
335337
//! Include undo data with block disconnected notifications.

0 commit comments

Comments
 (0)