indexes, refactor: Pass Chain interface instead of CChainState class to indexes

Passing abstract Chain interface will let indexes run in separate
processes.

This commit does not change behavior in any way.
This commit is contained in:
Ryan Ofsky
2022-01-13 07:57:54 -05:00
parent a0b5b4ae5a
commit 33b4d48cfc
15 changed files with 58 additions and 33 deletions

View File

@@ -4,7 +4,9 @@
#include <chainparams.h> #include <chainparams.h>
#include <index/base.h> #include <index/base.h>
#include <interfaces/chain.h>
#include <node/blockstorage.h> #include <node/blockstorage.h>
#include <node/context.h>
#include <node/interface_ui.h> #include <node/interface_ui.h>
#include <shutdown.h> #include <shutdown.h>
#include <tinyformat.h> #include <tinyformat.h>
@@ -49,6 +51,9 @@ void BaseIndex::DB::WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator
batch.Write(DB_BEST_BLOCK, locator); batch.Write(DB_BEST_BLOCK, locator);
} }
BaseIndex::BaseIndex(std::unique_ptr<interfaces::Chain> chain)
: m_chain{std::move(chain)} {}
BaseIndex::~BaseIndex() BaseIndex::~BaseIndex()
{ {
Interrupt(); Interrupt();
@@ -346,9 +351,11 @@ void BaseIndex::Interrupt()
m_interrupt(); m_interrupt();
} }
bool BaseIndex::Start(CChainState& active_chainstate) bool BaseIndex::Start()
{ {
m_chainstate = &active_chainstate; // m_chainstate member gives indexing code access to node internals. It is
// removed in followup https://github.com/bitcoin/bitcoin/pull/24230
m_chainstate = &m_chain->context()->chainman->ActiveChainstate();
// Need to register this ValidationInterface before running Init(), so that // Need to register this ValidationInterface before running Init(), so that
// callbacks are not missed if Init sets m_synced to true. // callbacks are not missed if Init sets m_synced to true.
RegisterValidationInterface(this); RegisterValidationInterface(this);

View File

@@ -6,12 +6,16 @@
#define BITCOIN_INDEX_BASE_H #define BITCOIN_INDEX_BASE_H
#include <dbwrapper.h> #include <dbwrapper.h>
#include <interfaces/chain.h>
#include <threadinterrupt.h> #include <threadinterrupt.h>
#include <validationinterface.h> #include <validationinterface.h>
class CBlock; class CBlock;
class CBlockIndex; class CBlockIndex;
class CChainState; class CChainState;
namespace interfaces {
class Chain;
} // namespace interfaces
struct IndexSummary { struct IndexSummary {
std::string name; std::string name;
@@ -79,6 +83,7 @@ private:
virtual bool AllowPrune() const = 0; virtual bool AllowPrune() const = 0;
protected: protected:
std::unique_ptr<interfaces::Chain> m_chain;
CChainState* m_chainstate{nullptr}; CChainState* m_chainstate{nullptr};
void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override;
@@ -110,6 +115,7 @@ protected:
void SetBestBlockIndex(const CBlockIndex* block); void SetBestBlockIndex(const CBlockIndex* block);
public: public:
BaseIndex(std::unique_ptr<interfaces::Chain> chain);
/// Destructor interrupts sync thread if running and blocks until it exits. /// Destructor interrupts sync thread if running and blocks until it exits.
virtual ~BaseIndex(); virtual ~BaseIndex();
@@ -124,7 +130,7 @@ public:
/// Start initializes the sync state and registers the instance as a /// Start initializes the sync state and registers the instance as a
/// ValidationInterface so that it stays in sync with blockchain updates. /// ValidationInterface so that it stays in sync with blockchain updates.
[[nodiscard]] bool Start(CChainState& active_chainstate); [[nodiscard]] bool Start();
/// Stops the instance from staying in sync with blockchain updates. /// Stops the instance from staying in sync with blockchain updates.
void Stop(); void Stop();

View File

@@ -94,9 +94,9 @@ struct DBHashKey {
static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes; static std::map<BlockFilterType, BlockFilterIndex> g_filter_indexes;
BlockFilterIndex::BlockFilterIndex(BlockFilterType filter_type, BlockFilterIndex::BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe) size_t n_cache_size, bool f_memory, bool f_wipe)
: m_filter_type(filter_type) : BaseIndex(std::move(chain)), m_filter_type(filter_type)
{ {
const std::string& filter_name = BlockFilterTypeName(filter_type); const std::string& filter_name = BlockFilterTypeName(filter_type);
if (filter_name.empty()) throw std::invalid_argument("unknown filter_type"); if (filter_name.empty()) throw std::invalid_argument("unknown filter_type");
@@ -467,12 +467,12 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn)
for (auto& entry : g_filter_indexes) fn(entry.second); for (auto& entry : g_filter_indexes) fn(entry.second);
} }
bool InitBlockFilterIndex(BlockFilterType filter_type, bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory, bool f_wipe) size_t n_cache_size, bool f_memory, bool f_wipe)
{ {
auto result = g_filter_indexes.emplace(std::piecewise_construct, auto result = g_filter_indexes.emplace(std::piecewise_construct,
std::forward_as_tuple(filter_type), std::forward_as_tuple(filter_type),
std::forward_as_tuple(filter_type, std::forward_as_tuple(make_chain(), filter_type,
n_cache_size, f_memory, f_wipe)); n_cache_size, f_memory, f_wipe));
return result.second; return result.second;
} }

View File

@@ -55,7 +55,7 @@ protected:
public: public:
/** Constructs the index, which becomes available to be queried. */ /** Constructs the index, which becomes available to be queried. */
explicit BlockFilterIndex(BlockFilterType filter_type, explicit BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false); size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
BlockFilterType GetFilterType() const { return m_filter_type; } BlockFilterType GetFilterType() const { return m_filter_type; }
@@ -88,7 +88,7 @@ void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn);
* Initialize a block filter index for the given type if one does not already exist. Returns true if * Initialize a block filter index for the given type if one does not already exist. Returns true if
* a new index is created and false if one has already been initialized. * a new index is created and false if one has already been initialized.
*/ */
bool InitBlockFilterIndex(BlockFilterType filter_type, bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type,
size_t n_cache_size, bool f_memory = false, bool f_wipe = false); size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
/** /**

View File

@@ -102,7 +102,8 @@ struct DBHashKey {
std::unique_ptr<CoinStatsIndex> g_coin_stats_index; std::unique_ptr<CoinStatsIndex> g_coin_stats_index;
CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe) CoinStatsIndex::CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
: BaseIndex(std::move(chain))
{ {
fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"}; fs::path path{gArgs.GetDataDirNet() / "indexes" / "coinstats"};
fs::create_directories(path); fs::create_directories(path);

View File

@@ -53,7 +53,7 @@ protected:
public: public:
// Constructs the index, which becomes available to be queried. // Constructs the index, which becomes available to be queried.
explicit CoinStatsIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); explicit CoinStatsIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Look up stats for a specific block using CBlockIndex // Look up stats for a specific block using CBlockIndex
std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const; std::optional<kernel::CCoinsStats> LookUpStats(const CBlockIndex* block_index) const;

View File

@@ -48,8 +48,8 @@ bool TxIndex::DB::WriteTxs(const std::vector<std::pair<uint256, CDiskTxPos>>& v_
return WriteBatch(batch); return WriteBatch(batch);
} }
TxIndex::TxIndex(size_t n_cache_size, bool f_memory, bool f_wipe) TxIndex::TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory, bool f_wipe)
: m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe)) : BaseIndex(std::move(chain)), m_db(std::make_unique<TxIndex::DB>(n_cache_size, f_memory, f_wipe))
{} {}
TxIndex::~TxIndex() = default; TxIndex::~TxIndex() = default;

View File

@@ -31,7 +31,7 @@ protected:
public: public:
/// Constructs the index, which becomes available to be queried. /// Constructs the index, which becomes available to be queried.
explicit TxIndex(size_t n_cache_size, bool f_memory = false, bool f_wipe = false); explicit TxIndex(std::unique_ptr<interfaces::Chain> chain, size_t n_cache_size, bool f_memory = false, bool f_wipe = false);
// Destructor is declared because this class contains a unique_ptr to an incomplete type. // Destructor is declared because this class contains a unique_ptr to an incomplete type.
virtual ~TxIndex() override; virtual ~TxIndex() override;

View File

@@ -1594,22 +1594,22 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
return InitError(*error); return InitError(*error);
} }
g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex); g_txindex = std::make_unique<TxIndex>(interfaces::MakeChain(node), cache_sizes.tx_index, false, fReindex);
if (!g_txindex->Start(chainman.ActiveChainstate())) { if (!g_txindex->Start()) {
return false; return false;
} }
} }
for (const auto& filter_type : g_enabled_filter_types) { for (const auto& filter_type : g_enabled_filter_types) {
InitBlockFilterIndex(filter_type, cache_sizes.filter_index, false, fReindex); InitBlockFilterIndex([&]{ return interfaces::MakeChain(node); }, filter_type, cache_sizes.filter_index, false, fReindex);
if (!GetBlockFilterIndex(filter_type)->Start(chainman.ActiveChainstate())) { if (!GetBlockFilterIndex(filter_type)->Start()) {
return false; return false;
} }
} }
if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) {
g_coin_stats_index = std::make_unique<CoinStatsIndex>(/* cache size */ 0, false, fReindex); g_coin_stats_index = std::make_unique<CoinStatsIndex>(interfaces::MakeChain(node), /* cache size */ 0, false, fReindex);
if (!g_coin_stats_index->Start(chainman.ActiveChainstate())) { if (!g_coin_stats_index->Start()) {
return false; return false;
} }
} }

