mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-04-08 14:47:31 +02:00
kernel: Expose context-free block validation
This introduces a context-free validation entry point for full blocks in the kernel C and C++ APIs. * Add `btck_block_check`, a C function that wraps `CheckBlock` and runs header and body checks for a `btck_Block` using `btck_ConsensusParams`. Callers provide a `btck_BlockValidationState` to receive the result and supply a `btck_BlockCheckFlags` bitmask to control POW and merkle-root verification. * Add `btck_BlockCheckFlags` in the C API, plus the corresponding `BlockCheckFlags` scoped enum in the C++ wrapper, including a `*_ALL` convenience value. * Add `Block::Check()` to the C++ wrapper to mirror the new C function and return a bool while filling a `BlockValidationState`. * Add a test `(btck_check_block_context_free)` that verifies a known valid mainnet block passes with `BlockCheckFlags::ALL` and that truncated block data fails deserialization. Co-authored-by: yuvicc <yuvichh01@gmail.com>
This commit is contained in:
@@ -10,6 +10,7 @@
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <test/kernel/block_data.h>
|
||||
#include <test/util/common.h>
|
||||
|
||||
#include <charconv>
|
||||
#include <cstdint>
|
||||
@@ -913,6 +914,65 @@ void chainman_mainnet_validation_test(TestDirectory& test_directory)
|
||||
BOOST_CHECK(!new_block);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(btck_check_block_context_free)
|
||||
{
|
||||
constexpr size_t MERKLE_ROOT_OFFSET{4 + 32};
|
||||
constexpr size_t NBITS_OFFSET{4 + 32 + 32 + 4};
|
||||
constexpr size_t COINBASE_PREVOUT_N_OFFSET{4 + 32 + 32 + 4 + 4 + 4 + 1 + 4 + 1 + 32};
|
||||
|
||||
// Mainnet block 1
|
||||
auto raw_block = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e362990101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff0704ffff001d0104ffffffff0100f2052a0100000043410496b538e853519c726a2c91e61ec11600ae1390813a627c66fb8be7947be63c52da7589379515d4e0a604f8141781e62294721166bf621e73a82cbf2342c858eeac00000000");
|
||||
|
||||
// Context-free block checks still need consensus params for the optional
|
||||
// proof-of-work validation path.
|
||||
ChainParams mainnet_params{ChainType::MAINNET};
|
||||
auto consensus_params = mainnet_params.GetConsensusParams();
|
||||
|
||||
Block block{raw_block};
|
||||
BlockValidationState state;
|
||||
|
||||
BOOST_CHECK(block.Check(consensus_params, BlockCheckFlags::BASE, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);
|
||||
|
||||
BOOST_CHECK(block.Check(consensus_params, BlockCheckFlags::ALL, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);
|
||||
|
||||
auto bad_merkle_block_data = raw_block;
|
||||
bad_merkle_block_data[MERKLE_ROOT_OFFSET] ^= std::byte{0x01};
|
||||
Block bad_merkle_block{bad_merkle_block_data};
|
||||
|
||||
BOOST_CHECK(!bad_merkle_block.Check(consensus_params, BlockCheckFlags::MERKLE, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);
|
||||
BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::MUTATED);
|
||||
|
||||
BOOST_CHECK(bad_merkle_block.Check(consensus_params, BlockCheckFlags::BASE, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);
|
||||
|
||||
auto bad_pow_block_data = raw_block;
|
||||
bad_pow_block_data[NBITS_OFFSET + 3] = std::byte{0x1c};
|
||||
Block bad_pow_block{bad_pow_block_data};
|
||||
|
||||
BOOST_CHECK(!bad_pow_block.Check(consensus_params, BlockCheckFlags::POW, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);
|
||||
BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::INVALID_HEADER);
|
||||
|
||||
BOOST_CHECK(bad_pow_block.Check(consensus_params, BlockCheckFlags::MERKLE, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::VALID);
|
||||
|
||||
auto bad_base_block_data = raw_block;
|
||||
bad_base_block_data[COINBASE_PREVOUT_N_OFFSET] = std::byte{0x00};
|
||||
Block bad_base_block{bad_base_block_data};
|
||||
|
||||
BOOST_CHECK(!bad_base_block.Check(consensus_params, BlockCheckFlags::BASE, state));
|
||||
BOOST_CHECK(state.GetValidationMode() == ValidationMode::INVALID);
|
||||
BOOST_CHECK(state.GetBlockValidationResult() == BlockValidationResult::CONSENSUS);
|
||||
|
||||
// Test with invalid truncated block data.
|
||||
auto truncated_block_data = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299");
|
||||
BOOST_CHECK_EXCEPTION(Block{truncated_block_data}, std::runtime_error,
|
||||
HasReason{"failed to instantiate btck object"});
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(btck_chainman_mainnet_tests)
|
||||
{
|
||||
auto test_directory{TestDirectory{"mainnet_test_bitcoin_kernel"}};
|
||||
|
||||
Reference in New Issue
Block a user