Skip to content

Commit b0ad438

Browse files
knstfanquake
andcommitted
Merge bitcoin#25494: indexes: Stop using node internal types
7878f97 indexes, refactor: Remove CChainState use in index CommitInternal method (Ryan Ofsky) ee3a079 indexes, refactor: Remove CBlockIndex* uses in index Rewind methods (Ryan Ofsky) dc971be indexes, refactor: Remove CBlockIndex* uses in index WriteBlock methods (Ryan Ofsky) bef4e40 indexes, refactor: Remove CBlockIndex* uses in index Init methods (Ryan Ofsky) addb4f2 indexes, refactor: Remove CBlockIndex* uses in coinstatsindex LookUpOne function (Ryan Ofsky) 33b4d48 indexes, refactor: Pass Chain interface instead of CChainState class to indexes (Ryan Ofsky) a0b5b4a interfaces, refactor: Add more block information to block connected notifications (Ryan Ofsky) Pull request description: Start transitioning index code away from using internal node types like `CBlockIndex` and `CChain` so index code is less coupled to node code and index code will later be able to stop locking cs_main and sync without having to deal with validationinterface race conditions, and so new indexes are easier to write and can run as plugins or separate processes. This PR contains the first 7 commits from bitcoin#24230 (comment) which have been split off for easier review. Previous review comments can be found in bitcoin#24230 ACKs for top commit: MarcoFalke: ACK 7878f97 though did not review the last commit 🤼 mzumsande: Code Review ACK 7878f97 Tree-SHA512: f84ac2eb6dca2c305566ddeb35ea14d0b71c00860c0fd752bbcf1a0188be833d8c2a6ac9d3ef6ab5b46fbd02d7a24cbb8f60cf12464cb8ba208e22287f709989 Co-authored-by: fanquake <fanquake@gmail.com>
1 parent 9d3b80e commit b0ad438

29 files changed

Lines changed: 350 additions & 205 deletions

src/Makefile.am

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ BITCOIN_CORE_H = \
279279
interfaces/node.h \
280280
interfaces/wallet.h \
281281
kernel/blockmanager_opts.h \
282+
kernel/chain.h \
282283
kernel/chainstatemanager_opts.h \
283284
kernel/checks.h \
284285
kernel/coinstats.h \
@@ -562,6 +563,7 @@ libbitcoin_node_a_SOURCES = \
562563
instantsend/lock.cpp \
563564
instantsend/net_instantsend.cpp \
564565
instantsend/signing.cpp \
566+
kernel/chain.cpp \
565567
kernel/checks.cpp \
566568
kernel/coinstats.cpp \
567569
kernel/context.cpp \
@@ -1285,6 +1287,7 @@ libdashkernel_la_SOURCES = \
12851287
init/common.cpp \
12861288
instantsend/db.cpp \
12871289
instantsend/instantsend.cpp \
1290+
kernel/chain.cpp \
12881291
kernel/checks.cpp \
12891292
kernel/coinstats.cpp \
12901293
kernel/context.cpp \

src/core_write.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
#include <util/strencodings.h>
2020
#include <util/system.h>
2121

22-
#include <index/spentindex.h>
22+
#include <index/spentindex_types.h>
2323

2424
#include <evo/assetlocktx.h>
2525
#include <evo/cbtx.h>

src/index/addressindex.cpp

Lines changed: 25 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <tinyformat.h>
1414
#include <undo.h>
1515
#include <util/system.h>
16+
#include <validation.h>
1617

1718
constexpr uint8_t DB_ADDRESSINDEX{'a'};
1819
constexpr uint8_t DB_ADDRESSUNSPENTINDEX{'u'};
@@ -159,39 +160,44 @@ bool AddressIndex::DB::RewindBatch(const std::vector<CAddressIndexEntry>& addres
159160
return CDBWrapper::WriteBatch(batch);
160161
}
161162

162-
AddressIndex::AddressIndex(size_t n_cache_size, bool f_memory, bool f_wipe) :
163+
AddressIndex::AddressIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe) :
164+
BaseIndex(std::move(chain)),
163165
m_db(std::make_unique<AddressIndex::DB>(n_cache_size, f_memory, f_wipe))
164166
{
165167
}
166168