View File

@@ -304,6 +304,10 @@ public:
//! Return true if an assumed-valid chain is in use. //! Return true if an assumed-valid chain is in use.
virtual bool hasAssumedValidChain() = 0; virtual bool hasAssumedValidChain() = 0;
//! Get internal node context. Useful for testing, but not
//! accessible across processes.
virtual node::NodeContext* context() { return nullptr; }
}; };
//! Interface to let node manage chain clients (wallets, or maybe tools for //! Interface to let node manage chain clients (wallets, or maybe tools for

View File

@@ -781,6 +781,7 @@ public:
return Assert(m_node.chainman)->IsSnapshotActive(); return Assert(m_node.chainman)->IsSnapshotActive();
} }
NodeContext* context() override { return &m_node; }
NodeContext& m_node; NodeContext& m_node;
}; };
} // namespace } // namespace

View File

@@ -7,6 +7,7 @@
#include <consensus/merkle.h> #include <consensus/merkle.h>
#include <consensus/validation.h> #include <consensus/validation.h>
#include <index/blockfilterindex.h> #include <index/blockfilterindex.h>
#include <interfaces/chain.h>
#include <node/miner.h> #include <node/miner.h>
#include <pow.h> #include <pow.h>
#include <script/standard.h> #include <script/standard.h>
@@ -110,7 +111,7 @@ bool BuildChainTestingSetup::BuildChain(const CBlockIndex* pindex,
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup) BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
{ {
BlockFilterIndex filter_index(BlockFilterType::BASIC, 1 << 20, true); BlockFilterIndex filter_index(interfaces::MakeChain(m_node), BlockFilterType::BASIC, 1 << 20, true);
uint256 last_header; uint256 last_header;
@@ -137,7 +138,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, BuildChainTestingSetup)
// BlockUntilSyncedToCurrentChain should return false before index is started. // BlockUntilSyncedToCurrentChain should return false before index is started.
BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain()); BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
BOOST_REQUIRE(filter_index.Start(m_node.chainman->ActiveChainstate())); BOOST_REQUIRE(filter_index.Start());
// Allow filter index to catch up with the block index. // Allow filter index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000; constexpr int64_t timeout_ms = 10 * 1000;
@@ -279,14 +280,14 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC); filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index == nullptr); BOOST_CHECK(filter_index == nullptr);
BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false)); BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
filter_index = GetBlockFilterIndex(BlockFilterType::BASIC); filter_index = GetBlockFilterIndex(BlockFilterType::BASIC);
BOOST_CHECK(filter_index != nullptr); BOOST_CHECK(filter_index != nullptr);
BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC); BOOST_CHECK(filter_index->GetFilterType() == BlockFilterType::BASIC);
// Initialize returns false if index already exists. // Initialize returns false if index already exists.
BOOST_CHECK(!InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false)); BOOST_CHECK(!InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
int iter_count = 0; int iter_count = 0;
ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; }); ForEachBlockFilterIndex([&iter_count](BlockFilterIndex& _index) { iter_count++; });
@@ -301,7 +302,7 @@ BOOST_FIXTURE_TEST_CASE(blockfilter_index_init_destroy, BasicTestingSetup)
BOOST_CHECK(filter_index == nullptr); BOOST_CHECK(filter_index == nullptr);
// Reinitialize index. // Reinitialize index.
BOOST_CHECK(InitBlockFilterIndex(BlockFilterType::BASIC, 1 << 20, true, false)); BOOST_CHECK(InitBlockFilterIndex([&]{ return interfaces::MakeChain(m_node); }, BlockFilterType::BASIC, 1 << 20, true, false));
DestroyAllBlockFilterIndexes(); DestroyAllBlockFilterIndexes();

