mirror of https://github.com/bitcoin/bitcoin.git
kernel: Add function for copying block data to C header
This adds a function for streaming bytes into a user-owned data structure. Use it in the tests for verifying the implementation of the validation interface's `BlockChecked` method.
This commit is contained in:
parent
fbbec31efc
commit
e3d4d2461e
|
@ -962,6 +962,17 @@ const btck_Transaction* btck_block_get_transaction_at(const btck_Block* block, s
|
||||||
return btck_Transaction::ref(&btck_Block::get(block)->vtx[index]);
|
return btck_Transaction::ref(&btck_Block::get(block)->vtx[index]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int btck_block_to_bytes(const btck_Block* block, btck_WriteBytes writer, void* user_data)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
WriterStream ws{writer, user_data};
|
||||||
|
ws << TX_WITH_WITNESS(*btck_Block::get(block));
|
||||||
|
return 0;
|
||||||
|
} catch (...) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void btck_block_destroy(btck_Block* block)
|
void btck_block_destroy(btck_Block* block)
|
||||||
{
|
{
|
||||||
delete block;
|
delete block;
|
||||||
|
|
|
@ -248,6 +248,11 @@ typedef void (*btck_ValidationInterfacePowValidBlock)(void* user_data, const btc
|
||||||
typedef void (*btck_ValidationInterfaceBlockConnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
|
typedef void (*btck_ValidationInterfaceBlockConnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
|
||||||
typedef void (*btck_ValidationInterfaceBlockDisconnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
|
typedef void (*btck_ValidationInterfaceBlockDisconnected)(void* user_data, btck_Block* block, const btck_BlockTreeEntry* entry);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function signature for serializing data.
|
||||||
|
*/
|
||||||
|
typedef int (*btck_WriteBytes)(const void* bytes, size_t size, void* userdata);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether a validated data structure is valid, invalid, or an error was
|
* Whether a validated data structure is valid, invalid, or an error was
|
||||||
* encountered during processing.
|
* encountered during processing.
|
||||||
|
@ -384,11 +389,6 @@ typedef uint8_t btck_ChainType;
|
||||||
#define btck_ChainType_SIGNET ((btck_ChainType)(3))
|
#define btck_ChainType_SIGNET ((btck_ChainType)(3))
|
||||||
#define btck_ChainType_REGTEST ((btck_ChainType)(4))
|
#define btck_ChainType_REGTEST ((btck_ChainType)(4))
|
||||||
|
|
||||||
/**
|
|
||||||
* Function signature for serializing data.
|
|
||||||
*/
|
|
||||||
typedef int (*btck_WriteBytes)(const void* bytes, size_t size, void* userdata);
|
|
||||||
|
|
||||||
/** @name Transaction
|
/** @name Transaction
|
||||||
* Functions for working with transactions.
|
* Functions for working with transactions.
|
||||||
*/
|
*/
|
||||||
|
@ -965,6 +965,21 @@ BITCOINKERNEL_API size_t BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_count_trans
|
||||||
BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_transaction_at(
|
BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_transaction_at(
|
||||||
const btck_Block* block, size_t transaction_index) BITCOINKERNEL_ARG_NONNULL(1);
|
const btck_Block* block, size_t transaction_index) BITCOINKERNEL_ARG_NONNULL(1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief Serializes the block through the passed in callback to bytes.
|
||||||
|
* This is consensus serialization that is also used for the p2p network.
|
||||||
|
*
|
||||||
|
* @param[in] block Non-null.
|
||||||
|
* @param[in] writer Non-null, callback to a write bytes function.
|
||||||
|
* @param[in] user_data Holds a user-defined opaque structure that will be
|
||||||
|
* passed back through the writer callback.
|
||||||
|
* @return 0 on success.
|
||||||
|
*/
|
||||||
|
BITCOINKERNEL_API int btck_block_to_bytes(
|
||||||
|
const btck_Block* block,
|
||||||
|
btck_WriteBytes writer,
|
||||||
|
void* user_data) BITCOINKERNEL_ARG_NONNULL(1, 2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the block.
|
* Destroy the block.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -551,6 +551,11 @@ public:
|
||||||
return Range<Block, &Block::CountTransactions, &Block::GetTransaction>{*this};
|
return Range<Block, &Block::CountTransactions, &Block::GetTransaction>{*this};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<std::byte> ToBytes() const
|
||||||
|
{
|
||||||
|
return write_bytes(get(), btck_block_to_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
friend class ChainMan;
|
friend class ChainMan;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <span>
|
#include <span>
|
||||||
|
@ -134,9 +135,16 @@ public:
|
||||||
class TestValidationInterface : public ValidationInterface<TestValidationInterface>
|
class TestValidationInterface : public ValidationInterface<TestValidationInterface>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
std::optional<std::vector<std::byte>> m_expected_valid_block = std::nullopt;
|
||||||
|
|
||||||
void BlockChecked(Block block, const BlockValidationState state) override
|
void BlockChecked(Block block, const BlockValidationState state) override
|
||||||
{
|
{
|
||||||
std::cout << "Block checked: ";
|
{
|
||||||
|
auto ser_block{block.ToBytes()};
|
||||||
|
if (m_expected_valid_block.has_value()) {
|
||||||
|
check_equal(m_expected_valid_block.value(), ser_block);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto mode{state.GetValidationMode()};
|
auto mode{state.GetValidationMode()};
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
|
@ -553,8 +561,8 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
|
||||||
BOOST_AUTO_TEST_CASE(btck_block)
|
BOOST_AUTO_TEST_CASE(btck_block)
|
||||||
{
|
{
|
||||||
Block block{as_bytes(REGTEST_BLOCK_DATA[0])};
|
Block block{as_bytes(REGTEST_BLOCK_DATA[0])};
|
||||||
Block block_1{as_bytes(REGTEST_BLOCK_DATA[1])};
|
Block block_100{as_bytes(REGTEST_BLOCK_DATA[100])};
|
||||||
CheckHandle(block, block_1);
|
CheckHandle(block, block_100);
|
||||||
Block block_tx{as_bytes(REGTEST_BLOCK_DATA[205])};
|
Block block_tx{as_bytes(REGTEST_BLOCK_DATA[205])};
|
||||||
CheckRange(block_tx.Transactions(), block_tx.CountTransactions());
|
CheckRange(block_tx.Transactions(), block_tx.CountTransactions());
|
||||||
}
|
}
|
||||||
|
@ -701,10 +709,20 @@ void chainman_mainnet_validation_test(TestDirectory& test_directory)
|
||||||
return tx.CountOutputs();
|
return tx.CountOutputs();
|
||||||
})).begin();
|
})).begin();
|
||||||
BOOST_CHECK_EQUAL(output_counts, 1);
|
BOOST_CHECK_EQUAL(output_counts, 1);
|
||||||
|
|
||||||
|
validation_interface->m_expected_valid_block.emplace(raw_block);
|
||||||
|
auto ser_block{block.ToBytes()};
|
||||||
|
check_equal(ser_block, raw_block);
|
||||||
bool new_block = false;
|
bool new_block = false;
|
||||||
BOOST_CHECK(chainman->ProcessBlock(block, &new_block));
|
BOOST_CHECK(chainman->ProcessBlock(block, &new_block));
|
||||||
BOOST_CHECK(new_block);
|
BOOST_CHECK(new_block);
|
||||||
|
|
||||||
|
validation_interface->m_expected_valid_block = std::nullopt;
|
||||||
|
new_block = false;
|
||||||
|
Block invalid_block{as_bytes(REGTEST_BLOCK_DATA[REGTEST_BLOCK_DATA.size() - 1])};
|
||||||
|
BOOST_CHECK(!chainman->ProcessBlock(invalid_block, &new_block));
|
||||||
|
BOOST_CHECK(!new_block);
|
||||||
|
|
||||||
// If we try to validate it again, it should be a duplicate
|
// If we try to validate it again, it should be a duplicate
|
||||||
BOOST_CHECK(chainman->ProcessBlock(block, &new_block));
|
BOOST_CHECK(chainman->ProcessBlock(block, &new_block));
|
||||||
BOOST_CHECK(!new_block);
|
BOOST_CHECK(!new_block);
|
||||||
|
|
Loading…
Reference in New Issue