Skip to content

Commit a74b0f9

Browse files
committed
Have testBlockValidity hold cs_main instead of caller
The goal of interfaces is to eventually run in their own process, so we can't use EXCLUSIVE_LOCKS_REQUIRED in their declaration. However TestBlockValidaty will crash (in its call to ConnectBlock) if the tip changes from under the proposed block. Have the testBlockValidity implementation hold the lock instead, and non-fatally check for this condition.
1 parent f6dc6db commit a74b0f9

File tree

3 files changed

+10
-7
lines changed

3 files changed

+10
-7
lines changed

Diff for: src/interfaces/mining.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class Mining
6767
* @param[in] block the block to validate
6868
* @param[in] check_merkle_root call CheckMerkleRoot()
6969
* @param[out] state details of why a block failed to validate
70-
* @returns false if any of the checks fail
70+
* @returns false if it does not build on the current tip, or any of the checks fail
7171
*/
7272
virtual bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) = 0;
7373

Diff for: src/node/interfaces.cpp

+9-2
Original file line numberDiff line numberDiff line change
@@ -872,8 +872,15 @@ class MinerImpl : public Mining
872872

873873
bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
874874
{
875-
LOCK(::cs_main);
876-
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root);
875+
LOCK(cs_main);
876+
CBlockIndex* tip{chainman().ActiveChain().Tip()};
877+
// Fail if the tip updated before the lock was taken
878+
if (block.hashPrevBlock != tip->GetBlockHash()) {
879+
state.Error("Block does not connect to current chain tip.");
880+
return false;
881+
}
882+
883+
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, tip, /*fCheckPOW=*/false, check_merkle_root);
877884
}
878885

879886
std::unique_ptr<CBlockTemplate> createNewBlock(const CScript& script_pub_key, bool use_mempool) override

Diff for: src/rpc/mining.cpp

-4
Original file line numberDiff line numberDiff line change
@@ -371,8 +371,6 @@ static RPCHelpMan generateblock()
371371

372372
ChainstateManager& chainman = EnsureChainman(node);
373373
{
374-
LOCK(cs_main);
375-
376374
std::unique_ptr<CBlockTemplate> blocktemplate{miner.createNewBlock(coinbase_script, /*use_mempool=*/false)};
377375
if (!blocktemplate) {
378376
throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
@@ -387,8 +385,6 @@ static RPCHelpMan generateblock()
387385
RegenerateCommitments(block, chainman);
388386

389387
{
390-
LOCK(cs_main);
391-
392388
BlockValidationState state;
393389
if (!miner.testBlockValidity(block, /*check_merkle_root=*/false, state)) {
394390
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString()));

0 commit comments

Comments
 (0)