View File

@@ -4,6 +4,7 @@
#include <chainparams.h> #include <chainparams.h>
#include <index/coinstatsindex.h> #include <index/coinstatsindex.h>
#include <interfaces/chain.h>
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <test/util/validation.h> #include <test/util/validation.h>
#include <util/time.h> #include <util/time.h>
@@ -31,7 +32,7 @@ static void IndexWaitSynced(BaseIndex& index)
BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
{ {
CoinStatsIndex coin_stats_index{1 << 20, true}; CoinStatsIndex coin_stats_index{interfaces::MakeChain(m_node), 1 << 20, true};
const CBlockIndex* block_index; const CBlockIndex* block_index;
{ {
@@ -46,7 +47,7 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_initial_sync, TestChain100Setup)
// is started. // is started.
BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain()); BOOST_CHECK(!coin_stats_index.BlockUntilSyncedToCurrentChain());
BOOST_REQUIRE(coin_stats_index.Start(m_node.chainman->ActiveChainstate())); BOOST_REQUIRE(coin_stats_index.Start());
IndexWaitSynced(coin_stats_index); IndexWaitSynced(coin_stats_index);
@@ -90,8 +91,8 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate(); CChainState& chainstate = Assert(m_node.chainman)->ActiveChainstate();
const CChainParams& params = Params(); const CChainParams& params = Params();
{ {
CoinStatsIndex index{1 << 20}; CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
BOOST_REQUIRE(index.Start(chainstate)); BOOST_REQUIRE(index.Start());
IndexWaitSynced(index); IndexWaitSynced(index);
std::shared_ptr<const CBlock> new_block; std::shared_ptr<const CBlock> new_block;
CBlockIndex* new_block_index = nullptr; CBlockIndex* new_block_index = nullptr;
@@ -116,9 +117,9 @@ BOOST_FIXTURE_TEST_CASE(coinstatsindex_unclean_shutdown, TestChain100Setup)
} }
{ {
CoinStatsIndex index{1 << 20}; CoinStatsIndex index{interfaces::MakeChain(m_node), 1 << 20};
// Make sure the index can be loaded. // Make sure the index can be loaded.
BOOST_REQUIRE(index.Start(chainstate)); BOOST_REQUIRE(index.Start());
index.Stop(); index.Stop();
} }
} }

