init refactor: Only initialize node.notifications one time

Instead of having the InitAndLoadChainstate function delete and create the
KernelNotifications object each time it is called (it can be called twice when
reindexing) to clear cached state, create it just one time and add a
setChainstateLoaded() method to manage state as it is loaded and unloaded.

This refactoring should make sense by itself to be more explicit about how
KernelNotifications state is cleared, but it's also needed to make outside code
accessing KernelNotifications state (currently just mining code) safe during
node startup and shutdown so the KernelNofications mutex can be used for
synchronization and does not get recreated itself.
This commit is contained in:
Ryan Ofsky
2026-02-24 10:15:14 -05:00
parent c8e332cb33
commit a7cabf92e4
3 changed files with 31 additions and 9 deletions

View File

@@ -1304,16 +1304,12 @@ static ChainstateLoadResult InitAndLoadChainstate(
const ArgsManager& args)
{
// This function may be called twice, so any dirty state must be reset.
node.notifications.reset(); // Drop state, such as a cached tip block
node.notifications->setChainstateLoaded(false); // Drop state, such as a cached tip block
node.mempool.reset();
node.chainman.reset(); // Drop state, such as an initialized m_block_tree_db
const CChainParams& chainparams = Params();
Assert(!node.notifications); // Was reset above
node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings));
ReadNotificationArgs(args, *node.notifications);
CTxMemPool::Options mempool_opts{
.check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0,
.signals = node.validation_signals.get(),
@@ -1414,6 +1410,7 @@ static ChainstateLoadResult InitAndLoadChainstate(
std::tie(status, error) = catch_exceptions([&] { return VerifyLoadedChainstate(chainman, options); });
if (status == node::ChainstateLoadStatus::SUCCESS) {
LogInfo("Block index and chainstate loaded");
node.notifications->setChainstateLoaded(true);
}
}
return {status, error};
@@ -1486,6 +1483,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.validation_signals = std::make_unique<ValidationSignals>(std::make_unique<SerialTaskRunner>(scheduler));
auto& validation_signals = *node.validation_signals;
// Create KernelNotifications object. Important to do this early before
// calling ipc->listenAddress() below so makeMining and other IPC methods
// can use this.
assert(!node.notifications);
node.notifications = std::make_unique<KernelNotifications>(Assert(node.shutdown_request), node.exit_status, *Assert(node.warnings));
ReadNotificationArgs(args, *node.notifications);
// Create client interfaces for wallets that are supposed to be loaded
// according to -wallet and -disablewallet options. This only constructs
// the interfaces, it doesn't load wallet data. Wallets actually get loaded