mirror of https://github.com/bitcoin/bitcoin.git
Add checkBlock to Mining interface
Use it in miner_tests. The getblocktemplate and generateblock RPC calls don't use this, because it would make the code more verbose.
This commit is contained in:
parent
6077157531
commit
94959b8dee
|
@ -114,6 +114,21 @@ public:
|
|||
*/
|
||||
virtual std::unique_ptr<BlockTemplate> createNewBlock(const node::BlockCreateOptions& options = {}) = 0;
|
||||
|
||||
/**
|
||||
* Checks if a given block is valid.
|
||||
*
|
||||
* @param[in] block the block to check
|
||||
* @param[in] options verification options: the proof-of-work check can be
|
||||
* skipped in order to verify a template generated by
|
||||
* external software.
|
||||
* @param[out] reason failure reason (BIP22)
|
||||
* @param[out] debug more detailed rejection reason
|
||||
* @returns whether the block is valid
|
||||
*
|
||||
* For signets the challenge verification is skipped when check_pow is false.
|
||||
*/
|
||||
virtual bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) = 0;
|
||||
|
||||
//! Get internal node context. Useful for RPC and testing,
|
||||
//! but not accessible across processes.
|
||||
virtual node::NodeContext* context() { return nullptr; }
|
||||
|
|
|
@ -18,6 +18,7 @@ interface Mining $Proxy.wrap("interfaces::Mining") {
|
|||
getTip @2 (context :Proxy.Context) -> (result: Common.BlockRef, hasResult: Bool);
|
||||
waitTipChanged @3 (context :Proxy.Context, currentTip: Data, timeout: Float64) -> (result: Common.BlockRef);
|
||||
createNewBlock @4 (options: BlockCreateOptions) -> (result: BlockTemplate);
|
||||
checkBlock @5 (block: Data, options: BlockCheckOptions) -> (reason: Text, debug: Text, result: Bool);
|
||||
}
|
||||
|
||||
interface BlockTemplate $Proxy.wrap("interfaces::BlockTemplate") {
|
||||
|
@ -44,3 +45,8 @@ struct BlockWaitOptions $Proxy.wrap("node::BlockWaitOptions") {
|
|||
timeout @0 : Float64 $Proxy.name("timeout");
|
||||
feeThreshold @1 : Int64 $Proxy.name("fee_threshold");
|
||||
}
|
||||
|
||||
struct BlockCheckOptions $Proxy.wrap("node::BlockCheckOptions") {
|
||||
checkMerkleRoot @0 :Bool $Proxy.name("check_merkle_root");
|
||||
checkPow @1 :Bool $Proxy.name("check_pow");
|
||||
}
|
||||
|
|
|
@ -984,6 +984,15 @@ public:
|
|||
return std::make_unique<BlockTemplateImpl>(assemble_options, BlockAssembler{chainman().ActiveChainstate(), context()->mempool.get(), assemble_options}.CreateNewBlock(), m_node);
|
||||
}
|
||||
|
||||
bool checkBlock(const CBlock& block, const node::BlockCheckOptions& options, std::string& reason, std::string& debug) override
|
||||
{
|
||||
LOCK(chainman().GetMutex());
|
||||
BlockValidationState state{TestBlockValidity(chainman().ActiveChainstate(), block, /*check_pow=*/options.check_pow, /*=check_merkle_root=*/options.check_merkle_root)};
|
||||
reason = state.GetRejectReason();
|
||||
debug = state.GetDebugMessage();
|
||||
return state.IsValid();
|
||||
}
|
||||
|
||||
NodeContext* context() override { return &m_node; }
|
||||
ChainstateManager& chainman() { return *Assert(m_node.chainman); }
|
||||
KernelNotifications& notifications() { return *Assert(m_node.notifications); }
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <cstddef>
|
||||
#include <policy/policy.h>
|
||||
#include <script/script.h>
|
||||
#include <uint256.h>
|
||||
#include <util/time.h>
|
||||
|
||||
namespace node {
|
||||
|
@ -85,6 +86,17 @@ struct BlockWaitOptions {
|
|||
CAmount fee_threshold{MAX_MONEY};
|
||||
};
|
||||
|
||||
struct BlockCheckOptions {
|
||||
/**
|
||||
* Set false to omit the merkle root check
|
||||
*/
|
||||
bool check_merkle_root{true};
|
||||
|
||||
/**
|
||||
* Set false to omit the proof-of-work check
|
||||
*/
|
||||
bool check_pow{true};
|
||||
};
|
||||
} // namespace node
|
||||
|
||||
#endif // BITCOIN_NODE_TYPES_H
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <util/translation.h>
|
||||
#include <validation.h>
|
||||
#include <versionbits.h>
|
||||
#include <pow.h>
|
||||
|
||||
#include <test/util/setup_common.h>
|
||||
|
||||
|
@ -666,7 +667,44 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
|
|||
CScript scriptPubKey = CScript() << "04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"_hex << OP_CHECKSIG;
|
||||
BlockAssembler::Options options;
|
||||
options.coinbase_output_script = scriptPubKey;
|
||||
std::unique_ptr<BlockTemplate> block_template;
|
||||
|
||||
// Create and check a simple template
|
||||
std::unique_ptr<BlockTemplate> block_template = mining->createNewBlock(options);
|
||||
BOOST_REQUIRE(block_template);
|
||||
{
|
||||
CBlock block{block_template->getBlock()};
|
||||
{
|
||||
std::string reason;
|
||||
std::string debug;
|
||||
BOOST_REQUIRE(!mining->checkBlock(block, {.check_pow = false}, reason, debug));
|
||||
BOOST_REQUIRE_EQUAL(reason, "bad-txnmrklroot");
|
||||
BOOST_REQUIRE_EQUAL(debug, "hashMerkleRoot mismatch");
|
||||
}
|
||||
|
||||
block.hashMerkleRoot = BlockMerkleRoot(block);
|
||||
|
||||
{
|
||||
std::string reason;
|
||||
std::string debug;
|
||||
BOOST_REQUIRE(mining->checkBlock(block, {.check_pow = false}, reason, debug));
|
||||
BOOST_REQUIRE_EQUAL(reason, "");
|
||||
BOOST_REQUIRE_EQUAL(debug, "");
|
||||
}
|
||||
|
||||
{
|
||||
// A block template does not have proof-of-work, but it might pass
|
||||
// verification by coincidence. Grind the nonce if needed:
|
||||
while (CheckProofOfWork(block.GetHash(), block.nBits, Assert(m_node.chainman)->GetParams().GetConsensus())) {
|
||||
block.nNonce++;
|
||||
}
|
||||
|
||||
std::string reason;
|
||||
std::string debug;
|
||||
BOOST_REQUIRE(!mining->checkBlock(block, {.check_pow = true}, reason, debug));
|
||||
BOOST_REQUIRE_EQUAL(reason, "high-hash");
|
||||
BOOST_REQUIRE_EQUAL(debug, "proof of work failed");
|
||||
}
|
||||
}
|
||||
|
||||
// We can't make transactions until we have inputs
|
||||
// Therefore, load 110 blocks :)
|
||||
|
|
Loading…
Reference in New Issue