167169
AddressIndex::~AddressIndex() = default;
168170

169-
bool AddressIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
171+
bool AddressIndex::CustomAppend(const interfaces::BlockInfo& block)
170172
{
171173
// Skip genesis block (no inputs to index)
172-
if (pindex->nHeight == 0) {
174+
if (block.height == 0) {
173175
return true;
174176
}
175177

178+
// pindex variable gives indexing code access to node internals. It
179+
// will be removed in upcoming commit
180+
const CBlockIndex* pindex = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(block.hash));
181+
176182
// Read undo data for this block to get information about spent outputs
177183
CBlockUndo blockundo;
178184
if (!node::UndoReadFromDisk(blockundo, pindex)) {
179185
return error("%s: Failed to read undo data for block %s at height %d", __func__,
180-
pindex->GetBlockHash().ToString(), pindex->nHeight);
186+
block.hash.ToString(), block.height);
181187
}
182188

183189
std::vector<CAddressIndexEntry> addressIndex;
184190
std::vector<CAddressUnspentIndexEntry> addressUnspentIndex;
185191

186192
// Process each non-coinbase transaction
187193
// blockundo.vtxundo[i] corresponds to block.vtx[i+1] (coinbase is skipped in undo data)
188-
if (blockundo.vtxundo.size() != block.vtx.size() - 1) {
194+
if (blockundo.vtxundo.size() != block.data->vtx.size() - 1) {
189195
return error("%s: Undo data size mismatch for block %s (expected %zu, got %zu)", __func__,
190-
pindex->GetBlockHash().ToString(), block.vtx.size() - 1, blockundo.vtxundo.size());
196+
block.hash.ToString(), block.data->vtx.size() - 1, blockundo.vtxundo.size());
191197
}
192198

193199
for (size_t i = 0; i < blockundo.vtxundo.size(); i++) {
194-
const CTransactionRef& tx = block.vtx[i + 1]; // +1 to skip coinbase
200+
const CTransactionRef& tx = block.data->vtx[i + 1]; // +1 to skip coinbase
195201
const CTxUndo& txundo = blockundo.vtxundo[i];
196202
const uint256 txhash = tx->GetHash();
197203

@@ -213,7 +219,7 @@ bool AddressIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
213219
}
214220

215221
// Record spending activity
216-
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i + 1, txhash, j, true),
222+
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, block.height, i + 1, txhash, j, true),
217223
prevout.nValue * -1);
218224

219225
// Remove from unspent index
@@ -234,17 +240,17 @@ bool AddressIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
234240
}
235241

236242
// Record receiving activity
237-
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, i + 1, txhash, k, false),
243+
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, block.height, i + 1, txhash, k, false),
238244
out.nValue);
239245

240246
// Add to unspent index
241247
addressUnspentIndex.emplace_back(CAddressUnspentKey(address_type, address_bytes, txhash, k),
242-
CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight));
248+
CAddressUnspentValue(out.nValue, out.scriptPubKey, block.height));
243249
}
244250
}
245251

246252
// Also process coinbase outputs (receiving activity only)
247-
const CTransactionRef& coinbase = block.vtx[0];
253+
const CTransactionRef& coinbase = block.data->vtx[0];
248254
const uint256 coinbase_hash = coinbase->GetHash();
249255
for (size_t k = 0; k < coinbase->vout.size(); k++) {
250256
const CTxOut& out = coinbase->vout[k];
@@ -256,24 +262,26 @@ bool AddressIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
256262
}
257263

258264
// Record receiving activity for coinbase
259-
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, pindex->nHeight, 0, coinbase_hash, k, false),
265+
addressIndex.emplace_back(CAddressIndexKey(address_type, address_bytes, block.height, 0, coinbase_hash, k, false),
260266
out.nValue);
261267

