Skip to content

Commit 6f1392c

Browse files
ryanofskyfurszy
authored andcommitted
indexes, refactor: Remove remaining CBlockIndex* uses in index Rewind methods
Move ReadBlock code from CoinStatsIndex::CustomRewind to BaseIndex::Rewind Move ReadUndo code from CoinStatsIndex::ReverseBlock to BaseIndex::Rewind This commit does change behavior slightly. Since the new CustomRemove methods only take a single block at a time instead of a range of disconnected blocks, when they call CopyHeightIndexToHashIndex they will now do an index seek for each removed block instead of only seeking once to the height of the earliest removed block. Seeking instead of scanning is a little worse for performance if there is a >1 block reorg, but probably not noticeable unless the reorg is very deep.
1 parent 0a24870 commit 6f1392c

File tree

7 files changed

+70
-49
lines changed

7 files changed

+70
-49
lines changed

src/index/base.cpp

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <node/database_args.h>
1515
#include <node/interface_ui.h>
1616
#include <tinyformat.h>
17+
#include <undo.h>
1718
#include <util/string.h>
1819
#include <util/thread.h>
1920
#include <util/translation.h>
@@ -254,8 +255,28 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
254255
assert(current_tip == m_best_block_index);
255256
assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
256257

257-
if (!CustomRewind({current_tip->GetBlockHash(), current_tip->nHeight}, {new_tip->GetBlockHash(), new_tip->nHeight})) {
258-
return false;
258+
CBlock block;
259+
CBlockUndo block_undo;
260+
261+
for (const CBlockIndex* iter_tip = current_tip; iter_tip != new_tip; iter_tip = iter_tip->pprev) {
262+
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(iter_tip);
263+
if (CustomOptions().disconnect_data) {
264+
if (!m_chainstate->m_blockman.ReadBlock(block, *iter_tip)) {
265+
LogError("%s: Failed to read block %s from disk",
266+
__func__, iter_tip->GetBlockHash().ToString());
267+
return false;
268+
}
269+
block_info.data = &block;
270+
}
271+
if (CustomOptions().disconnect_undo_data && iter_tip->nHeight > 0) {
272+
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *iter_tip)) {
273+
return false;
274+
}
275+
block_info.undo_data = &block_undo;
276+
}
277+
if (!CustomRemove(block_info)) {
278+
return false;
279+
}
259280
}
260281

261282
// In the case of a reorg, ensure persisted block locator is not stale.

src/index/base.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ class BaseIndex : public CValidationInterface
9090
/// getting corrupted.
9191
bool Commit();
9292

93-
/// Loop over disconnected blocks and call CustomRewind.
93+
/// Loop over disconnected blocks and call CustomRemove.
9494
bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip);
9595

9696
virtual bool AllowPrune() const = 0;
@@ -107,6 +107,9 @@ class BaseIndex : public CValidationInterface
107107

108108
void ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator) override;
109109

110+
/// Return custom notification options for index.
111+
[[nodiscard]] virtual interfaces::Chain::NotifyOptions CustomOptions() { return {}; }
112+
110113
/// Initialize internal state from the database and block index.
111114
[[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockRef>& block) { return true; }
112115

@@ -117,9 +120,8 @@ class BaseIndex : public CValidationInterface
117120
/// commit more index state.
118121
virtual bool CustomCommit(CDBBatch& batch) { return true; }
119122

120-
/// Rewind index to an earlier chain tip during a chain reorg. The tip must
121-
/// be an ancestor of the current best block.
122-
[[nodiscard]] virtual bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) { return true; }
123+
/// Rewind index by one block during a chain reorg.
124+
[[nodiscard]] virtual bool CustomRemove(const interfaces::BlockInfo& block) { return true; }
123125

124126
virtual DB& GetDB() const = 0;
125127

src/index/blockfilterindex.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -316,15 +316,15 @@ bool BlockFilterIndex::Write(const BlockFilter& filter, uint32_t block_height, c
316316
return true;
317317
}
318318

