diff --git a/src/init.cpp b/src/init.cpp index d6c80d8f84d..65575f26fcc 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -284,7 +284,7 @@ void Shutdown(NodeContext& node) StopHTTPRPC(); StopREST(); - StopRPC(); + StopRPC(&node); StopHTTPServer(); for (const auto& client : node.chain_clients) { client->flush(); diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 60ff6d406a2..0b7685aa873 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -139,7 +139,7 @@ public: // Stop RPC for clean shutdown if any of waitfor* commands is executed. if (args().GetBoolArg("-server", false)) { InterruptRPC(); - StopRPC(); + StopRPC(m_context); } } bool shutdownRequested() override { return ShutdownRequested(*Assert(m_context)); }; diff --git a/src/node/kernel_notifications.cpp b/src/node/kernel_notifications.cpp index 9894052a3a0..40d45c8c2b8 100644 --- a/src/node/kernel_notifications.cpp +++ b/src/node/kernel_notifications.cpp @@ -50,6 +50,12 @@ namespace node { kernel::InterruptResult KernelNotifications::blockTip(SynchronizationState state, CBlockIndex& index) { + { + LOCK(m_tip_block_mutex); + m_tip_block = index.GetBlockHash(); + m_tip_block_cv.notify_all(); + } + uiInterface.NotifyBlockTip(state, &index); if (m_stop_at_height && index.nHeight >= m_stop_at_height) { if (!m_shutdown()) { diff --git a/src/node/kernel_notifications.h b/src/node/kernel_notifications.h index e37f4d4e1e4..9ff980ea56d 100644 --- a/src/node/kernel_notifications.h +++ b/src/node/kernel_notifications.h @@ -7,6 +7,10 @@ #include +#include +#include +#include + #include #include @@ -34,7 +38,7 @@ public: KernelNotifications(util::SignalInterrupt& shutdown, std::atomic& exit_status, node::Warnings& warnings) : m_shutdown(shutdown), m_exit_status{exit_status}, m_warnings{warnings} {} - [[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override; + [[nodiscard]] kernel::InterruptResult blockTip(SynchronizationState state, CBlockIndex& index) override EXCLUSIVE_LOCKS_REQUIRED(!m_tip_block_mutex); void headerTip(SynchronizationState state, int64_t height, int64_t timestamp, bool presync) override; @@ -52,6 +56,12 @@ public: int m_stop_at_height{DEFAULT_STOPATHEIGHT}; //! Useful for tests, can be set to false to avoid shutdown on fatal error. bool m_shutdown_on_fatal_error{true}; + + Mutex m_tip_block_mutex; + std::condition_variable m_tip_block_cv; + //! The block for which the last blockTip notification was received for. + uint256 m_tip_block; + private: util::SignalInterrupt& m_shutdown; std::atomic& m_exit_status; diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp index 2c07a2ff087..fb50d453fa9 100644 --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -311,16 +312,19 @@ void InterruptRPC() }); } -void StopRPC() +void StopRPC(const std::any& context) { static std::once_flag g_rpc_stop_flag; // This function could be called twice if the GUI has been started with -server=1. assert(!g_rpc_running); - std::call_once(g_rpc_stop_flag, []() { + std::call_once(g_rpc_stop_flag, [&]() { LogDebug(BCLog::RPC, "Stopping RPC\n"); WITH_LOCK(g_deadline_timers_mutex, deadlineTimers.clear()); DeleteAuthCookie(); g_rpcSignals.Stopped(); + node::NodeContext& node = EnsureAnyNodeContext(context); + // The notifications interface doesn't exist between initialization step 4a and 7. + if (node.notifications) node.notifications->m_tip_block_cv.notify_all(); }); } diff --git a/src/rpc/server.h b/src/rpc/server.h index 56e8a63088b..a13ae3b1e58 100644 --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -178,7 +179,7 @@ extern CRPCTable tableRPC; void StartRPC(); void InterruptRPC(); -void StopRPC(); +void StopRPC(const std::any& context); UniValue JSONRPCExec(const JSONRPCRequest& jreq, bool catch_errors); #endif // BITCOIN_RPC_SERVER_H