Skip to content

Commit

Permalink
Replace RPCNotifyBlockChange with waitTipChanged()
Browse files Browse the repository at this point in the history
This refactoring commit uses the newly introduced waitTipChanged mining interface method to replace the RPCNotifyBlockChange mechanism.
  • Loading branch information
Sjors committed Aug 26, 2024
1 parent fd05970 commit 24de8a6
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 57 deletions.
9 changes: 0 additions & 9 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -427,16 +427,12 @@ static void registerSignalHandler(int signal, void(*handler)(int))
}
#endif

static boost::signals2::connection rpc_notify_block_change_connection;
static void OnRPCStarted()
{
rpc_notify_block_change_connection = uiInterface.NotifyBlockTip_connect(std::bind(RPCNotifyBlockChange, std::placeholders::_2));
}

static void OnRPCStopped()
{
rpc_notify_block_change_connection.disconnect();
RPCNotifyBlockChange(nullptr);
g_best_block_cv.notify_all();
LogPrint(BCLog::RPC, "RPC stopped.\n");
}
Expand Down Expand Up @@ -1980,11 +1976,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
// 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 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();

uiInterface.InitMessage(_("Done loading").translated);
Expand Down
86 changes: 41 additions & 45 deletions src/rpc/blockchain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include <hash.h>
#include <index/blockfilterindex.h>
#include <index/coinstatsindex.h>
#include <interfaces/mining.h>
#include <kernel/coinstats.h>
#include <logging/timer.h>
#include <net.h>
Expand Down Expand Up @@ -60,21 +61,12 @@
using kernel::CCoinsStats;
using kernel::CoinStatsHashType;

using interfaces::Mining;
using node::BlockManager;
using node::NodeContext;
using node::SnapshotMetadata;
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);

/* Calculate the difficulty for a given block index.
*/
double GetDifficulty(const CBlockIndex& blockindex)
Expand Down Expand Up @@ -243,16 +235,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()
{
return RPCHelpMan{"waitfornewblock",
Expand All @@ -279,16 +261,14 @@ static RPCHelpMan waitfornewblock()
timeout = request.params[0].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");

CUpdatedBlock block;
{
WAIT_LOCK(cs_blockchange, lock);
block = latestblock;
if(timeout)
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(); });
else
cond_blockchange.wait(lock, [&block]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height != block.height || latestblock.hash != block.hash || !IsRPCRunning(); });
block = latestblock;
NodeContext& node = EnsureAnyNodeContext(request.context);
Mining& miner = EnsureMining(node);

auto block{CHECK_NONFATAL(miner.getTip()).value()};
if (IsRPCRunning()) {
block = timeout ? miner.waitTipChanged(block.hash, std::chrono::milliseconds(timeout)) : miner.waitTipChanged(block.hash);
}

UniValue ret(UniValue::VOBJ);
ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height);
Expand Down Expand Up @@ -327,14 +307,21 @@ static RPCHelpMan waitforblock()
timeout = request.params[1].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");

CUpdatedBlock block;
{
WAIT_LOCK(cs_blockchange, lock);
if(timeout)
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning();});
else
cond_blockchange.wait(lock, [&hash]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.hash == hash || !IsRPCRunning(); });
block = latestblock;
NodeContext& node = EnsureAnyNodeContext(request.context);
Mining& miner = EnsureMining(node);

auto block{CHECK_NONFATAL(miner.getTip()).value()};
const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};
while (IsRPCRunning()) {
if (block.hash == hash) break;
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);
Expand Down Expand Up @@ -376,15 +363,24 @@ static RPCHelpMan waitforblockheight()
timeout = request.params[1].getInt<int>();
if (timeout < 0) throw JSONRPCError(RPC_MISC_ERROR, "Negative timeout");

CUpdatedBlock block;
{
WAIT_LOCK(cs_blockchange, lock);
if(timeout)
cond_blockchange.wait_for(lock, std::chrono::milliseconds(timeout), [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning();});
else
cond_blockchange.wait(lock, [&height]() EXCLUSIVE_LOCKS_REQUIRED(cs_blockchange) {return latestblock.height >= height || !IsRPCRunning(); });
block = latestblock;
NodeContext& node = EnsureAnyNodeContext(request.context);
Mining& miner = EnsureMining(node);

auto block{CHECK_NONFATAL(miner.getTip()).value()};
const auto deadline{std::chrono::steady_clock::now() + 1ms * timeout};

while (IsRPCRunning()) {
if (block.height >= height) break;
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);
ret.pushKV("hash", block.hash.GetHex());
ret.pushKV("height", block.height);
Expand Down
3 changes: 0 additions & 3 deletions src/rpc/blockchain.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,6 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
*/
double GetDifficulty(const CBlockIndex& blockindex);

/** Callback for when block tip changed. */
void RPCNotifyBlockChange(const CBlockIndex*);

/** Block description to JSON */
UniValue blockToJSON(node::BlockManager& blockman, const CBlock& block, const CBlockIndex& tip, const CBlockIndex& blockindex, TxVerbosity verbosity) LOCKS_EXCLUDED(cs_main);

Expand Down

0 comments on commit 24de8a6

Please sign in to comment.