mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-12-06 02:33:28 +01:00
Merge bitcoin/bitcoin#30409: Introduce waitTipChanged() mining interface, replace RPCNotifyBlockChange, drop CRPCSignals & g_best_block
7942951e3fRemove unused g_best_block (Ryan Ofsky)e3a560ca68rpc: use waitTipChanged for longpoll (Ryan Ofsky)460687a09cRemove unused CRPCSignals (Sjors Provoost)dca923150eReplace RPCNotifyBlockChange with waitTipChanged() (Sjors Provoost)2a40ee1121rpc: check for negative timeout arg in waitfor* (Sjors Provoost)de7c855b3arpc: recommend -rpcclienttimeout=0 for waitfor* (Sjors Provoost)77ec072925rpc: fix waitfornewblock description (Sjors Provoost)285fe9fb51rpc: add test for waitforblock and waitfornewblock (Sjors Provoost)b94b27cf05Add waitTipChanged to Mining interface (Sjors Provoost)7eccdaf160node: Track last block that received a blockTip notification (Sjors Provoost)ebb8215f23Rename getTipHash() to getTip() and return BlockRef (Sjors Provoost)89a8f74bbbrefactor: rename BlockKey to BlockRef (Sjors Provoost) Pull request description: This continues the work in #30200 so that a future Stratum v2 Template Provider (see #29432) can avoid accessing node internals. It needs to know when a new block arrives in order to push new templates to connected clients. `waitTipChanged()` uses a new kernel notification `notifications().m_tip_block_mutex`, which this PR also introduces (a previous version used `g_best_block`). In order to ensure the new method works as intended, the `waitfornewblock`, `waitforblock` and `waitforblockheight` RPC methods are refactored to use it. This allows removing `RPCNotifyBlockChange`. There's a commit to add (direct) tests for the methods that are about to be refactored: - `waitfornewblock` was already implicitly tested by `feature_shutdown.py`. - `waitforblockheight` by `feature_coinstatsindex.py` and `example_test.py` This PR renames `getTipHash()` to `getTip()` and returns a `BlockRef` (renamed from `BlockKey`) so that callers can use either the height or hash. The later commits make trivial improvements to the `waitfor*` RPC calls (not needed for this PR). The `waitTipChanged()` method could probably also be used for the longpoll functionality in `getblocktemplate`, but I'm a bit reluctant to touch that. `RPCServer::OnStarted` no longer does anything and `RPCServer::OnStopped` merely prints a log statement. They were added in #5711 as a refactor. This PR drops them entirely. Finally `g_best_block` is also dropped. ACKs for top commit: achow101: ACK7942951e3fryanofsky: Code review ACK7942951e3f. Just rebased since last review TheCharlatan: Re-ACK7942951e3fTree-SHA512: a5559446b4000c95e07aad33284b7ee2e57aafd87e1ae778b3825d59689566d047a8047e47a10f76e6e341e7dc72fd265a65afbc0a9c011d17c4cafd55031837
This commit is contained in:
@@ -17,6 +17,7 @@
|
||||
#include <interfaces/handler.h>
|
||||
#include <interfaces/mining.h>
|
||||
#include <interfaces/node.h>
|
||||
#include <interfaces/types.h>
|
||||
#include <interfaces/wallet.h>
|
||||
#include <kernel/chain.h>
|
||||
#include <kernel/context.h>
|
||||
@@ -33,6 +34,7 @@
|
||||
#include <node/interface_ui.h>
|
||||
#include <node/mini_miner.h>
|
||||
#include <node/miner.h>
|
||||
#include <node/kernel_notifications.h>
|
||||
#include <node/transaction.h>
|
||||
#include <node/types.h>
|
||||
#include <node/warnings.h>
|
||||
@@ -67,6 +69,7 @@
|
||||
|
||||
#include <boost/signals2/signal.hpp>
|
||||
|
||||
using interfaces::BlockRef;
|
||||
using interfaces::BlockTemplate;
|
||||
using interfaces::BlockTip;
|
||||
using interfaces::Chain;
|
||||
@@ -137,7 +140,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)); };
|
||||
@@ -925,12 +928,33 @@ public:
|
||||
return chainman().IsInitialBlockDownload();
|
||||
}
|
||||
|
||||
std::optional<uint256> getTipHash() override
|
||||
std::optional<BlockRef> getTip() override
|
||||
{
|
||||
LOCK(::cs_main);
|
||||
CBlockIndex* tip{chainman().ActiveChain().Tip()};
|
||||
if (!tip) return {};
|
||||
return tip->GetBlockHash();
|
||||
return BlockRef{tip->GetBlockHash(), tip->nHeight};
|
||||
}
|
||||
|
||||
BlockRef waitTipChanged(uint256 current_tip, MillisecondsDouble timeout) override
|
||||
{
|
||||
// Interrupt check interval
|
||||
const MillisecondsDouble tick{1000};
|
||||
auto now{std::chrono::steady_clock::now()};
|
||||
auto deadline = now + timeout;
|
||||
// std::chrono does not check against overflow
|
||||
if (deadline < now) deadline = std::chrono::steady_clock::time_point::max();
|
||||
{
|
||||
WAIT_LOCK(notifications().m_tip_block_mutex, lock);
|
||||
while ((notifications().m_tip_block == uint256() || notifications().m_tip_block == current_tip) && !chainman().m_interrupt) {
|
||||
now = std::chrono::steady_clock::now();
|
||||
if (now >= deadline) break;
|
||||
notifications().m_tip_block_cv.wait_until(lock, std::min(deadline, now + tick));
|
||||
}
|
||||
}
|
||||
// Must release m_tip_block_mutex before locking cs_main, to avoid deadlocks.
|
||||
LOCK(::cs_main);
|
||||
return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
|
||||
}
|
||||
|
||||
bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
|
||||
@@ -965,6 +989,7 @@ public:
|
||||
|
||||
NodeContext* context() override { return &m_node; }
|
||||
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
|
||||
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
|
||||
NodeContext& m_node;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
@@ -7,6 +7,10 @@
|
||||
|
||||
#include <kernel/notifications_interface.h>
|
||||
|
||||
#include <sync.h>
|
||||
#include <threadsafety.h>
|
||||
#include <uint256.h>
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
@@ -34,7 +38,7 @@ public:
|
||||
KernelNotifications(util::SignalInterrupt& shutdown, std::atomic<int>& 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<int>& m_exit_status;
|
||||
|
||||
Reference in New Issue
Block a user