rpc: call TestBlockValidity via miner interface

This commit is contained in:
Sjors Provoost 2024-06-10 17:58:13 +02:00
parent 8ecb681678
commit d8a3496b5a
No known key found for this signature in database
GPG key ID: 57FF9BDBCC301009
4 changed files with 31 additions and 7 deletions

View file

@ -9,6 +9,9 @@ namespace node {
struct NodeContext;
} // namespace node
class BlockValidationState;
class CBlock;
namespace interfaces {
//! Interface giving clients (RPC, Stratum v2 Template Provider in the future)
@ -22,6 +25,18 @@ public:
//! If this chain is exclusively used for testing
virtual bool isTestChain() = 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[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
*/
virtual bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root = true) = 0;
//! Get internal node context. Useful for RPC and testing,
//! but not accessible across processes.
virtual node::NodeContext* context() { return nullptr; }

View file

@ -8,6 +8,7 @@
#include <chain.h>
#include <chainparams.h>
#include <common/args.h>
#include <consensus/validation.h>
#include <deploymentstatus.h>
#include <external_signer.h>
#include <index/blockfilterindex.h>
@ -844,6 +845,12 @@ public:
return chainman().GetParams().IsTestChain();
}
bool testBlockValidity(BlockValidationState& state, const CBlock& block, bool check_merkle_root) override
{
LOCK(::cs_main);
return TestBlockValidity(state, chainman().GetParams(), chainman().ActiveChainstate(), block, chainman().ActiveChain().Tip(), /*fCheckPOW=*/false, check_merkle_root);
}
NodeContext* context() override { return &m_node; }
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
NodeContext& m_node;

View file

@ -339,6 +339,7 @@ static RPCHelpMan generateblock()
}
NodeContext& node = EnsureAnyNodeContext(request.context);
Mining& miner = EnsureMining(node);
const CTxMemPool& mempool = EnsureMemPool(node);
std::vector<CTransactionRef> txs;
@ -389,8 +390,8 @@ static RPCHelpMan generateblock()
LOCK(cs_main);
BlockValidationState state;
if (!TestBlockValidity(state, chainman.GetParams(), chainman.ActiveChainstate(), block, chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock), false, false)) {
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("TestBlockValidity failed: %s", state.ToString()));
if (!miner.testBlockValidity(state, block, /*check_merkle_root=*/false)) {
throw JSONRPCError(RPC_VERIFY_ERROR, strprintf("testBlockValidity failed: %s", state.ToString()));
}
}
@ -664,6 +665,7 @@ static RPCHelpMan getblocktemplate()
{
NodeContext& node = EnsureAnyNodeContext(request.context);
ChainstateManager& chainman = EnsureChainman(node);
Mining& miner = EnsureMining(node);
LOCK(cs_main);
std::string strMode = "template";
@ -706,11 +708,12 @@ static RPCHelpMan getblocktemplate()
}
CBlockIndex* const pindexPrev = active_chain.Tip();
// TestBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash())
// testBlockValidity only supports blocks built on the current Tip
if (block.hashPrevBlock != pindexPrev->GetBlockHash()) {
return "inconclusive-not-best-prevblk";
}
BlockValidationState state;
TestBlockValidity(state, chainman.GetParams(), active_chainstate, block, pindexPrev, false, true);
miner.testBlockValidity(state, block);
return BIP22ValidationResult(state);
}
@ -726,7 +729,6 @@ static RPCHelpMan getblocktemplate()
if (strMode != "template")
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid mode");
Mining& miner = EnsureMining(node);
if (!miner.isTestChain()) {
const CConnman& connman = EnsureConnman(node);
if (connman.GetNodeCount(ConnectionDirection::Both) == 0) {

View file

@ -87,7 +87,7 @@ class RPCGenerateTest(BitcoinTestFramework):
txid1 = miniwallet.send_self_transfer(from_node=node)['txid']
utxo1 = miniwallet.get_utxo(txid=txid1)
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')
missing_txid = '0000000000000000000000000000000000000000000000000000000000000000'