262268
// Add coinbase outputs to unspent index
263269
addressUnspentIndex.emplace_back(CAddressUnspentKey(address_type, address_bytes, coinbase_hash, k),
264-
CAddressUnspentValue(out.nValue, out.scriptPubKey, pindex->nHeight));
270+
CAddressUnspentValue(out.nValue, out.scriptPubKey, block.height));
265271
}
266272

267273
return m_db->WriteBatch(addressIndex, addressUnspentIndex);
268274
}
269275

270-
bool AddressIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip)
276+
bool AddressIndex::CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip)
271277
{
272-
assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
278+
const CBlockIndex* current_tip_index = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(current_tip.hash));
279+
const CBlockIndex* new_tip_index = WITH_LOCK(cs_main, return m_chainstate->m_blockman.LookupBlockIndex(new_tip.hash));
280+
assert(current_tip_index->GetAncestor(new_tip_index->nHeight) == new_tip_index);
273281

274282
// Rewind the unspent index by processing blocks in reverse
275283
// We need to undo all operations from current_tip back to (but not including) new_tip
276-
for (const CBlockIndex* pindex = current_tip; pindex != new_tip; pindex = pindex->pprev) {
284+
for (const CBlockIndex* pindex = current_tip_index; pindex != new_tip_index; pindex = pindex->pprev) {
277285
CBlock block;
278286
if (!node::ReadBlockFromDisk(block, pindex, Params().GetConsensus())) {
279287
return error("%s: Failed to read block %s from disk during rewind", __func__,
@@ -387,8 +395,7 @@ bool AddressIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new
387395
}
388396
}
389397

390-
// Call base class Rewind to update the best block pointer
391-
return BaseIndex::Rewind(current_tip, new_tip);
398+
return true;
392399
}
393400

394401
BaseIndex::DB& AddressIndex::GetDB() const { return *m_db; }

src/index/addressindex.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,18 +62,18 @@ class AddressIndex final : public BaseIndex
6262
bool AllowPrune() const override { return false; }
6363

6464
/// Write block data to the index databases
65-
bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) override;
65+
bool CustomAppend(const interfaces::BlockInfo& block) override;
6666

6767
/// Custom rewind to handle both transaction history and unspent index
68-
bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip) override;
68+
bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override;
6969

7070
BaseIndex::DB& GetDB() const override;
7171

7272
const char* GetName() const override { return "addressindex"; }
7373

7474
public:
7575
/// Constructs the index, which becomes available to be queried
76-
explicit AddressIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
76+
explicit AddressIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
7777

7878
/// Destructor
7979
virtual ~AddressIndex() override;

src/index/base.cpp

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@
44

55
#include <chainparams.h>
66
#include <index/base.h>
7+
#include <interfaces/chain.h>
8+
#include <kernel/chain.h>
79
#include <node/blockstorage.h>
10+
#include <node/context.h>
811
#include <node/interface_ui.h>
912
#include <shutdown.h>
1013
#include <tinyformat.h>
@@ -31,6 +34,15 @@ void BaseIndex::FatalErrorImpl(const std::string& message)
3134
StartShutdown();
3235
}
3336

37+
CBlockLocator GetLocator(interfaces::Chain& chain, const uint256& block_hash)
38+
{
39+
CBlockLocator locator;
40+
bool found = chain.findBlock(block_hash, interfaces::FoundBlock().locator(locator));
41+
assert(found);
42+
assert(!locator.IsNull());
43+
return locator;
44+
}
45+
3446
BaseIndex::DB::DB(const fs::path& path, size_t n_cache_size, bool f_memory, bool f_wipe, bool f_obfuscate) :
3547
CDBWrapper(path, n_cache_size, f_memory, f_wipe, f_obfuscate)
3648
{}
@@ -49,6 +61,9 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator
4961
batch.Write(DB_BEST_BLOCK, locator);
5062
}
5163

64+
BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain)
65+
: m_chain{std::move(chain)} {}
66+
5267
BaseIndex::~BaseIndex()
5368
{
5469
Interrupt();
@@ -164,12 +179,15 @@ void BaseIndex::ThreadSync()
164179
}
165180

