From 14a5f51a185a3d45677ae629356c3e6ebda3b669 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Fri, 31 Oct 2025 15:51:24 +0100 Subject: [PATCH 1/2] ipc: add interruptWait() Co-authored-by: ismaelsadeeq --- src/interfaces/mining.h | 5 +++++ src/ipc/capnp/mining.capnp | 1 + src/test/sv2_mock_mining.cpp | 6 ++++++ src/test/sv2_mock_mining.h | 1 + 4 files changed, 13 insertions(+) diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 82f0a9e4..ec88829b 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -68,6 +68,11 @@ class BlockTemplate * the tip is more than 20 minutes old. */ virtual std::unique_ptr waitNext(const node::BlockWaitOptions options = {}) = 0; + + /** + * Interrupts the current wait for the next block template. + */ + virtual void interruptWait() = 0; }; //! Interface giving clients (RPC, Stratum v2 Template Provider in the future) diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index 8ee4745b..ed01e44a 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -33,6 +33,7 @@ interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { getCoinbaseMerklePath @8 (context: Proxy.Context) -> (result: List(Data)); submitSolution @9 (context: Proxy.Context, version: UInt32, timestamp: UInt32, nonce: UInt32, coinbase :Data) -> (result: Bool); waitNext @10 (context: Proxy.Context, options: BlockWaitOptions) -> (result: BlockTemplate); + interruptWait @11() -> (); } struct BlockCreateOptions $Proxy.wrap("node::BlockCreateOptions") { diff --git a/src/test/sv2_mock_mining.cpp b/src/test/sv2_mock_mining.cpp index 7a9ac916..d0ba7d54 100644 --- a/src/test/sv2_mock_mining.cpp +++ b/src/test/sv2_mock_mining.cpp @@ -6,6 +6,7 @@ #include #include +#include namespace { static inline uint256 HashFromHeight(uint64_t h) @@ -94,6 +95,11 @@ std::unique_ptr MockBlockTemplate::waitNext(const nod } } + void MockBlockTemplate::interruptWait() +{ + LogPrintLevel(BCLog::SV2, BCLog::Level::Trace, "mock interruptWait()"); +} + MockMining::MockMining(std::shared_ptr st) : state(std::move(st)) {} bool MockMining::isTestChain() { return true; } bool MockMining::isInitialBlockDownload() { return false; } diff --git a/src/test/sv2_mock_mining.h b/src/test/sv2_mock_mining.h index 0f7badf1..57f1275a 100644 --- a/src/test/sv2_mock_mining.h +++ b/src/test/sv2_mock_mining.h @@ -65,6 +65,7 @@ class MockBlockTemplate : public interfaces::BlockTemplate { bool submitSolution(uint32_t, uint32_t, uint32_t, CTransactionRef) override; std::unique_ptr waitNext(const node::BlockWaitOptions options = {}) override; + void interruptWait() override; private: std::shared_ptr state; From 8c2c9f661f586beb0b263027805b7cf9ec2ea176 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Fri, 31 Oct 2025 15:53:42 +0100 Subject: [PATCH 2/2] Have ctrl + c interrupt pending waitNext() bitcoin/bitcoin#33676 adds interruptWait() to the Mining interface. Call this method for quicker shutdown. This change is backward compatible with the currently released version Bitcoin Core v30. If the new IPC method doesn't exist, it falls back to the previous behavior of just waiting for waitNext() to return after -sv2interval. --- src/sv2-tp.cpp | 4 ---- src/sv2/template_provider.cpp | 19 +++++++++++++++++++ src/sv2/template_provider.h | 5 +++-- 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/sv2-tp.cpp b/src/sv2-tp.cpp index f6fc41bf..126f2b6a 100644 --- a/src/sv2-tp.cpp +++ b/src/sv2-tp.cpp @@ -214,10 +214,6 @@ MAIN_FUNCTION UninterruptibleSleep(100ms); } - LogPrintLevel(BCLog::SV2, BCLog::Level::Info, - "Interrupt received, waiting up to %d seconds before shutting down (-sv2interval)", - options.fee_check_interval.count()); - tp->Interrupt(); tp->StopThreads(); tp.reset(); diff --git a/src/sv2/template_provider.cpp b/src/sv2/template_provider.cpp index 53fea776..34c213d9 100644 --- a/src/sv2/template_provider.cpp +++ b/src/sv2/template_provider.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include // NO_WITNESS_COMMITMENT @@ -122,6 +123,24 @@ Sv2TemplateProvider::~Sv2TemplateProvider() void Sv2TemplateProvider::Interrupt() { + AssertLockNotHeld(m_tp_mutex); + + LogPrintLevel(BCLog::SV2, BCLog::Level::Trace, "Interrupt pending waitNext() calls..."); + { + LOCK(m_tp_mutex); + try { + for (auto& t : GetBlockTemplates()) { + t.second->interruptWait(); + } + } catch (const ipc::Exception& e) { + // Bitcoin Core v30 does not yet implement interruptWait(), fall back + // to just waiting until waitNext() returns. + LogPrintLevel(BCLog::SV2, BCLog::Level::Info, + "Interrupt received, waiting up to %d seconds before shutting down (-sv2interval)", + m_options.fee_check_interval.count()); + } + } + m_flag_interrupt_sv2 = true; // Also interrupt network threads so client handlers can wind down quickly. if (m_connman) m_connman->Interrupt(); diff --git a/src/sv2/template_provider.h b/src/sv2/template_provider.h index 9de88910..7c8e82be 100644 --- a/src/sv2/template_provider.h +++ b/src/sv2/template_provider.h @@ -142,8 +142,9 @@ class Sv2TemplateProvider : public Sv2EventsInterface /** * Triggered on interrupt signals to stop the main event loop in ThreadSv2Handler(). + * Interrupts pending waitNext() calls */ - void Interrupt(); + void Interrupt() EXCLUSIVE_LOCKS_REQUIRED(!m_tp_mutex); /** * Tear down of the template provider thread and any other necessary tear down. @@ -162,7 +163,7 @@ class Sv2TemplateProvider : public Sv2EventsInterface void SubmitSolution(node::Sv2SubmitSolutionMsg solution) EXCLUSIVE_LOCKS_REQUIRED(!m_tp_mutex) override; - /* Block templates that connected clients may be working on, only used for tests */ + /* Block templates that connected clients may be working on */ BlockTemplateCache& GetBlockTemplates() EXCLUSIVE_LOCKS_REQUIRED(m_tp_mutex) { return m_block_template_cache; } private: