diff --git a/src/init.cpp b/src/init.cpp index bdff6863be0..9d7c76a872f 100644 --- a/src/init.cpp +++ b/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(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(std::make_unique(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(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 diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp index f207b49a96b..ab0e5ccb69e 100644 --- a/src/node/kernel_notifications.cpp +++ b/src/node/kernel_notifications.cpp @@ -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 KernelNotifications::TipBlock() { AssertLockHeld(m_tip_block_mutex); - return m_tip_block; + return m_state.tip_block; }; diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h index e9f1e8f1889..b90248bf0ab 100644 --- a/src/node/kernel_notifications.h +++ b/src/node/kernel_notifications.h @@ -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 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& m_shutdown_request; std::atomic& m_exit_status; node::Warnings& m_warnings; - - std::optional m_tip_block GUARDED_BY(m_tip_block_mutex); }; void ReadNotificationArgs(const ArgsManager& args, KernelNotifications& notifications);