diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index 435151c5dda..23c23fe23f7 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -7,7 +7,7 @@ #include // for CAmount #include // for BlockRef -#include // for BlockCreateOptions, BlockWaitOptions +#include // for BlockCreateOptions, BlockWaitOptions, BlockCheckOptions #include // for CBlock, CBlockHeader #include // for CTransactionRef #include // for int64_t @@ -106,6 +106,20 @@ 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) + * @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) = 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-types.h b/src/ipc/capnp/mining-types.h index 2e60b43fcf3..62789759490 100644 --- a/src/ipc/capnp/mining-types.h +++ b/src/ipc/capnp/mining-types.h @@ -14,13 +14,7 @@ #include namespace mp { -// Custom serialization for BlockValidationState. -void CustomBuildMessage(InvokeContext& invoke_context, - const BlockValidationState& src, - ipc::capnp::messages::BlockValidationState::Builder&& builder); -void CustomReadMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::BlockValidationState::Reader& reader, - BlockValidationState& dest); +// Custom serializations } // namespace mp #endif // BITCOIN_IPC_CAPNP_MINING_TYPES_H diff --git a/src/ipc/capnp/mining.capnp b/src/ipc/capnp/mining.capnp index 32048e0ed19..3e5fc729c58 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, result: Bool); } interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") { @@ -45,12 +46,7 @@ struct BlockWaitOptions $Proxy.wrap("node::BlockWaitOptions") { feeThreshold @1 : Int64 $Proxy.name("fee_threshold"); } -# Note: serialization of the BlockValidationState C++ type is somewhat fragile -# and using the struct can be awkward. It would be good if testBlockValidity -# method were changed to return validity information in a simpler format. -struct BlockValidationState { - mode @0 :Int32; - result @1 :Int32; - rejectReason @2 :Text; - debugMessage @3 :Text; +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/ipc/capnp/mining.cpp b/src/ipc/capnp/mining.cpp index 0f9533c1c73..f598f1b2d8e 100644 --- a/src/ipc/capnp/mining.cpp +++ b/src/ipc/capnp/mining.cpp @@ -8,40 +8,4 @@ #include namespace mp { -void CustomBuildMessage(InvokeContext& invoke_context, - const BlockValidationState& src, - ipc::capnp::messages::BlockValidationState::Builder&& builder) -{ - if (src.IsValid()) { - builder.setMode(0); - } else if (src.IsInvalid()) { - builder.setMode(1); - } else if (src.IsError()) { - builder.setMode(2); - } else { - assert(false); - } - builder.setResult(static_cast(src.GetResult())); - builder.setRejectReason(src.GetRejectReason()); - builder.setDebugMessage(src.GetDebugMessage()); -} - -void CustomReadMessage(InvokeContext& invoke_context, - const ipc::capnp::messages::BlockValidationState::Reader& reader, - BlockValidationState& dest) -{ - if (reader.getMode() == 0) { - assert(reader.getResult() == 0); - assert(reader.getRejectReason().size() == 0); - assert(reader.getDebugMessage().size() == 0); - } else if (reader.getMode() == 1) { - dest.Invalid(static_cast(reader.getResult()), reader.getRejectReason(), reader.getDebugMessage()); - } else if (reader.getMode() == 2) { - assert(reader.getResult() == 0); - dest.Error(reader.getRejectReason()); - assert(reader.getDebugMessage().size() == 0); - } else { - assert(false); - } -} } // namespace mp diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index 50207c658d8..272245d1ed3 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -1093,6 +1093,11 @@ 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) override + { + return chainman().TestBlockValidity(block, reason, /*check_pow=*/options.check_pow, /*=check_merkle_root=*/options.check_merkle_root); + } + 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/miner.cpp b/src/node/miner.cpp index 33eeaf91fb2..30607b54fc6 100644 --- a/src/node/miner.cpp +++ b/src/node/miner.cpp @@ -176,10 +176,9 @@ std::unique_ptr BlockAssembler::CreateNewBlock() pblock->nNonce = 0; pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]); - BlockValidationState state; - if (m_options.test_block_validity && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, - /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) { - throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString())); + std::string reason; + if (m_options.test_block_validity && !m_chainstate.m_chainman.TestBlockValidity(*pblock, reason, /*check_pow=*/false, /*check_merkle_root=*/false)) { + throw std::runtime_error(strprintf("TestBlockValidity failed: %s", reason)); } const auto time_2{SteadyClock::now()}; diff --git a/src/node/types.h b/src/node/types.h index 0f9b871084a..9d9f96ee345 100644 --- a/src/node/types.h +++ b/src/node/types.h @@ -17,6 +17,7 @@ #include #include #include