mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-03-10 09:06:15 +01:00
Merge bitcoin/bitcoin#31196: Prune mining interface
c991cea1a0
Remove processNewBlock() from mining interface (Sjors Provoost)9a47852d88
Remove getTransactionsUpdated() from mining interface (Sjors Provoost)bfc4e029d4
Remove testBlockValidity() from mining interface (Sjors Provoost) Pull request description: There are three methods in the mining interface that can be dropped. The Template Provider doesn't need them and other application should probably not use them either. 1. `processNewBlock()` was added in7b4d3249ce
, but became unnecessary with the introduction of interfaces::BlockTemplate::submitSolution in7b4d3249ce
. Dropping it was suggested in https://github.com/bitcoin/bitcoin/pull/30200#issuecomment-2404460342 2. `getTransactionsUpdated()`: this is used in the implementation of #31003 `waitFeesChanged`. It's not very useful generically because the mempool updates very frequently. 3. `testBlockValidity()`: it might be useful for mining application to have a way to check the validity of a block template they modified, but the Stratum v2 Template Provider doesn't do that, and this method is a bit brittle (e.g. the block needs to build on the tip). ACKs for top commit: TheCharlatan: Re-ACKc991cea1a0
ryanofsky: Code review ACKc991cea1a0
. Since last review, just rebased to avoid conflicts in surrounding code, and edited a commit message tdb3: code review ACKc991cea1a0
Tree-SHA512: 2138e54f920b26e01c068b24498c6a210c5c4358138dce0702ab58185d9ae148a18f04c97ac9f043646d40f8031618d80a718a176b1ce4779c237de6fb9c4a67
This commit is contained in:
commit
fa0c473d4c
5 changed files with 15 additions and 67 deletions
|
@ -93,31 +93,6 @@ public:
|
||||||
*/
|
*/
|
||||||
virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}) = 0;
|
virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* Processes new block. A valid new block is automatically relayed to peers.
|
|
||||||
*
|
|
||||||
* @param[in] block The block we want to process.
|
|
||||||
* @param[out] new_block A boolean which is set to indicate if the block was first received via this call
|
|
||||||
* @returns If the block was processed, independently of block validity
|
|
||||||
*/
|
|
||||||
virtual bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) = 0;
|
|
||||||
|
|
||||||
//! Return the number of transaction updates in the mempool,
|
|
||||||
//! used to decide whether to make a new block template.
|
|
||||||
virtual unsigned int getTransactionsUpdated() = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check a block is completely valid from start to finish.
|
|
||||||
* Only works on top of our current best block.
|
|
||||||
* Does not check proof-of-work.
|
|
||||||
*
|
|
||||||
* @param[in] block the block to validate
|
|
||||||
* @param[in] check_merkle_root call CheckMerkleRoot()
|
|
||||||
* @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(const CBlock& block, bool check_merkle_root, BlockValidationState& state) = 0;
|
|
||||||
|
|
||||||
//! Get internal node context. Useful for RPC and testing,
|
//! Get internal node context. Useful for RPC and testing,
|
||||||
//! but not accessible across processes.
|
//! but not accessible across processes.
|
||||||
virtual node::NodeContext* context() { return nullptr; }
|
virtual node::NodeContext* context() { return nullptr; }
|
||||||
|
|
|
@ -18,9 +18,6 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
|
||||||
getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool);
|
getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool);
|
||||||
waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef);
|
waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef);
|
||||||
createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate);
|
createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate);
|
||||||
processNewBlock @5 (context :Proxy.Context, block: Data) -> (newBlock: Bool, result: Bool);
|
|
||||||
getTransactionsUpdated @6 (context :Proxy.Context) -> (result: UInt32);
|
|
||||||
testBlockValidity @7 (context :Proxy.Context, block: Data, checkMerkleRoot: Bool) -> (state: BlockValidationState, result: Bool);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
||||||
|
|
|
@ -979,29 +979,6 @@ public:
|
||||||
return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
|
return BlockRef{chainman().ActiveChain().Tip()->GetBlockHash(), chainman().ActiveChain().Tip()->nHeight};
|
||||||
}
|
}
|
||||||
|
|
||||||
bool processNewBlock(const std::shared_ptr<const CBlock>& block, bool* new_block) override
|
|
||||||
{
|
|
||||||
return chainman().ProcessNewBlock(block, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/new_block);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int getTransactionsUpdated() override
|
|
||||||
{
|
|
||||||
return context()->mempool->GetTransactionsUpdated();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool testBlockValidity(const CBlock& block, bool check_merkle_root, BlockValidationState& state) override
|
|
||||||
{
|
|
||||||
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<BlockTemplate> createNewBlock(const BlockCreateOptions& options) override
|
std::unique_ptr<BlockTemplate> createNewBlock(const BlockCreateOptions& options) override
|
||||||
{
|
{
|
||||||
BlockAssembler::Options assemble_options{options};
|
BlockAssembler::Options assemble_options{options};
|
||||||
|
|
|
@ -131,7 +131,7 @@ static RPCHelpMan getnetworkhashps()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
|
static bool GenerateBlock(ChainstateManager& chainman, CBlock&& block, uint64_t& max_tries, std::shared_ptr<const CBlock>& block_out, bool process_new_block)
|
||||||
{
|
{
|
||||||
block_out.reset();
|
block_out.reset();
|
||||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||||
|
@ -151,7 +151,7 @@ static bool GenerateBlock(ChainstateManager& chainman, Mining& miner, CBlock&& b
|
||||||
|
|
||||||
if (!process_new_block) return true;
|
if (!process_new_block) return true;
|
||||||
|
|
||||||
if (!miner.processNewBlock(block_out, nullptr)) {
|
if (!chainman.ProcessNewBlock(block_out, /*force_processing=*/true, /*min_pow_checked=*/true, nullptr)) {
|
||||||
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +166,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, Mining& miner, const
|
||||||
CHECK_NONFATAL(block_template);
|
CHECK_NONFATAL(block_template);
|
||||||
|
|
||||||
std::shared_ptr<const CBlock> block_out;
|
std::shared_ptr<const CBlock> block_out;
|
||||||
if (!GenerateBlock(chainman, miner, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
|
if (!GenerateBlock(chainman, block_template->getBlock(), nMaxTries, block_out, /*process_new_block=*/true)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,16 +384,17 @@ static RPCHelpMan generateblock()
|
||||||
RegenerateCommitments(block, chainman);
|
RegenerateCommitments(block, chainman);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
LOCK(::cs_main);
|
||||||
BlockValidationState state;
|
BlockValidationState state;
|
||||||
if (!miner.testBlockValidity(block, /*check_merkle_root=*/false, state)) {
|
if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/false)) {
|
||||||
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString()));
|
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<const CBlock> block_out;
|
std::shared_ptr<const CBlock> block_out;
|
||||||
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
uint64_t max_tries{DEFAULT_MAX_TRIES};
|
||||||
|
|
||||||
if (!GenerateBlock(chainman, miner, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
|
if (!GenerateBlock(chainman, std::move(block), max_tries, block_out, process_new_block) || !block_out) {
|
||||||
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
|
throw JSONRPCError(RPC_MISC_ERROR, "Failed to make block.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -709,12 +710,12 @@ static RPCHelpMan getblocktemplate()
|
||||||
return "duplicate-inconclusive";
|
return "duplicate-inconclusive";
|
||||||
}
|
}
|
||||||
|
|
||||||
// testBlockValidity only supports blocks built on the current Tip
|
// TestBlockValidity only supports blocks built on the current Tip
|
||||||
if (block.hashPrevBlock != tip) {
|
if (block.hashPrevBlock != tip) {
|
||||||
return "inconclusive-not-best-prevblk";
|
return "inconclusive-not-best-prevblk";
|
||||||
}
|
}
|
||||||
BlockValidationState state;
|
BlockValidationState state;
|
||||||
miner.testBlockValidity(block, /*check_merkle_root=*/true, state);
|
TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), /*fCheckPOW=*/false, /*fCheckMerkleRoot=*/true);
|
||||||
return BIP22ValidationResult(state);
|
return BIP22ValidationResult(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,6 +743,7 @@ static RPCHelpMan getblocktemplate()
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int nTransactionsUpdatedLast;
|
static unsigned int nTransactionsUpdatedLast;
|
||||||
|
const CTxMemPool& mempool = EnsureMemPool(node);
|
||||||
|
|
||||||
if (!lpval.isNull())
|
if (!lpval.isNull())
|
||||||
{
|
{
|
||||||
|
@ -772,7 +774,7 @@ static RPCHelpMan getblocktemplate()
|
||||||
tip = miner.waitTipChanged(hashWatchedChain, checktxtime).hash;
|
tip = miner.waitTipChanged(hashWatchedChain, checktxtime).hash;
|
||||||
// Timeout: Check transactions for update
|
// Timeout: Check transactions for update
|
||||||
// without holding the mempool lock to avoid deadlocks
|
// without holding the mempool lock to avoid deadlocks
|
||||||
if (miner.getTransactionsUpdated() != nTransactionsUpdatedLastLP)
|
if (mempool.GetTransactionsUpdated() != nTransactionsUpdatedLastLP)
|
||||||
break;
|
break;
|
||||||
checktxtime = std::chrono::seconds(10);
|
checktxtime = std::chrono::seconds(10);
|
||||||
}
|
}
|
||||||
|
@ -803,13 +805,13 @@ static RPCHelpMan getblocktemplate()
|
||||||
static int64_t time_start;
|
static int64_t time_start;
|
||||||
static std::unique_ptr<BlockTemplate> block_template;
|
static std::unique_ptr<BlockTemplate> block_template;
|
||||||
if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
|
if (!pindexPrev || pindexPrev->GetBlockHash() != tip ||
|
||||||
(miner.getTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
|
(mempool.GetTransactionsUpdated() != nTransactionsUpdatedLast && GetTime() - time_start > 5))
|
||||||
{
|
{
|
||||||
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
// Clear pindexPrev so future calls make a new block, despite any failures from here on
|
||||||
pindexPrev = nullptr;
|
pindexPrev = nullptr;
|
||||||
|
|
||||||
// Store the pindexBest used before createNewBlock, to avoid races
|
// Store the pindexBest used before createNewBlock, to avoid races
|
||||||
nTransactionsUpdatedLast = miner.getTransactionsUpdated();
|
nTransactionsUpdatedLast = mempool.GetTransactionsUpdated();
|
||||||
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
|
CBlockIndex* pindexPrevNew = chainman.m_blockman.LookupBlockIndex(tip);
|
||||||
time_start = GetTime();
|
time_start = GetTime();
|
||||||
|
|
||||||
|
@ -1032,13 +1034,10 @@ static RPCHelpMan submitblock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NodeContext& node = EnsureAnyNodeContext(request.context);
|
|
||||||
Mining& miner = EnsureMining(node);
|
|
||||||
|
|
||||||
bool new_block;
|
bool new_block;
|
||||||
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
|
auto sc = std::make_shared<submitblock_StateCatcher>(block.GetHash());
|
||||||
CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
|
CHECK_NONFATAL(chainman.m_options.signals)->RegisterSharedValidationInterface(sc);
|
||||||
bool accepted = miner.processNewBlock(blockptr, /*new_block=*/&new_block);
|
bool accepted = chainman.ProcessNewBlock(blockptr, /*force_processing=*/true, /*min_pow_checked=*/true, /*new_block=*/&new_block);
|
||||||
CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
|
CHECK_NONFATAL(chainman.m_options.signals)->UnregisterSharedValidationInterface(sc);
|
||||||
if (!new_block && accepted) {
|
if (!new_block && accepted) {
|
||||||
return "duplicate";
|
return "duplicate";
|
||||||
|
|
|
@ -87,7 +87,7 @@ class RPCGenerateTest(BitcoinTestFramework):
|
||||||
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
|
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
|
||||||
utxo1 = miniwallet.get_utxo(txid=txid1)
|
utxo1 = miniwallet.get_utxo(txid=txid1)
|
||||||
rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
|
rawtx2 = miniwallet.create_self_transfer(utxo_to_spend=utxo1)['hex']
|
||||||
assert_raises_rpc_error(-25, 'testBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
|
assert_raises_rpc_error(-25, 'TestBlockValidity failed: bad-txns-inputs-missingorspent', self.generateblock, node, address, [rawtx2, txid1])
|
||||||
|
|
||||||
self.log.info('Fail to generate block with txid not in mempool')
|
self.log.info('Fail to generate block with txid not in mempool')
|
||||||
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
|
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'
|
||||||
|
|
Loading…
Add table
Reference in a new issue