0
0
Fork 0
mirror of https://github.com/bitcoin/bitcoin.git synced 2025-02-02 09:46:52 -05:00

kernel: Pass interrupt reference to chainman

This and the following commit seek to decouple the libbitcoinkernel
library from the shutdown code. As a library, it should it should have
its own flexible interrupt infrastructure without relying on node-wide
globals.

The commit takes the first step towards this goal by de-globalising
`ShutdownRequested` calls in kernel code.

Co-authored-by: Russell Yanofsky <russ@yanofsky.org>
Co-authored-by: TheCharlatan <seb.kung@gmail.com>
This commit is contained in:
TheCharlatan 2023-05-17 12:43:23 +02:00
parent e2d680a32d
commit edb55e2777
No known key found for this signature in database
GPG key ID: 9B79B45691DB4173
12 changed files with 55 additions and 40 deletions

View file

@ -113,7 +113,7 @@ int main(int argc, char* argv[])
.chainparams = chainman_opts.chainparams,
.blocks_dir = abs_datadir / "blocks",
};
ChainstateManager chainman{chainman_opts, blockman_opts};
ChainstateManager chainman{kernel_context.interrupt, chainman_opts, blockman_opts};
node::CacheSizes cache_sizes;
cache_sizes.block_tree_db = 2 << 20;

View file

@ -1462,7 +1462,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) {
node.mempool = std::make_unique<CTxMemPool>(mempool_opts);
node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
node.chainman = std::make_unique<ChainstateManager>(node.kernel->interrupt, chainman_opts, blockman_opts);
ChainstateManager& chainman = *node.chainman;
node::ChainstateLoadOptions options;

View file

@ -9,13 +9,13 @@
#include <logging.h>
#include <primitives/transaction.h>
#include <serialize.h>
#include <shutdown.h>
#include <streams.h>
#include <sync.h>
#include <txmempool.h>
#include <uint256.h>
#include <util/fs.h>
#include <util/fs_helpers.h>
#include <util/signalinterrupt.h>
#include <util/time.h>
#include <validation.h>
@ -95,7 +95,7 @@ bool LoadMempool(CTxMemPool& pool, const fs::path& load_path, Chainstate& active
} else {
++expired;
}
if (ShutdownRequested())
if (active_chainstate.m_chainman.m_interrupt)
return false;
}
std::map<uint256, CAmount> mapDeltas;

View file