166181
CBlock block;
182+
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex);
167183
if (!ReadBlockFromDisk(block, pindex, consensus_params)) {
168184
FatalError("%s: Failed to read block %s from disk",
169185
__func__, pindex->GetBlockHash().ToString());
170186
return;
187+
} else {
188+
block_info.data = &block;
171189
}
172-
if (!WriteBlock(block, pindex)) {
190+
if (!CustomAppend(block_info)) {
173191
FatalError("%s: Failed to write block %s to index database",
174192
__func__, pindex->GetBlockHash().ToString());
175193
return;
@@ -200,22 +218,20 @@ void BaseIndex::ThreadSync()
200218

201219
bool BaseIndex::Commit()
202220
{
203-
CDBBatch batch(GetDB());
204-
if (!CommitInternal(batch) || !GetDB().WriteBatch(batch)) {
205-
return error("%s: Failed to commit latest %s state", __func__, GetName());
206-
}
207-
return true;
208-
}
209-
210-
bool BaseIndex::CommitInternal(CDBBatch& batch)
211-
{
212-
LOCK(cs_main);
213221
// Don't commit anything if we haven't indexed any block yet
214222
// (this could happen if init is interrupted).
215-
if (m_best_block_index == nullptr) {
216-
return false;
223+
bool ok = m_best_block_index != nullptr;
224+
if (ok) {
225+
CDBBatch batch(GetDB());
226+
ok = CustomCommit(batch);
227+
if (ok) {
228+
GetDB().WriteBestBlock(batch, GetLocator(*m_chain, m_best_block_index.load()->GetBlockHash()));
229+
ok = GetDB().WriteBatch(batch);
230+
}
231+
}
232+
if (!ok) {
233+
return error("%s: Failed to commit latest %s state", __func__, GetName());
217234
}
218-
GetDB().WriteBestBlock(batch, m_chainstate->m_chain.GetLocator(m_best_block_index));
219235
return true;
220236
}
221237

@@ -224,6 +240,10 @@ bool BaseIndex::Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_ti
224240
assert(current_tip == m_best_block_index);
225241
assert(current_tip->GetAncestor(new_tip->nHeight) == new_tip);
226242

243+
if (!CustomRewind({current_tip->GetBlockHash(), current_tip->nHeight}, {new_tip->GetBlockHash(), new_tip->nHeight})) {
244+
return false;
245+
}
246+
227247
// In the case of a reorg, ensure persisted block locator is not stale.
228248
// Pruning has a minimum of 288 blocks-to-keep and getting the index
229249
// out of sync may be possible but a users fault.
@@ -271,8 +291,8 @@ void BaseIndex::BlockConnected(const std::shared_ptr<const CBlock>& block, const
271291
return;
272292
}
273293
}
274-
275-
if (WriteBlock(*block, pindex)) {
294+
interfaces::BlockInfo block_info = kernel::MakeBlockInfo(pindex, block.get());
295+
if (CustomAppend(block_info)) {
276296
// Setting the best block index is intentionally the last step of this
277297
// function, so BlockUntilSyncedToCurrentChain callers waiting for the
278298
// best block index to be updated can rely on the block being fully
@@ -377,13 +397,18 @@ void BaseIndex::Interrupt()
377397
m_interrupt();
378398
}
379399

380-
bool BaseIndex::Start(Chainstate& active_chainstate)
400+
bool BaseIndex::Start()
381401
{
382-
m_chainstate = &active_chainstate;
402+
// m_chainstate member gives indexing code access to node internals. It is
403+
// removed in followup https://github.com/bitcoin/bitcoin/pull/24230
404+
m_chainstate = &m_chain->context()->chainman->ActiveChainstate();
383405
// Need to register this ValidationInterface before running Init(), so that
384406
// callbacks are not missed if Init sets m_synced to true.
385407
RegisterValidationInterface(this);
386-
if (!Init()) {
408+
if (!Init()) return false;
409+
410+
const CBlockIndex* index = m_best_block_index.load();
411+
if (!CustomInit(index ? std::make_optional(interfaces::BlockKey{index->GetBlockHash(), index->nHeight}) : std::nullopt)) {
387412
return false;
388413
}
389414

0 commit comments

Comments
 (0)