View File

@@ -4,6 +4,7 @@
#include <chainparams.h> #include <chainparams.h>
#include <index/txindex.h> #include <index/txindex.h>
#include <interfaces/chain.h>
#include <script/standard.h> #include <script/standard.h>
#include <test/util/setup_common.h> #include <test/util/setup_common.h>
#include <util/time.h> #include <util/time.h>
@@ -15,7 +16,7 @@ BOOST_AUTO_TEST_SUITE(txindex_tests)
BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup) BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
{ {
TxIndex txindex(1 << 20, true); TxIndex txindex(interfaces::MakeChain(m_node), 1 << 20, true);
CTransactionRef tx_disk; CTransactionRef tx_disk;
uint256 block_hash; uint256 block_hash;
@@ -28,7 +29,7 @@ BOOST_FIXTURE_TEST_CASE(txindex_initial_sync, TestChain100Setup)
// BlockUntilSyncedToCurrentChain should return false before txindex is started. // BlockUntilSyncedToCurrentChain should return false before txindex is started.
BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain()); BOOST_CHECK(!txindex.BlockUntilSyncedToCurrentChain());
BOOST_REQUIRE(txindex.Start(m_node.chainman->ActiveChainstate())); BOOST_REQUIRE(txindex.Start());
// Allow tx index to catch up with the block index. // Allow tx index to catch up with the block index.
constexpr int64_t timeout_ms = 10 * 1000; constexpr int64_t timeout_ms = 10 * 1000;

View File

@@ -23,6 +23,9 @@ EXPECTED_CIRCULAR_DEPENDENCIES = (
"wallet/wallet -> wallet/walletdb -> wallet/wallet", "wallet/wallet -> wallet/walletdb -> wallet/wallet",
"kernel/coinstats -> validation -> kernel/coinstats", "kernel/coinstats -> validation -> kernel/coinstats",
"kernel/mempool_persist -> validation -> kernel/mempool_persist", "kernel/mempool_persist -> validation -> kernel/mempool_persist",
# Temporary, removed in followup https://github.com/bitcoin/bitcoin/pull/24230
"index/base -> node/context -> net_processing -> index/blockfilterindex -> index/base",
) )
CODE_DIR = "src" CODE_DIR = "src"