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/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: 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;