Skip to content

Commit 87c9ebd

Browse files
committed
Merge bitcoin/bitcoin#31563: rpc: Extend scope of validation mutex in generateblock
fa63b82 test: generateblocks called by multiple threads (MarcoFalke) fa62c8b rpc: Extend scope of validation mutex in generateblock (MarcoFalke) Pull request description: The mutex (required by TestBlockValidity) must be held after creating the block, until TestBlockValidity is called. Otherwise, it is possible that the chain advances in the meantime and leads to a crash in TestBlockValidity: `Assertion failed: pindexPrev && pindexPrev == chainstate.m_chain.Tip() (validation.cpp: TestBlockValidity: 4338)` Fixes #31562 ACKs for top commit: davidgumberg: reACK bitcoin/bitcoin@fa63b82 achow101: ACK fa63b82 ismaelsadeeq: re-ACK fa63b82 mzumsande: utACK fa63b82 Tree-SHA512: 3dfda1192af52546ab11fbffe44af8713073763863f4a63fbcdbdf95b1c6cbeb003dc4b8b29e7ec67362238ad15e07d8f6855832a0c68dc5370254f8cbf9445c
2 parents df5c643 + fa63b82 commit 87c9ebd

File tree

2 files changed

+22
-13
lines changed

2 files changed

+22
-13
lines changed

src/rpc/mining.cpp

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Copyright (c) 2010 Satoshi Nakamoto
2-
// Copyright (c) 2009-2022 The Bitcoin Core developers
2+
// Copyright (c) 2009-present The Bitcoin Core developers
33
// Distributed under the MIT software license, see the accompanying
44
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
55

@@ -371,22 +371,22 @@ static RPCHelpMan generateblock()
371371

372372
ChainstateManager& chainman = EnsureChainman(node);
373373
{
374-
std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock({.use_mempool = false, .coinbase_output_script = coinbase_output_script})};
375-
CHECK_NONFATAL(block_template);
374+
LOCK(chainman.GetMutex());
375+
{
376+
std::unique_ptr<BlockTemplate> block_template{miner.createNewBlock({.use_mempool = false, .coinbase_output_script = coinbase_output_script})};
377+
CHECK_NONFATAL(block_template);
376378

377-
block = block_template->getBlock();
378-
}
379+
block = block_template->getBlock();
380+
}
379381

380-
CHECK_NONFATAL(block.vtx.size() == 1);
382+
CHECK_NONFATAL(block.vtx.size() == 1);
381383

382-
// Add transactions
383-
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
384-
RegenerateCommitments(block, chainman);
384+
// Add transactions
385+
block.vtx.insert(block.vtx.end(), txs.begin(), txs.end());
386+
RegenerateCommitments(block, chainman);
385387

386-
{
387-
LOCK(::cs_main);
388388
BlockValidationState state;
389-
if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
389+
if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
390390
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
391391
}
392392
}

test/functional/rpc_generate.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#!/usr/bin/env python3
2-
# Copyright (c) 2020-2022 The Bitcoin Core developers
2+
# Copyright (c) 2020-present The Bitcoin Core developers
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test generate* RPCs."""
66

7+
from concurrent.futures import ThreadPoolExecutor
8+
79
from test_framework.test_framework import BitcoinTestFramework
810
from test_framework.wallet import MiniWallet
911
from test_framework.util import (
@@ -83,6 +85,13 @@ def test_generateblock(self):
8385
txid = block['tx'][1]
8486
assert_equal(node.getrawtransaction(txid=txid, verbose=False, blockhash=hash), rawtx)
8587

88+
# Ensure that generateblock can be called concurrently by many threads.
89+
self.log.info('Generate blocks in parallel')
90+
generate_50_blocks = lambda n: [n.generateblock(output=address, transactions=[]) for _ in range(50)]
91+
rpcs = [node.cli for _ in range(6)]
92+
with ThreadPoolExecutor(max_workers=len(rpcs)) as threads:
93+
list(threads.map(generate_50_blocks, rpcs))
94+
8695
self.log.info('Fail to generate block with out of order txs')
8796
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
8897
utxo1 = miniwallet.get_utxo(txid=txid1)

0 commit comments

Comments
 (0)