must be 80 might suggest there is an enforcement of the length somewhere while for example in the test_kernel.cpp appending extra bytes to mainnet_block_1_header won't break the test and extra bytes would just be discarded.
Might be helpful to have the enforcement in btck_block_header_create or revise the doc.
Alternatively we might be able to be explicit about the length in the API (like BlockHash) and have the following changes, adapting both the C API and C++ wrapper:
<details>
<summary>diff</summary>
diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp
--- a/src/kernel/bitcoinkernel.cpp
+++ b/src/kernel/bitcoinkernel.cpp
@@ -1310,10 +1310,10 @@ int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entr
return btck_Chain::get(chain).Contains(&btck_BlockTreeEntry::get(entry)) ? 1 : 0;
}
-btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)
+btck_BlockHeader* btck_block_header_create(const unsigned char raw_block_header[80])
{
auto header{std::make_unique<CBlockHeader>()};
- DataStream stream{std::span{reinterpret_cast<const std::byte*>(raw_block_header), raw_block_header_len}};
+ DataStream stream{std::span<const unsigned char>{raw_block_header, 80}};
try {
stream >> *header;
diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
index 24990772d8..10985ce7c2 100644
--- a/src/kernel/bitcoinkernel.h
+++ b/src/kernel/bitcoinkernel.h
@@ -1643,12 +1643,11 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
/**
* [@brief](/bitcoin-bitcoin/contributor/brief/) Create a btck_BlockHeader from serialized data.
*
- * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header Non-null, serialized header data (80 bytes)
- * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header_len Length of serialized header (must be 80)
- * [@return](/bitcoin-bitcoin/contributor/return/) Block Header, or null on error.
+ * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header Non-null, serialized header data
+ * [@return](/bitcoin-bitcoin/contributor/return/) Block Header, or null on error.
*/
BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
- const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1);
+ const unsigned char raw_block_header[80]) BITCOINKERNEL_ARG_NONNULL(1);
/**
* [@brief](/bitcoin-bitcoin/contributor/brief/) Copy a btck_BlockHeader.
diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h
index f7b956824f..2c92507a2d 100644
--- a/src/kernel/bitcoinkernel_wrapper.h
+++ b/src/kernel/bitcoinkernel_wrapper.h
@@ -755,14 +755,14 @@ public:
class BlockHeader : public Handle<btck_BlockHeader, btck_block_header_copy, btck_block_header_destroy>, public BlockHeaderApi<BlockHeader>
{
public:
- explicit BlockHeader(std::span<const std::byte> raw_header)
- : Handle{btck_block_header_create(reinterpret_cast<const unsigned char*>(raw_header.data()), raw_header.size())} {}
+ explicit BlockHeader(const std::array<std::byte, 80>& raw_header)
+ : Handle{btck_block_header_create(reinterpret_cast<const unsigned char*>(raw_header.data()))} {}
BlockHeader(const BlockHeaderView& view)
: Handle{view} {}
BlockHeader(btck_BlockHeader* ptr)
: Handle{ptr} {}
};
class Block : public Handle<btck_Block, btck_block_copy, btck_block_destroy>
diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp
index 01865ee9d7..239680f06d 100644
--- a/src/test/kernel/test_kernel.cpp
+++ b/src/test/kernel/test_kernel.cpp
@@ -61,6 +61,18 @@ std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
return bytes;
}
+std::array<std::byte, 80> hex_string_to_block_header(std::string_view hex)
+{
+ auto vec = hex_string_to_byte_vec(hex);
+ if (vec.size() != 80) {
+ throw std::invalid_argument("Block header must be exactly 80 bytes");
+ }
+
+ std::array<std::byte, 80> header;
+ std::copy(vec.begin(), vec.end(), header.begin());
+ return header;
+}
+
std::string byte_span_to_hex_string_reversed(std::span<const std::byte> bytes)
{
std::ostringstream oss;
@@ -585,18 +597,14 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
BOOST_AUTO_TEST_CASE(btck_block_header_tests)
{
// Block header format: version(4) + prev_hash(32) + merkle_root(32) + timestamp(4) + bits(4) + nonce(4) = 80 bytes
- BlockHeader header_0{hex_string_to_byte_vec("00e07a26beaaeee2e71d7eb19279545edbaf15de0999983626ec00000000000000000000579cf78b65229bfb93f4a11463af2eaa5ad91780f27f5d147a423bea5f7e4cdf2a47e268b4dd01173a9662ee")};
+ BlockHeader header_0{hex_string_to_block_header("00e07a26beaaeee2e71d7eb19279545edbaf15de0999983626ec00000000000000000000579cf78b65229bfb93f4a11463af2eaa5ad91780f27f5d147a423bea5f7e4cdf2a47e268b4dd01173a9662ee")};
BOOST_CHECK_EQUAL(byte_span_to_hex_string_reversed(header_0.Hash().ToBytes()), "00000000000000000000325c7e14a4ee3b4fcb2343089a839287308a0ddbee4f");
- BlockHeader header_1{hex_string_to_byte_vec("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")};
+ BlockHeader header_1{hex_string_to_block_header("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")};
CheckHandle(header_0, header_1);
- // Test error handling for invalid data
- BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("00")}, std::runtime_error);
-
// Test all header field accessors using mainnet block 1
// Version: 1, Timestamp: 1231469665 (Jan 3, 2009), Bits: 0x1d00ffff, Nonce: 2573394689
- auto mainnet_block_1_header = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299");
- BlockHeader header{mainnet_block_1_header};
+ BlockHeader header{hex_string_to_block_header("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299")};
BOOST_CHECK_EQUAL(header.Version(), 1);
BOOST_CHECK_EQUAL(header.Timestamp(), 1231469665);
BOOST_CHECK_EQUAL(header.Bits(), 0x1d00ffff);
</details>
If the last approach is taken then I think my first comment (https://github.com/bitcoin/bitcoin/pull/33822#discussion_r2623138029) is not applicable anymore.