mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-03-02 01:36:13 +00:00
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:
parent
c8e332cb33
commit
a7cabf92e4
14
src/init.cpp
14
src/init.cpp
@ -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
|
||||
|
||||
@ -53,7 +53,7 @@ kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state
|
||||
{
|
||||
LOCK(m_tip_block_mutex);
|
||||
Assume(index.GetBlockHash() != uint256::ZERO);
|
||||
m_tip_block = index.GetBlockHash();
|
||||
m_state.tip_block = index.GetBlockHash();
|
||||
m_tip_block_cv.notify_all();
|
||||
}
|
||||
|
||||
@ -103,7 +103,7 @@ void KernelNotifications::fatalError(const bilingual_str& message)
|
||||
std::optional<uint256> KernelNotifications::TipBlock()
|
||||
{
|
||||
AssertLockHeld(m_tip_block_mutex);
|
||||
return m_tip_block;
|
||||
return m_state.tip_block;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@ -29,6 +29,18 @@ namespace node {
|
||||
class Warnings;
|
||||
static constexpr int DEFAULT_STOPATHEIGHT{0};
|
||||
|
||||
//! State tracked by the KernelNotifications interface meant to be used by
|
||||
//! mining code, index code, RPCs, and other code sitting above the validation
|
||||
//! layer.
|
||||
//!
|
||||
//! Currently just tracks the chain tip, but could be used to hold other
|
||||
//! information in the future, like the last flushed block, pruning
|
||||
//! information, etc.
|
||||
struct KernelState {
|
||||
bool chainstate_loaded{false};
|
||||
std::optional<uint256> tip_block;
|
||||
};
|
||||
|
||||
class KernelNotifications : public kernel::Notifications
|
||||
{
|
||||
public:
|
||||
@ -49,6 +61,13 @@ public:
|
||||
|
||||
void fatalError(const bilingual_str& message) override;
|
||||
|
||||
void setChainstateLoaded(bool chainstate_loaded) EXCLUSIVE_LOCKS_REQUIRED(!m_tip_block_mutex) {
|
||||
LOCK(m_tip_block_mutex);
|
||||
if (!chainstate_loaded) m_state = {};
|
||||
m_state.chainstate_loaded = chainstate_loaded;
|
||||
m_tip_block_cv.notify_all();
|
||||
}
|
||||
|
||||
//! Block height after which blockTip notification will return Interrupted{}, if >0.
|
||||
int m_stop_at_height{DEFAULT_STOPATHEIGHT};
|
||||
//! Useful for tests, can be set to false to avoid shutdown on fatal error.
|
||||
@ -56,6 +75,7 @@ public:
|
||||
|
||||
Mutex m_tip_block_mutex;
|
||||
std::condition_variable m_tip_block_cv GUARDED_BY(m_tip_block_mutex);
|
||||
KernelState m_state GUARDED_BY(m_tip_block_mutex);
|
||||
//! The block for which the last blockTip notification was received.
|
||||
//! It's first set when the tip is connected during node initialization.
|
||||
//! Might be unset during an early shutdown.
|
||||
@ -65,8 +85,6 @@ private:
|
||||
const std::function<bool()>& m_shutdown_request;
|
||||
std::atomic<int>& m_exit_status;
|
||||
node::Warnings& m_warnings;
|
||||
|
||||
std::optional<uint256> m_tip_block GUARDED_BY(m_tip_block_mutex);
|
||||
};
|
||||
|
||||
void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user