@ -13,12 +13,12 @@
#include <logging.h>
#include <pow.h>
#include <reverse_iterator.h>
#include <shutdown.h>
#include <signet.h>
#include <streams.h>
#include <undo.h>
#include <util/batchpriority.h>
#include <util/fs.h>
#include <util/signalinterrupt.h>
#include <validation.h>
#include <map>
@ -250,7 +250,8 @@ CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
bool BlockManager::LoadBlockIndex()
{
if (!m_block_tree_db->LoadBlockIndexGuts(GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); })) {
if (!m_block_tree_db->LoadBlockIndexGuts(
GetConsensus(), [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }, m_interrupt)) {
return false;
}
@ -260,7 +261,7 @@ bool BlockManager::LoadBlockIndex()
CBlockIndexHeightOnlyComparator());
for (CBlockIndex* pindex : vSortedByHeight) {
if (ShutdownRequested()) return false;
if (m_interrupt) return false;
pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
@ -890,8 +891,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
}
LogPrintf("Reindexing block file blk%05u.dat...\n", (unsigned int)nFile);
chainman.ActiveChainstate().LoadExternalBlockFile(file, &pos, &blocks_with_unknown_parent);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
if (chainman.m_interrupt) {
LogPrintf("Interrupt requested. Exit %s\n", __func__);
return;
}
nFile++;
@ -909,8 +910,8 @@ void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFile
if (file) {
LogPrintf("Importing blocks file %s...\n", fs::PathToString(path));
chainman.ActiveChainstate().LoadExternalBlockFile(file);
if (ShutdownRequested()) {
LogPrintf("Shutdown requested. Exit %s\n", __func__);
if (chainman.m_interrupt) {
LogPrintf("Interrupt requested. Exit %s\n", __func__);
return;
}
} else {

View file

@ -33,6 +33,9 @@ struct FlatFilePos;
namespace Consensus {
struct Params;
}
namespace util {
class SignalInterrupt;
} // namespace util
namespace node {
@ -153,10 +156,12 @@ private:
public:
using Options = kernel::BlockManagerOpts;
explicit BlockManager(Options opts)
explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts)
: m_prune_mode{opts.prune_target > 0},
m_opts{std::move(opts)} {};
m_opts{std::move(opts)},
m_interrupt{interrupt} {};
const util::SignalInterrupt& m_interrupt;
std::atomic<bool> m_importing{false};
BlockMap m_block_index GUARDED_BY(cs_main);

View file

@ -25,7 +25,7 @@ BOOST_AUTO_TEST_CASE(blockmanager_find_block_pos)
.chainparams = *params,
.blocks_dir = m_args.GetBlocksDirPath(),
};
BlockManager blockman{blockman_opts};
BlockManager blockman{m_node.kernel->interrupt, blockman_opts};
CChain chain {};
// simulate adding a genesis block normally
BOOST_CHECK_EQUAL(blockman.SaveBlockToDisk(params->GenesisBlock(), 0, chain, nullptr).nPos, BLOCK_SERIALIZATION_HEADER_SIZE);

View file

@ -197,7 +197,7 @@ ChainTestingSetup::ChainTestingSetup(const ChainType chainType, const std::vecto
.chainparams = chainman_opts.chainparams,
.blocks_dir = m_args.GetBlocksDirPath(),
};
m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
m_node.chainman->m_blockman.m_block_tree_db = std::make_unique<CBlockTreeDB>(DBParams{
.path = m_args.GetDataDirNet() / "blocks" / "index",
.cache_bytes = static_cast<size_t>(m_cache_sizes.block_tree_db),

View file

@ -393,7 +393,7 @@ struct SnapshotTestSetup : TestChain100Setup {
// For robustness, ensure the old manager is destroyed before creating a
// new one.
m_node.chainman.reset();
m_node.chainman = std::make_unique<ChainstateManager>(chainman_opts, blockman_opts);
m_node.chainman = std::make_unique<ChainstateManager>(m_node.kernel->interrupt, chainman_opts, blockman_opts);
}
return *Assert(m_node.chainman);
}

View file

@ -9,8 +9,8 @@
#include <logging.h>
#include <pow.h>
#include <random.h>
#include <shutdown.h>
#include <uint256.h>
#include <util/signalinterrupt.h>
#include <util/translation.h>
#include <util/vector.h>
@ -291,7 +291,7 @@ bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
return true;
}
bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt)
{
AssertLockHeld(::cs_main);
std::unique_ptr<CDBIterator> pcursor(NewIterator());
@ -299,7 +299,7 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
// Load m_block_index
while (pcursor->Valid()) {
if (ShutdownRequested()) return false;
if (interrupt) return false;
std::pair<uint8_t, uint256> key;
if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
CDiskBlockIndex diskindex;

View file

@ -29,6 +29,9 @@ class uint256;
namespace Consensus {
struct Params;
};
namespace util {
class SignalInterrupt;
} // namespace util
//! -dbcache default (MiB)
static const int64_t nDefaultDbCache = 450;
@ -98,7 +101,7 @@ public:
void ReadReindexing(bool &fReindexing);
bool WriteFlag(const std::string &name, bool fValue);
bool ReadFlag(const std::string &name, bool &fValue);
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt)
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
};

View file