319-
bool BlockFilterIndex::CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip)
319+
bool BlockFilterIndex::CustomRemove(const interfaces::BlockInfo& block)
320320
{
321321
CDBBatch batch(*m_db);
322322
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
323323

324324
// During a reorg, we need to copy all filters for blocks that are getting disconnected from the
325325
// height index to the hash index so we can still find them when the height index entries are
326326
// overwritten.
327-
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
327+
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, block.height - 1, block.height)) {
328328
return false;
329329
}
330330

@@ -334,8 +334,8 @@ bool BlockFilterIndex::CustomRewind(const interfaces::BlockRef& current_tip, con
334334
batch.Write(DB_FILTER_POS, m_next_filter_pos);
335335
if (!m_db->WriteBatch(batch)) return false;
336336

337-
// Update cached header
338-
m_last_header = *Assert(ReadFilterHeader(new_tip.height, new_tip.hash));
337+
// Update cached header to the previous block hash
338+
m_last_header = *Assert(ReadFilterHeader(block.height - 1, *Assert(block.prev_hash)));
339339
return true;
340340
}
341341

src/index/blockfilterindex.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class BlockFilterIndex final : public BaseIndex
5858

5959
bool CustomAppend(const interfaces::BlockInfo& block) override;
6060

61-
bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) override;
61+
bool CustomRemove(const interfaces::BlockInfo& block) override;
6262

6363
BaseIndex::DB& GetDB() const LIFETIMEBOUND override { return *m_db; }
6464

src/index/coinstatsindex.cpp

Lines changed: 23 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -265,40 +265,22 @@ bool CoinStatsIndex::CustomAppend(const interfaces::BlockInfo& block)
265265
return true;
266266
}
267267

