Skip to content

Commit

Permalink
rpc: call TestBlockValidity via miner interface
Browse files Browse the repository at this point in the history
  • Loading branch information
Sjors committed Jun 18, 2024
1 parent 8ecb681 commit d8a3496
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
15 changes: 15 additions & 0 deletions src/interfaces/mining.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -22,6 +25,18 @@ class Mining
//! 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; }
Expand Down
7 changes: 7 additions & 0 deletions src/node/interfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -844,6 +845,12 @@ class MinerImpl : public Mining
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;
Expand Down
14 changes: 8 additions & 6 deletions src/rpc/mining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()));
}
}

Expand Down Expand Up @@ -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";
Expand Down Expand Up @@ -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);
}

Expand All @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion test/functional/rpc_generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ def test_generateblock(self):
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'
Expand Down

0 comments on commit d8a3496

Please sign in to comment.