diff --git a/src/init.cpp b/src/init.cpp index f6e4de9e55..eb4fd0d685 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -2400,7 +2400,17 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 13: finished + // At this point, the RPC is "started", but still in warmup, which means it + // cannot yet be called. Before we make it callable, we need to make sure + // that the RPC's view of the best block is valid and consistent with + // ChainstateManager's ActiveTip. + // + // If we do not do this, RPC's view of the best block will be height=0 and + // hash=0x0. This will lead to erroroneous responses for things like + // waitforblockheight. + RPCNotifyBlockChange(chainman.ActiveTip()); SetRPCWarmupFinished(); + uiInterface.InitMessage(_("Done loading").translated); for (const auto& client : node.chain_clients) { diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index 88cb8add95..59a91679ef 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -6,7 +6,6 @@ #include // for CChainParams #include // for DeploymentActiveAfter -#include // for RPCNotifyBlockChange #include // for GetTime #include // for CleanupBlockRevFiles, fHavePruned, fReindex #include // for ShutdownRequested @@ -246,7 +245,6 @@ std::optional VerifyLoadedChainstate(ChainstateManage for (CChainState* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { const CBlockIndex* tip = chainstate->m_chain.Tip(); - RPCNotifyBlockChange(tip); if (tip && tip->nTime > GetTime() + MAX_FUTURE_BLOCK_TIME) { return ChainstateLoadVerifyError::ERROR_BLOCK_FROM_FUTURE; }