268-
bool CoinStatsIndex::CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip)
268+
bool CoinStatsIndex::CustomRemove(const interfaces::BlockInfo& block)
269269
{
270270
CDBBatch batch(*m_db);
271271
std::unique_ptr<CDBIterator> db_it(m_db->NewIterator());
272272

273273
// During a reorg, we need to copy all hash digests for blocks that are
274274
// getting disconnected from the height index to the hash index so we can
275275
// still find them when the height index entries are overwritten.
276-
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, new_tip.height, current_tip.height)) {
276+
if (!CopyHeightIndexToHashIndex(*db_it, batch, m_name, block.height - 1, block.height)) {
277277
return false;
278278
}
279279

280280
if (!m_db->WriteBatch(batch)) return false;
281281

282-
{
283-
LOCK(cs_main);
284-
const CBlockIndex* iter_tip{m_chainstate->m_blockman.LookupBlockIndex(current_tip.hash)};
285-
const CBlockIndex* new_tip_index{m_chainstate->m_blockman.LookupBlockIndex(new_tip.hash)};
286-
287-
do {
288-
CBlock block;
289-
290-
if (!m_chainstate->m_blockman.ReadBlock(block, *iter_tip)) {
291-
LogError("%s: Failed to read block %s from disk\n",
292-
__func__, iter_tip->GetBlockHash().ToString());
293-
return false;
294-
}
295-
296-
if (!ReverseBlock(block, iter_tip)) {
297-
return false; // failure cause logged internally
298-
}
299-
300-
iter_tip = iter_tip->GetAncestor(iter_tip->nHeight - 1);
301-
} while (new_tip_index != iter_tip);
282+
if (!ReverseBlock(block)) {
283+
return false; // failure cause logged internally
302284
}
303285

304286
return true;
@@ -404,26 +386,29 @@ bool CoinStatsIndex::CustomCommit(CDBBatch& batch)
404386
return true;
405387
}
406388

389+
interfaces::Chain::NotifyOptions CoinStatsIndex::CustomOptions()
390+
{
391+
interfaces::Chain::NotifyOptions options;
392+
options.disconnect_data = true;
393+
options.disconnect_undo_data = true;
394+
return options;
395+
}
396+
407397
// Reverse a single block as part of a reorg
408-
bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex)
398+
bool CoinStatsIndex::ReverseBlock(const interfaces::BlockInfo& block)
409399
{
410-
CBlockUndo block_undo;
411400
std::pair<uint256, DBVal> read_out;
412401

413-
const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
402+
const CAmount block_subsidy{GetBlockSubsidy(block.height, Params().GetConsensus())};
414403
m_total_subsidy -= block_subsidy;
415404

416405
// Ignore genesis block
417-
if (pindex->nHeight > 0) {
418-
if (!m_chainstate->m_blockman.ReadBlockUndo(block_undo, *pindex)) {
419-
return false;
420-
}
421-
422-
if (!m_db->Read(DBHeightKey(pindex->nHeight - 1), read_out)) {
406+
if (block.height > 0) {
407+
if (!m_db->Read(DBHeightKey(block.height - 1), read_out)) {
423408
return false;
424409
}
425410

426-
uint256 expected_block_hash{pindex->pprev->GetBlockHash()};
411+
uint256 expected_block_hash{*block.prev_hash};
427412
if (read_out.first != expected_block_hash) {
428413
LogPrintf("WARNING: previous block header belongs to unexpected block %s; expected %s\n",
429414
read_out.first.ToString(), expected_block_hash.ToString());
@@ -437,13 +422,15 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
437422
}
438423

439424
// Remove the new UTXOs that were created from the block
440-
for (size_t i = 0; i < block.vtx.size(); ++i) {
441-
const auto& tx{block.vtx.at(i)};
425+
assert(block.data);
426+
assert(block.undo_data);
427+
for (size_t i = 0; i < block.data->vtx.size(); ++i) {
428+
const auto& tx{block.data->vtx.at(i)};
442429

443430
for (uint32_t j = 0; j < tx->vout.size(); ++j) {
444431
const CTxOut& out{tx->vout[j]};
445432
COutPoint outpoint{tx->GetHash(), j};
446-
Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
433+
Coin coin{out, block.height, tx->IsCoinBase()};
447434

448435
// Skip unspendable coins
449436
if (coin.out.scriptPubKey.IsUnspendable()) {
@@ -467,7 +454,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
467454

468455
// The coinbase tx has no undo data since no former output is spent
469456
if (!tx->IsCoinBase()) {
470-
const auto& tx_undo{block_undo.vtxundo.at(i - 1)};
457+
const auto& tx_undo{block.undo_data->vtxundo.at(i - 1)};
471458

472459
for (size_t j = 0; j < tx_undo.vprevout.size(); ++j) {
473460
Coin coin{tx_undo.vprevout[j]};

src/index/coinstatsindex.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,18 +38,20 @@ class CoinStatsIndex final : public BaseIndex
3838
CAmount m_total_unspendables_scripts{0};
3939
CAmount m_total_unspendables_unclaimed_rewards{0};
4040

41-
[[nodiscard]] bool ReverseBlock(const CBlock& block, const CBlockIndex* pindex);
41+
[[nodiscard]] bool ReverseBlock(const interfaces::BlockInfo& block);
4242

4343
bool AllowPrune() const override { return true; }
4444

4545
protected:
46+
interfaces::Chain::NotifyOptions CustomOptions() override;
47+
4648
bool CustomInit(const std::optional<interfaces::BlockRef>& block) override;
4749

4850
bool CustomCommit(CDBBatch& batch) override;
4951

5052
bool CustomAppend(const interfaces::BlockInfo& block) override;
5153

52-
bool CustomRewind(const interfaces::BlockRef& current_tip, const interfaces::BlockRef& new_tip) override;
54+
bool CustomRemove(const interfaces::BlockInfo& block) override;
5355

5456
BaseIndex::DB& GetDB() const override { return *m_db; }
5557

src/interfaces/chain.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,15 @@ class Chain
327327
virtual void chainStateFlushed(ChainstateRole role, const CBlockLocator& locator) {}
328328
};
329329

330+
//! Options specifying which chain notifications are required.
331+
struct NotifyOptions
332+
{
333+
//! Include block data with block disconnected notifications.
334+
bool disconnect_data = false;
335+
//! Include undo data with block disconnected notifications.
336+
bool disconnect_undo_data = false;
337+
};
338+
330339
//! Register handler for notifications.
331340
virtual std::unique_ptr<Handler> handleNotifications(std::shared_ptr<Notifications> notifications) = 0;
332341

0 commit comments

Comments
 (0)