diff --git a/src/interfaces/mining.h b/src/interfaces/mining.h index b96881f67c487..7d71a01450e25 100644 --- a/src/interfaces/mining.h +++ b/src/interfaces/mining.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_INTERFACES_MINING_H #define BITCOIN_INTERFACES_MINING_H +#include #include #include @@ -44,6 +45,7 @@ class Mining * @returns a block template */ virtual std::unique_ptr createNewBlock(const CScript& script_pub_key, bool use_mempool = true) = 0; + /** * Processes new block. A valid new block is automatically relayed to peers. * @@ -62,12 +64,12 @@ class Mining * Only works on top of our current best block. * Does not check proof-of-work. * - * @param[out] state details of why a block failed to validate * @param[in] block the block to validate * @param[in] check_merkle_root call CheckMerkleRoot() - * @returns false if any of the checks fail + * @param[out] state details of why a block failed to validate + * @returns false if it does not build on the current tip, or any of the checks fail */ - virtual bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root = true) = 0; + virtual bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) = 0; //! Get internal node context. Useful for RPC and testing, //! but not accessible across processes. diff --git a/src/node/interfaces.cpp b/src/node/interfaces.cpp index e0bab6e22e80d..fa151407fa0d5 100644 --- a/src/node/interfaces.cpp +++ b/src/node/interfaces.cpp @@ -870,10 +870,17 @@ class MinerImpl : public Mining return context()->mempool->GetTransactionsUpdated(); } - bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root) override + bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override { - LOCK(::cs_main); - return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root); + LOCK(cs_main); + CBlockIndex* tip{chainman().ActiveChain().Tip()}; + // Fail if the tip updated before the lock was taken + if (block.hashPrevBlock != tip->GetBlockHash()) { + state.Error("Block does not connect to current chain tip."); + return false; + } + + return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root); } std::unique_ptr createNewBlock(const CScript& script_pub_key, bool use_mempool) override @@ -881,7 +888,6 @@ class MinerImpl : public Mining BlockAssembler::Options options; ApplyArgsManOptions(gArgs, options); - LOCK(::cs_main); return BlockAssembler{chainman().ActiveChainstate(), use_mempool ? context()->mempool.get() : nullptr, options}.CreateNewBlock(script_pub_key); } diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 2b93c189657d6..7e420dcd9b509 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -371,8 +371,6 @@ static RPCHelpMan generateblock() ChainstateManager& chainman = EnsureChainman(node); { - LOCK(cs_main); - std::unique_ptr blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)}; if (!blocktemplate) { throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block"); @@ -387,10 +385,8 @@ static RPCHelpMan generateblock() RegenerateCommitments(block, chainman); { - LOCK(cs_main); - BlockValidationState state; - if (!miner.testBlockValidity(state, block, /*check_merkle_root=*/false)) { + if (!miner.testBlockValidity(block, /*check_merkle_root=*/false, state)) { throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString())); } } @@ -667,9 +663,7 @@ static RPCHelpMan getblocktemplate() ChainstateManager& chainman = EnsureChainman(node); Mining& miner = EnsureMining(node); LOCK(cs_main); - std::optional maybe_tip{miner.getTipHash()}; - CHECK_NONFATAL(maybe_tip); - uint256 tip{maybe_tip.value()}; + uint256 tip{CHECK_NONFATAL(miner.getTipHash()).value()}; std::string strMode = "template"; UniValue lpval = NullUniValue; @@ -713,7 +707,7 @@ static RPCHelpMan getblocktemplate() return "inconclusive-not-best-prevblk"; } BlockValidationState state; - miner.testBlockValidity(state, block); + miner.testBlockValidity(block, /*check_merkle_root=*/true, state); return BIP22ValidationResult(state); }