Replace RPCNotifyBlockChange with waitTipChanged()

This refactoring commit uses the newly introduced waitTipChanged mining interface method to replace the RPCNotifyBlockChange mechanism.
This commit is contained in:
Sjors Provoost 2024-08-12 12:36:49 +02:00
parent 2a40ee1121
commit dca923150e
No known key found for this signature in database
GPG key ID: 57FF9BDBCC301009
3 changed files with 39 additions and 57 deletions

View file

@ -429,16 +429,12 @@ static void registerSignalHandler(int signal, void(*handler)(int))
} }
#endif #endif
static boost::signals2::connection rpc_notify_block_change_connection;
static void OnRPCStarted() static void OnRPCStarted()
{ {
rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(std::bind(RPCNotifyBlockChange, std::placeholders::_2));
} }
static void OnRPCStopped() static void OnRPCStopped()
{ {
rpc_notify_block_change_connection.disconnect();
RPCNotifyBlockChange(nullptr);
g_best_block_cv.notify_all(); g_best_block_cv.notify_all();
LogDebug(BCLog::RPC, "RPC stopped.\n"); LogDebug(BCLog::RPC, "RPC stopped.\n");
} }
@ -2011,11 +2007,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// cannot yet be called. Before we make it callable, we need to make sure // 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 // that the RPC's view of the best block is valid and consistent with
// ChainstateManager's active tip. // ChainstateManager's active tip.
//
// 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(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip()));
SetRPCWarmupFinished(); SetRPCWarmupFinished();
uiInterface.InitMessage(_("Done loading").translated); uiInterface.InitMessage(_("Done loading").translated);

View file

@ -22,6 +22,7 @@
#include <hash.h> #include <hash.h>
#include <index/blockfilterindex.h> #include <index/blockfilterindex.h>
#include <index/coinstatsindex.h> #include <index/coinstatsindex.h>
#include <interfaces/mining.h>
#include <kernel/coinstats.h> #include <kernel/coinstats.h>
#include <logging/timer.h> #include <logging/timer.h>
#include <net.h> #include <net.h>
@ -61,21 +62,12 @@
using kernel::CCoinsStats; using kernel::CCoinsStats;
using kernel::CoinStatsHashType; using kernel::CoinStatsHashType;
using interfaces::Mining;
using node::BlockManager; using node::BlockManager;
using node::NodeContext; using node::NodeContext;
using node::SnapshotMetadata; using node::SnapshotMetadata;
using util::MakeUnorderedList; using util::MakeUnorderedList;
struct CUpdatedBlock
{
uint256 hash;
int height;
};
static GlobalMutex cs_blockchange;
static std::condition_variable cond_blockchange;
static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*> std::tuple<std::unique_ptr<CCoinsViewCursor>, CCoinsStats, const CBlockIndex*>
PrepareUTXOSnapshot( PrepareUTXOSnapshot(
Chainstate& chainstate, Chainstate& chainstate,
@ -262,16 +254,6 @@ static RPCHelpMan getbestblockhash()
}; };
} }
void RPCNotifyBlockChange(const CBlockIndex* pindex)
{
if(pindex) {
LOCK(cs_blockchange);
latestblock.hash = pindex->GetBlockHash();
latestblock.height = pindex->nHeight;
}
cond_blockchange.notify_all();
}
static RPCHelpMan waitfornewblock() static RPCHelpMan waitfornewblock()
{ {
return RPCHelpMan{"waitfornewblock", return RPCHelpMan{"waitfornewblock",
@ -298,16 +280,14 @@ static RPCHelpMan waitfornewblock()
timeout = request.params[0].getInt<int>(); timeout = request.params[0].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
CUpdatedBlock block; NodeContext& node = EnsureAnyNodeContext(request.context);
{ Mining& miner = EnsureMining(node);
WAIT_LOCK(cs_blockchange, lock);
block = latestblock; auto block{CHECK_NONFATAL(miner.getTip()).value()};
if(timeout) if (IsRPCRunning()) {
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); }); block = timeout ? miner.waitTipChanged(block.hash, std::chrono::milliseconds(timeout)) : miner.waitTipChanged(block.hash);
else
cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
block = latestblock;
} }
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height); ret.pushKV("height", block.height);
@ -346,14 +326,20 @@ static RPCHelpMan waitforblock()
timeout = request.params[1].getInt<int>(); timeout = request.params[1].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
CUpdatedBlock block; NodeContext& node = EnsureAnyNodeContext(request.context);
{ Mining& miner = EnsureMining(node);
WAIT_LOCK(cs_blockchange, lock);
if(timeout) auto block{CHECK_NONFATAL(miner.getTip()).value()};
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();}); const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
else while (IsRPCRunning() && block.hash != hash) {
cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); }); if (timeout) {
block = latestblock; auto now{std::chrono::steady_clock::now()};
if (now >= deadline) break;
const MillisecondsDouble remaining{deadline - now};
block = miner.waitTipChanged(block.hash, remaining);
} else {
block = miner.waitTipChanged(block.hash);
}
} }
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
@ -395,15 +381,23 @@ static RPCHelpMan waitforblockheight()
timeout = request.params[1].getInt<int>(); timeout = request.params[1].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout"); if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");
CUpdatedBlock block; NodeContext& node = EnsureAnyNodeContext(request.context);
{ Mining& miner = EnsureMining(node);
WAIT_LOCK(cs_blockchange, lock);
if(timeout) auto block{CHECK_NONFATAL(miner.getTip()).value()};
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();}); const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
else
cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); }); while (IsRPCRunning() && block.height < height) {
block = latestblock; if (timeout) {
auto now{std::chrono::steady_clock::now()};
if (now >= deadline) break;
const MillisecondsDouble remaining{deadline - now};
block = miner.waitTipChanged(block.hash, remaining);
} else {
block = miner.waitTipChanged(block.hash);
}
} }
UniValue ret(UniValue::VOBJ); UniValue ret(UniValue::VOBJ);
ret.pushKV("hash", block.hash.GetHex()); ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height); ret.pushKV("height", block.height);

View file

@ -35,9 +35,6 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
*/ */
double GetDifficulty(const CBlockIndex& blockindex); double GetDifficulty(const CBlockIndex& blockindex);
/** Callback for when block tip changed. */
void RPCNotifyBlockChange(const CBlockIndex*);
/** Block description to JSON */ /** Block description to JSON */
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main); UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);