@ -50,6 +50,7 @@
#include <util/hasher.h>
#include <util/moneystr.h>
#include <util/rbf.h>
#include <util/signalinterrupt.h>
#include <util/strencodings.h>
#include <util/time.h>
#include <util/trace.h>
@ -3183,11 +3184,11 @@ bool Chainstate::ActivateBestChain(BlockValidationState& state, std::shared_ptr<
break;
}
// We check shutdown only after giving ActivateBestChainStep a chance to run once so that we
// never shutdown before connecting the genesis block during LoadChainTip(). Previously this
// caused an assert() failure during shutdown in such cases as the UTXO DB flushing checks
// We check interrupt only after giving ActivateBestChainStep a chance to run once so that we
// never interrupt before connecting the genesis block during LoadChainTip(). Previously this
// caused an assert() failure during interrupt in such cases as the UTXO DB flushing checks
// that the best block hash is non-null.
if (ShutdownRequested()) break;
if (m_chainman.m_interrupt) break;
} while (pindexNewTip != pindexMostWork);
CheckBlockIndex();
@ -3277,7 +3278,7 @@ bool Chainstate::InvalidateBlock(BlockValidationState& state, CBlockIndex* pinde
// Disconnect (descendants of) pindex, and mark them invalid.
while (true) {
if (ShutdownRequested()) break;
if (m_chainman.m_interrupt) break;
// Make sure the queue of validation callbacks doesn't grow unboundedly.
LimitValidationInterfaceQueue();
@ -4079,7 +4080,7 @@ void Chainstate::LoadMempool(const fs::path& load_path, FopenFn mockable_fopen_f
{
if (!m_mempool) return;
::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function);
m_mempool->SetLoadTried(!ShutdownRequested());
m_mempool->SetLoadTried(!m_chainman.m_interrupt);
}
bool Chainstate::LoadChainTip()
@ -4212,7 +4213,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
skipped_l3_checks = true;
}
}
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
}
if (pindexFailure) {
LogPrintf("Verification error: coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainstate.m_chain.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
@ -4245,7 +4246,7 @@ VerifyDBResult CVerifyDB::VerifyDB(
LogPrintf("Verification error: found unconnectable block at %d, hash=%s (%s)\n", pindex->nHeight, pindex->GetBlockHash().ToString(), state.ToString());
return VerifyDBResult::CORRUPTED_BLOCK_DB;
}
if (ShutdownRequested()) return VerifyDBResult::INTERRUPTED;
if (chainstate.m_chainman.m_interrupt) return VerifyDBResult::INTERRUPTED;
}
}
@ -4413,7 +4414,7 @@ bool ChainstateManager::LoadBlockIndex()
}
for (CBlockIndex* pindex : vSortedByHeight) {
if (ShutdownRequested()) return false;
if (m_interrupt) return false;
if (pindex->IsAssumedValid() ||
(pindex->IsValid(BLOCK_VALID_TRANSACTIONS) &&
(pindex->HaveTxsDownloaded() || pindex->pprev == nullptr))) {
@ -4519,7 +4520,7 @@ void Chainstate::LoadExternalBlockFile(
// such as a block fails to deserialize.
uint64_t nRewind = blkdat.GetPos();
while (!blkdat.eof()) {
if (ShutdownRequested()) return;
if (m_chainman.m_interrupt) return;
blkdat.SetPos(nRewind);
nRewind++; // start one byte further next time, in case of failure
@ -5152,13 +5153,13 @@ struct StopHashingException : public std::exception
{
const char* what() const throw() override
{
return "ComputeUTXOStats interrupted by shutdown.";
return "ComputeUTXOStats interrupted.";
}
};
static void SnapshotUTXOHashBreakpoint()
static void SnapshotUTXOHashBreakpoint(const util::SignalInterrupt& interrupt)
{
if (ShutdownRequested()) throw StopHashingException();
if (interrupt) throw StopHashingException();
}
bool ChainstateManager::PopulateAndValidateSnapshot(
@ -5235,7 +5236,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
// If our average Coin size is roughly 41 bytes, checking every 120,000 coins
// means <5MB of memory imprecision.
if (coins_processed % 120000 == 0) {
if (ShutdownRequested()) {
if (m_interrupt) {
return false;
}
@ -5292,7 +5293,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
try {
maybe_stats = ComputeUTXOStats(
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, SnapshotUTXOHashBreakpoint);
CoinStatsHashType::HASH_SERIALIZED, snapshot_coinsdb, m_blockman, [&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
} catch (StopHashingException const&) {
return false;
}
@ -5470,7 +5471,7 @@ SnapshotCompletionResult ChainstateManager::MaybeCompleteSnapshotValidation(
CoinStatsHashType::HASH_SERIALIZED,
&ibd_coins_db,
m_blockman,
SnapshotUTXOHashBreakpoint);
[&interrupt = m_interrupt] { SnapshotUTXOHashBreakpoint(interrupt); });
} catch (StopHashingException const&) {
return SnapshotCompletionResult::STATS_FAILED;
}
@ -5579,9 +5580,10 @@ static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts)
return std::move(opts);
}
ChainstateManager::ChainstateManager(Options options, node::BlockManager::Options blockman_options)
: m_options{Flatten(std::move(options))},
m_blockman{std::move(blockman_options)} {}
ChainstateManager::ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options)
: m_interrupt{interrupt},
m_options{Flatten(std::move(options))},
m_blockman{interrupt, std::move(blockman_options)} {}
ChainstateManager::~ChainstateManager()
{

View file

@ -62,6 +62,9 @@ class SnapshotMetadata;
namespace Consensus {
struct Params;
} // namespace Consensus
namespace util {
class SignalInterrupt;
} // namespace util
/** Maximum number of dedicated script-checking threads allowed */
static const int MAX_SCRIPTCHECK_THREADS = 15;
@ -959,7 +962,7 @@ private:
public:
using Options = kernel::ChainstateManagerOpts;
explicit ChainstateManager(Options options, node::BlockManager::Options blockman_options);
explicit ChainstateManager(const util::SignalInterrupt& interrupt, Options options, node::BlockManager::Options blockman_options);
const CChainParams& GetParams() const { return m_options.chainparams; }
const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); }
@ -982,6 +985,7 @@ public:
*/
RecursiveMutex& GetMutex() const LOCK_RETURNED(::cs_main) { return ::cs_main; }
const util::SignalInterrupt& m_interrupt;
const Options m_options;
std::thread m_load_block;
//! A single BlockManager instance is shared across each constructed