From 94959b8deedcff98a55c87b5e473890b2e7a3b16 Mon Sep 17 00:00:00 2001 From: Sjors Provoost Date: Tue, 20 May 2025 09:25:03 +0200 Subject: [PATCH] Add checkBlock to Mining interface Use it in miner_tests. The getblocktemplate and generateblock RPC calls don't use this, because it would make the code more verbose. --- src/interfaces/mining.h | 15 ++++++++++++++ src/ipc/capnp/mining.capnp | 6 ++++++ src/node/interfaces.cpp | 9 +++++++++ src/node/types.h | 12 ++++++++++++ src/test/miner_tests.cpp | 40 +++++++++++++++++++++++++++++++++++++- 5 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 3ecb86e8ea1..150295e5b7b 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -114,6 +114,21 @@ public: */ virtual std::unique_ptr createNewBlock(const node::BlockCreateOptions& options = {}) = 0; + /** + * Checks if a given block is valid. + * + * @param[in] block the block to check + * @param[in] options verification options: the proof-of-work check can be + * skipped in order to verify a template generated by + * external software. + * @param[out] reason failure reason (BIP22) + * @param[out] debug more detailed rejection reason + * @returns whether the block is valid + * + * For signets the challenge verification is skipped when check_pow is false. + */ + virtual bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) = 0; + //! Get internal node context. Useful for RPC and testing, //! but not accessible across processes. virtual node::NodeContext* context() { return nullptr; } diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index f3327bf2e7b..8ee4745b858 100644 --- a/src/ipc/capnp/mining.capnp +++ b/src/ipc/capnp/mining.capnp @@ -18,6 +18,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") { getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool); waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef); createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate); + checkBlock @5 (block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { @@ -44,3 +45,8 @@ struct BlockWaitOptions $Proxy.wrap("node::BlockWaitOptions") { timeout @0 : Float64 $Proxy.name("timeout"); feeThreshold @1 : Int64 $Proxy.name("fee_threshold"); } + +struct BlockCheckOptions $Proxy.wrap("node::BlockCheckOptions") { + checkMerkleRoot @0 :Bool $Proxy.name("check_merkle_root"); + checkPow @1 :Bool $Proxy.name("check_pow"); +} diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 04afc852e43..1e659e0ee0d 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -984,6 +984,15 @@ public: return std::make_unique(assemble_options, BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(), m_node); } + bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) override + { + LOCK(chainman().GetMutex()); + BlockValidationState state{TestBlockValidity(chainman().ActiveChainstate(), block, /*check_pow=*/options.check_pow, /*=check_merkle_root=*/options.check_merkle_root)}; + reason = state.GetRejectReason(); + debug = state.GetDebugMessage(); + return state.IsValid(); + } + NodeContext* context() override { return &m_node; } ChainstateManager& chainman() { return *Assert(m_node.chainman); } KernelNotifications& notifications() { return *Assert(m_node.notifications); } diff --git a/src/node/types.h b/src/node/types.h index 0f9b871084a..547d644831c 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -17,6 +17,7 @@ #include #include #include