kernel: Add block header support and validation #33822

pull yuvicc wants to merge 2 commits into bitcoin:master from yuvicc:2025-11-kernelApi_add_blockheaders changing 5 files +437 −18
  1. yuvicc commented at 5:16 pm on November 7, 2025: contributor

    Adds a new btck_BlockHeader type and associated functions to create, access, and validate block headers. Block headers will have their own type (btck_BlockHeader) that can be created from raw data, copied, and queried for all the standard header fields (hash, prev hash, timestamp, bits, version, nonce). We can also extract headers from full blocks or block tree entries.

    The first commit here refactors BlockValidationState to use Handle/View pattern so external code can own them, which is required for the header processing in the API.

    New Block Header API

    • btck_BlockHeader type: Opaque handle for block headers

    • Header methods:

      • btck_block_header_create(): Create header from 80-byte serialized data

      • btck_block_header_copy(): Copy block headers

      • btck_block_header_destroy(): Destroy header object

      • btck_block_header_get_hash(): Calculate block hash

      • btck_block_header_get_prev_hash(): Get previous block hash

      • btck_block_header_get_timestamp(): Get block timestamp

      • btck_block_header_get_bits(): Get difficulty target (compact format)

      • btck_block_header_get_version(): Get block version

      • btck_block_header_get_nonce(): Get proof-of-work nonce

      • btck_block_get_header(): Extract header from a full block

      • btck_block_tree_entry_get_block_header(): Get header associated with a block tree entry

    • Header Processing Methods:

      • btck_chainstate_manager_process_block_header(): Validates and processes a block header without requiring the full block. This performs proof-of-work verification, timestamp validation, and updates the internal chain state.
      • btck_chainstate_manager_get_best_entry(): Returns the block tree entry with the most cumulative proof-of-work.

    Why btck_chainstate_manager_get_best_entry() is included alongside header validation? Just as we have logic to get the tip for block validation (so you can request more blocks extending your best from your peers), we need the equivalent for header validation. To make header validation worthwhile, knowing what the best current header is seems useful—it tells you what headers to request next from peers.

    Testing

    Added tests in test_kernel.cpp that cover creating headers from raw data, extracting all header fields, and processing headers through the chainstate manager.

    CC @TheCharlatan

  2. DrahtBot commented at 5:16 pm on November 7, 2025: contributor

    The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

    Code Coverage & Benchmarks

    For details see: https://corecheck.dev/bitcoin/bitcoin/pulls/33822.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK sedited, stringintech
    Approach ACK stickies-v
    Stale ACK alexanderwiederin

    If your review is incorrectly listed, please copy-paste <!–meta-tag:bot-skip–> into the comment that the bot should ignore.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #33856 (kernel, validation: Refactor ProcessNewBlockHeaders to return BlockValidationState by yuvicc)

    If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

  3. fanquake renamed this:
    [kernel] Add block header support and validation
    kernel: Add block header support and validation
    on Nov 7, 2025
  4. DrahtBot added the label Validation on Nov 7, 2025
  5. fanquake commented at 5:27 pm on November 7, 2025: member

    https://github.com/bitcoin/bitcoin/actions/runs/19175802541/job/54820162776?pr=33822#step:5:179:

    0<snip>
    1src/kernel/bitcoinkernel.h:1726: * 
    2src/kernel/bitcoinkernel_wrapper.h:759:    
    3src/kernel/bitcoinkernel_wrapper.h:762:    
    4^^^
    5Trailing whitespace (including Windows line endings [CR LF]) is problematic
    
  6. DrahtBot added the label CI failed on Nov 7, 2025
  7. DrahtBot commented at 5:27 pm on November 7, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/actions/runs/19175802541/job/54820162776 LLM reason (✨ experimental): Trailing whitespace detected by lint, causing the CI to fail.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  8. yuvicc force-pushed on Nov 8, 2025
  9. yuvicc commented at 5:20 am on November 8, 2025: contributor
    Fixed some lint errors.
  10. yuvicc force-pushed on Nov 8, 2025
  11. DrahtBot removed the label CI failed on Nov 8, 2025
  12. in src/bitcoin-chainstate.cpp:47 in 86958ee668
    43@@ -44,17 +44,17 @@ class TestValidationInterface : public ValidationInterface
    44 
    45     std::optional<std::string> m_expected_valid_block = std::nullopt;
    46 
    47-    void BlockChecked(const Block block, const BlockValidationState state) override
    48+    void BlockChecked(Block block, const BlockValidationStateView view) override
    


    sedited commented at 11:42 am on November 9, 2025:
    I think the variable name state should just be kept.

    stickies-v commented at 3:33 pm on November 11, 2025:
    This is marked as resolved, but I don’t think this is resolved yet? I agree to keep the state name.
  13. in src/test/kernel/test_kernel.cpp:667 in 86958ee668 outdated
    573@@ -574,6 +574,14 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
    574     }
    575 }
    576 
    577+BOOST_AUTO_TEST_CASE(btck_block_header_tests)
    578+{
    579+    BlockHeader header_0{hex_string_to_byte_vec("00e07a26beaaeee2e71d7eb19279545edbaf15de0999983626ec00000000000000000000579cf78b65229bfb93f4a11463af2eaa5ad91780f27f5d147a423bea5f7e4cdf2a47e268b4dd01173a9662ee")};
    580+    BOOST_CHECK_EQUAL(byte_span_to_hex_string_reversed(header_0.Hash().ToBytes()), "00000000000000000000325c7e14a4ee3b4fcb2343089a839287308a0ddbee4f");
    581+    BlockHeader header_1{hex_string_to_byte_vec("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")};
    


    sedited commented at 1:23 pm on November 9, 2025:
    Can you add BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("00")}, std::runtime_error);?
  14. in src/kernel/bitcoinkernel.cpp:1311 in 86958ee668
    1306+btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)
    1307+{
    1308+    if (raw_block_header_len != 80) {
    1309+        LogError("invalid header length %zu (expected 80)", raw_block_header_len);
    1310+        return nullptr;
    1311+    }
    


    sedited commented at 1:36 pm on November 9, 2025:
    I wouldn’t add this length check here and would instead just rely on the exception. We do the same thing in the rpc too: submitheader just calls DecodeHexBlockHeader, which doesn’t have a length check either.

    stringintech commented at 2:18 pm on December 18, 2025:
    Seems for len > 80 we would not throw though (please see #33822 (review)).

    stringintech commented at 9:09 am on January 1, 2026:

    After taking another look, it makes sense to replicate the behavior of submitheader here (which accepts trailing bytes). Looking across the functional tests, there are multiple usages of the submitheader RPC passing whole block data instead of just the header.

    I was initially confused by DecodeHexTx which IS strict about unconsumed bytes, but notably DecodeHexBlk (for full blocks) also doesn’t enforce this check. The strictness in DecodeTx appears to be related to differentiating between witness vs non-witness transaction formats.

  15. in src/kernel/bitcoinkernel.cpp:1267 in 86958ee668
    1262+    btck_ChainstateManager* chainstate_manager,
    1263+    const btck_BlockHeader* header,
    1264+    btck_BlockValidationState* state)
    1265+{
    1266+    auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
    1267+    auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, true, btck_BlockValidationState::get(state), nullptr);
    


    sedited commented at 1:42 pm on November 9, 2025:
    I saw that in your own patch, you wrapped this call in a try-catch block. As far as I can tell we should not run into an exception here, but maybe it is still better to add it for defensive reasons?

    yancyribbens commented at 4:42 pm on November 9, 2025:
    Isn’t this something the fuzz harness can help answer?

    stringintech commented at 11:57 am on December 18, 2025:

    Re #33822 (review)

    but maybe it is still better to add it for defensive reasons?

    I am not against having the try-catch block, but seeing it next to btck_chainstate_manager_process_block (which doesn’t have try-catch) made me wonder why btck_chainstate_manager_process_block_header gets the special treatment. Is there something that makes ProcessNewBlockHeaders a better fit for this?


    sedited commented at 12:19 pm on December 18, 2025:
    I think that is fair. We are doing a bunch of disk reads that may throw when processing new blocks, so adding a try-catch there too seems like a good idea.
  16. in src/kernel/bitcoinkernel.cpp:1268 in 86958ee668
    1263+    const btck_BlockHeader* header,
    1264+    btck_BlockValidationState* state)
    1265+{
    1266+    auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
    1267+    auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, true, btck_BlockValidationState::get(state), nullptr);
    1268+    return result ? 0 : -1;
    


    sedited commented at 1:54 pm on November 9, 2025:
    One thing that could be considered here is returning the BlockValidationState directly instead of having an in/out param. To safely do that I think we’d need to refactor ProcessNewBlockHeaders though, similarly to what was done in https://github.com/bitcoin/bitcoin/commit/74690f4ed82b1584abb07c0387db0d924c4c0cab. Not sure that is worth it.

    yuvicc commented at 12:02 pm on November 10, 2025:
    This sounds interesting to me.

    yuvicc commented at 5:25 pm on November 11, 2025:
    Opened #33856 to address this.

    yuvicc commented at 6:42 am on November 12, 2025:
    For now I have kept a try-catch block and #33856 can be a potential solution. I will rebase when there’s potential interest for the change. @TheCharlatan
  17. in src/kernel/bitcoinkernel.h:1244 in 86958ee668
    1237@@ -1184,6 +1238,11 @@ BITCOINKERNEL_API void btck_block_destroy(btck_Block* block);
    1238  */
    1239 ///@{
    1240 
    1241+/**
    1242+ * Create a new block validation state.
    1243+ */
    1244+BITCOINKERNEL_API btck_BlockValidationState* btck_block_validation_state_create();
    


    sedited commented at 1:57 pm on November 9, 2025:
    This (and btck_block_validation_state_copy needs BITCOINKERNEL_WARN_UNUSED_RESULT
  18. sedited commented at 2:00 pm on November 9, 2025: contributor
    Approach ACK
  19. Aa777263100 commented at 4:52 pm on November 9, 2025: none

    نعم اريد سحب

    hsan saed abd alwhap

    في الأحد، 9 نوفمبر 2025 7:43 م yancy @.***> كتب:

    @.**** commented on this pull request.

    In src/kernel/bitcoinkernel.cpp https://github.com/bitcoin/bitcoin/pull/33822#discussion_r2508162294:

    @@ -1225,6 +1258,16 @@ int btck_chainstate_manager_process_block( return result ? 0 : -1; }

    +int btck_chainstate_manager_process_block_header(

    • btck_ChainstateManager* chainstate_manager,
    • const btck_BlockHeader* header,
    • btck_BlockValidationState* state) +{
    • auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
    • auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, true, btck_BlockValidationState::get(state), nullptr);

    Isn’t this something the fuzz harness can help answer?

    — Reply to this email directly, view it on GitHub https://github.com/bitcoin/bitcoin/pull/33822#discussion_r2508162294, or unsubscribe https://github.com/notifications/unsubscribe-auth/BVZIU6M4XOH3WNDVIC2JYLD335VLNAVCNFSM6AAAAACLO3ZMFSVHI2DSMVQWIX3LMV43YUDVNRWFEZLROVSXG5CSMV3GSZLXHMZTINBQGEZDOOBQGY . You are receiving this because you are subscribed to this thread.Message ID: @.***>

  20. ?
    added_to_project_v2 sedited
  21. ?
    project_v2_item_status_changed sedited
  22. in src/kernel/bitcoinkernel.h:919 in 86958ee668
    913@@ -904,6 +914,16 @@ BITCOINKERNEL_API void btck_context_destroy(btck_Context* context);
    914 BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_previous(
    915     const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
    916 
    917+/**
    918+ * @brief Return the block header associated with this entry. The returned
    919+ * header is not owned and depends on the lifetime of the block.
    


    stickies-v commented at 3:29 pm on November 11, 2025:

    header is not owned and depends on the lifetime of the block

    I don’t think that’s correct?


    yuvicc commented at 5:35 am on November 12, 2025:
    Yes, Thanks.
  23. in src/test/kernel/test_kernel.cpp:662 in 86958ee668 outdated
    573@@ -574,6 +574,14 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
    574     }
    575 }
    576 
    577+BOOST_AUTO_TEST_CASE(btck_block_header_tests)
    


    stickies-v commented at 3:36 pm on November 11, 2025:
    Would be nice if the test tests the entire block header interface.
  24. stickies-v commented at 3:40 pm on November 11, 2025: contributor

    Approach ACK 86958ee668a950a03d08ef188f2de27137e89b33

    I think the commit can be broken up a bit further, e.g. validationstate logic and chainman logic can be separate I think?

  25. yuvicc force-pushed on Nov 12, 2025
  26. yuvicc commented at 6:38 am on November 12, 2025: contributor

    Thank you @TheCharlatan and @stickies-v for the review.

  27. fanquake referenced this in commit d0da953773 on Nov 12, 2025
  28. in src/kernel/bitcoinkernel.cpp:1258 in bd73ce6dc2
    1256-    if (_new_block) {
    1257-        *_new_block = new_block ? 1 : 0;
    1258+        if (_new_block) {
    1259+            *_new_block = new_block ? 1 : 0;
    1260+        }
    1261+        return result ? 0 : -1;
    


    sedited commented at 6:45 pm on November 14, 2025:
    These lines are needlessly indented.
  29. in src/kernel/bitcoinkernel.cpp:1268 in bd73ce6dc2
    1266+    const btck_BlockHeader* header,
    1267+    btck_BlockValidationState* state)
    1268+{
    1269+   try {
    1270+        auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
    1271+        auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, /*min_pow_checked=*/true, btck_BlockValidationState::get(state), nullptr);
    


    sedited commented at 7:56 pm on November 14, 2025:
    Please also add an inline doc for the nullptr.
  30. in src/kernel/bitcoinkernel.h:1655 in bd73ce6dc2
    1650+/**
    1651+ * @brief Create a block header from serialized data.
    1652+ *
    1653+ * @param[in] raw_block_header        Non-null, serialized header data (80 bytes)
    1654+ * @param[in] raw_block_header_len    Length of serialized header (must be 80)
    1655+ * @return                      Block Header, or null on error. Must be destroyed with btck_block_header_destroy().
    


    sedited commented at 8:24 pm on November 14, 2025:
    The indentation should be fixed here.
  31. in src/test/kernel/test_kernel.cpp:579 in bd73ce6dc2
    573@@ -574,6 +574,53 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
    574     }
    575 }
    576 
    577+BOOST_AUTO_TEST_CASE(btck_block_header_tests)
    578+{
    579+    // Test block header creation and basic operations
    


    sedited commented at 8:27 pm on November 14, 2025:
    I don’t think the comments here add anything, can you remove them again?
  32. yuvicc force-pushed on Nov 16, 2025
  33. yuvicc commented at 6:00 am on November 16, 2025: contributor

    Thanks for the review @TheCharlatan

    • Removed some unnecessary comments and indentation
    • Added inline doc comment
  34. in src/kernel/bitcoinkernel.h:1123 in 0405b37f15 outdated
    1052+ * @param[in] chainstate_manager  Non-null.
    1053+ * @param[in] header    Non-null header to be validated.
    1054+ * @param[out] block_validation_state  The result of the header validation.
    1055+ * @return              0 if header processing completed successfully, non-zero on error.
    1056+ */
    1057+BITCOINKERNEL_API int BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_process_block_header(
    


    stringintech commented at 4:05 pm on November 16, 2025:
    Indentation can be fixed here.
  35. in src/kernel/bitcoinkernel.cpp:860 in 0405b37f15
    854@@ -854,6 +855,21 @@ const btck_BlockTreeEntry* btck_block_tree_entry_get_previous(const btck_BlockTr
    855     return btck_BlockTreeEntry::ref(btck_BlockTreeEntry::get(entry).pprev);
    856 }
    857 
    858+btck_BlockValidationState* btck_block_validation_state_create()
    859+{
    860+    return btck_BlockValidationState::create(BlockValidationState{});
    


    stringintech commented at 4:16 pm on November 16, 2025:

    This can be simplified:

    0    return btck_BlockValidationState::create();
    

    yuvicc commented at 6:01 am on November 17, 2025:
    Correct.
  36. in src/kernel/bitcoinkernel.h:1733 in 0405b37f15 outdated
    1680+ *
    1681+ * @param[in] header    Non-null header
    1682+ * @return              Previous block hash (view, do not destroy)
    1683+ */
    1684+BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_prev_hash(
    1685+    const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    


    stringintech commented at 4:25 pm on November 16, 2025:

    We have usually documented the non-owned pointers this way: The returned X is unowned and only valid for the lifetime of Y.

    0/**
    1 * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the previous block hash from block header. The returned hash is unowned and only valid for the lifetime of the block header.
    2 *
    3 * [@param](/bitcoin-bitcoin/contributor/param/)[in] header    Non-null header
    4 * [@return](/bitcoin-bitcoin/contributor/return/)              Previous block hash
    5 */
    6BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_prev_hash(
    7    const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    
  37. in src/kernel/bitcoinkernel.h:921 in 0405b37f15
    913@@ -904,6 +914,15 @@ BITCOINKERNEL_API void btck_context_destroy(btck_Context* context);
    914 BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_previous(
    915     const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
    916 
    917+/**
    918+ * @brief Return the block header associated with this entry.
    919+ *
    920+ * @param[in] block_tree_entry Non-null.
    921+ * @return                     Block Header, or null on error. Must be destroyed with btck_block_header_destroy().
    


    stringintech commented at 4:34 pm on November 16, 2025:

    Not sure but “Must be destroyed …” docs may not be necessary as we have not documented this for the rest of the owned returned pointers (e.g. btck_Block*).

     0diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
     1index 89b69b849d..a980000968 100644
     2--- a/src/kernel/bitcoinkernel.h
     3+++ b/src/kernel/bitcoinkernel.h
     4@@ -918,7 +918,7 @@ BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT bt
     5  * [@brief](/bitcoin-bitcoin/contributor/brief/) Return the block header associated with this entry.
     6  *
     7  * [@param](/bitcoin-bitcoin/contributor/param/)[in] block_tree_entry Non-null.
     8- * [@return](/bitcoin-bitcoin/contributor/return/)                     Block Header, or null on error. Must be destroyed with btck_block_header_destroy().
     9+ * [@return](/bitcoin-bitcoin/contributor/return/)                     Block Header, or null on error.
    10  */
    11 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_block_header(
    12     const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
    13@@ -1196,7 +1196,7 @@ BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_
    14  * Creates a new block header object from the block's header data.
    15  *
    16  * [@param](/bitcoin-bitcoin/contributor/param/)[in] block Non-null block
    17- * [@return](/bitcoin-bitcoin/contributor/return/)          Block Header, or null on error. Must be destroyed with btck_block_header_destroy().
    18+ * [@return](/bitcoin-bitcoin/contributor/return/)          Block Header, or null on error.
    19  */
    20 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_header(
    21     const btck_Block* block) BITCOINKERNEL_ARG_NONNULL(1);
    22@@ -1652,7 +1652,7 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
    23  *
    24  * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header      Non-null, serialized header data (80 bytes)
    25  * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header_len  Length of serialized header (must be 80)
    26- * [@return](/bitcoin-bitcoin/contributor/return/)                          Block Header, or null on error. Must be destroyed with btck_block_header_destroy().
    27+ * [@return](/bitcoin-bitcoin/contributor/return/)                          Block Header, or null on error.
    28  */
    29 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
    30     const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1);
    31@@ -1661,7 +1661,7 @@ BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_
    32  * [@brief](/bitcoin-bitcoin/contributor/brief/) Copy a block header
    33  *
    34  * [@param](/bitcoin-bitcoin/contributor/param/)[in] header    Non-null header
    35- * [@return](/bitcoin-bitcoin/contributor/return/)              Copied header. Must be destroyed with btck_block_header_destroy().
    36+ * [@return](/bitcoin-bitcoin/contributor/return/)              Copied header.
    37  */
    38 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_copy(
    39     const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    40@@ -1670,7 +1670,7 @@ BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_
    41  * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the block hash.
    42  *
    43  * [@param](/bitcoin-bitcoin/contributor/param/)[in] header    Non-null header
    44- * [@return](/bitcoin-bitcoin/contributor/return/)              Block hash. Must be destroyed btck_block_hash_destroy().
    45+ * [@return](/bitcoin-bitcoin/contributor/return/)              Block hash.
    46  */
    47 BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_hash(
    48     const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    
  38. stringintech commented at 4:45 pm on November 16, 2025: contributor
    Approach ACK
  39. yuvicc force-pushed on Nov 17, 2025
  40. yuvicc force-pushed on Nov 17, 2025
  41. DrahtBot added the label CI failed on Nov 17, 2025
  42. yuvicc commented at 6:11 am on November 17, 2025: contributor

    Thanks for the review @stringintech.

    • Fixed some indentations and removed some extra comments to maintain consistency.
    • Simplified BlockValidationState create method by @stringintech comment
  43. DrahtBot removed the label CI failed on Nov 17, 2025
  44. in src/kernel/bitcoinkernel.h:1050 in 650f0464b3
    1045+ */
    1046+BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_best_entry(
    1047+    const btck_ChainstateManager* chainstate_manager) BITCOINKERNEL_ARG_NONNULL(1);
    1048+
    1049+/**
    1050+ * @brief Processes and validates the passes in block header.
    


    stickies-v commented at 4:05 pm on November 17, 2025:

    typo nit

    0 * [@brief](/bitcoin-bitcoin/contributor/brief/) Processes and validates the provided block header.
    
  45. in src/kernel/bitcoinkernel.h:1199 in 650f0464b3
    1194+ * @brief Get the header from the block.
    1195+ *
    1196+ * Creates a new block header object from the block's header data.
    1197+ *
    1198+ * @param[in] block Non-null block
    1199+ * @return          Block Header, or null on error.
    


    stickies-v commented at 4:18 pm on November 17, 2025:

    nit: inconsistent capitalization

    0 * [@return](/bitcoin-bitcoin/contributor/return/)          Block header, or null on error.
    
  46. in src/kernel/bitcoinkernel.cpp:1320 in 650f0464b3
    1315+    DataStream stream{std::span{reinterpret_cast<const std::byte*>(raw_block_header), raw_block_header_len}};
    1316+
    1317+    try {
    1318+        stream >> *header;
    1319+    } catch (...) {
    1320+        LogDebug(BCLog::KERNEL, "Block header decode failed.");
    


    stickies-v commented at 5:00 pm on November 17, 2025:
    This should be LogError
  47. in src/kernel/bitcoinkernel.h:1112 in 650f0464b3 outdated
    1041+ * known cumulative proof of work.
    1042+ *
    1043+ * @param[in] chainstate_manager Non-null.
    1044+ * @return                       The block tree entry.
    1045+ */
    1046+BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_best_entry(
    


    stickies-v commented at 5:27 pm on November 17, 2025:
    I’m not sure why this function is included in this PR, it doesn’t seem to be related to any of the block header functionality? Would make more sense to leave it out?

    sedited commented at 5:41 pm on November 17, 2025:
    This retrieves the best known header at a time. If you are syncing headers from a peer that seems like useful information to have?

    stickies-v commented at 11:26 am on November 18, 2025:
    It doesn’t return a header, though. I’m not saying we shouldn’t add it, but it is orthogonal to the PR, and it is bundled in an unrelated commit without motivation. I think doing this separately makes more sense, I’d like to think more about how we want to expose this functionality, whereas the actual block header changes are quite straightforward and mechanistic.

    sedited commented at 11:40 am on November 18, 2025:
    I think it should be part of this PR. We should not make changes to the API if we don’t know how completing simple tasks will look like in the future. If there are doubts about how this should be exposed, this seems like the correct place to voice them and come up with something better. Would you be more on favour if it returned the header directly instead of having to retrieve the header from the entry?

    stickies-v commented at 12:09 pm on November 18, 2025:

    We should not make changes to the API if we don’t know how completing simple tasks will look like in the future.

    I agree with that, but I think I’m misunderstanding the purpose of this PR, then. Adding block headers to the API seems like a pretty straightforward addition to the existing API for which imo just the additional introspection ability seems worthwhile, and that’s how I was reviewing it. From your messages, it seems like the actual goal is to implement a specific use case, but that doesn’t seem to be mentioned anywhere? Can you elaborate on what we’re actually trying to achieve here, so people can review and test accordingly? That rationale (and perhaps links to example(s) if they exist) should then also be reflected in the PR description and commit messages.

    Would you be more on favour if it returned the header directly instead of having to retrieve the header from the entry?

    I don’t think so, that seems wasteful.


    sedited commented at 12:36 pm on November 18, 2025:

    From your messages, it seems like the actual goal is to implement a specific use case, but that doesn’t seem to be mentioned anywhere?

    The PR title says add block header support and validation. To make validation worthwhile, knowing what the best current header is, seems useful. Similarly, we added logic to get the tip for block validation, so you can request more blocks extending your best from your peers. Are you looking for a complete header sync implementation first?


    stickies-v commented at 12:58 pm on November 18, 2025:

    Are you looking for a complete header sync implementation first?

    No, that’s not necessary. I’m just highlighting that in my view there’s a gap between what we’re expecting of API changes (having clarity on how the new APIs will be used to achieve goals) and then not document (in PR or commits) how we’re expecting the API to be used. Just “validation” seems concise.

    Anyway, it seems like I’m bringing stop energy and that was not the goal, so I’ll take a break here and perhaps revisit later.


    sedited commented at 1:00 pm on November 18, 2025:

    No, that’s not necessary

    I think that would be perfectly reasonable as a prerequisite for these kind of deep changes actually. The commit and PR description should be updated too to better explain what is going on with the validation changes here in my view.


    yuvicc commented at 1:04 pm on November 18, 2025:
    Makes sense @TheCharlatan @stickies-v, I will update the PR description for better understanding of the changes here.

    sedited commented at 8:38 pm on November 25, 2025:
    I added a simple headers-first sync mechanism to kernel-node here: https://github.com/TheCharlatan/kernel-node/pull/23
  48. in src/test/kernel/test_kernel.cpp:612 in 650f0464b3
    607+
    608+    // Test previous block hash
    609+    auto prev_hash = header.PrevHash();
    610+    BOOST_CHECK_EQUAL(byte_span_to_hex_string_reversed(prev_hash.ToBytes()), "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f");
    611+
    612+    // Test header from Block::GetHeader()
    


    stickies-v commented at 5:28 pm on November 17, 2025:
    These docstrings don’t add any value imo.
  49. yuvicc force-pushed on Nov 18, 2025
  50. yuvicc commented at 1:15 pm on November 18, 2025: contributor

    Thanks for the review @stickies-v

    • Address usage of LogError instead of LogDebug comment
    • Addressed some nits and removed docstrings.
  51. yuvicc force-pushed on Nov 18, 2025
  52. yuvicc commented at 2:36 pm on November 18, 2025: contributor
    Updated commit message an PR description to better reflect the changes and intention as suggested by @TheCharlatan @stickies-v.
  53. DrahtBot added the label CI failed on Nov 18, 2025
  54. yuvicc force-pushed on Nov 22, 2025
  55. yuvicc commented at 12:34 pm on November 22, 2025: contributor
    Rebased to fix the CI error. For reference check #33884.
  56. DrahtBot removed the label CI failed on Nov 22, 2025
  57. in src/kernel/bitcoinkernel_wrapper.h:827 in 159c51f361 outdated
    823@@ -824,36 +824,50 @@ class KernelNotifications
    824     virtual void FatalErrorHandler(std::string_view error) {}
    825 };
    826 
    827-class BlockValidationState
    828+template<typename Derived>
    


    sedited commented at 12:14 pm on November 27, 2025:
    Nit (clang-format-diff): Needs a whitespace after template.
  58. in src/kernel/bitcoinkernel.cpp:1279 in 10389bcfcf
    1270@@ -1253,6 +1271,22 @@ int btck_chainstate_manager_process_block(
    1271     return result ? 0 : -1;
    1272 }
    1273 
    1274+int btck_chainstate_manager_process_block_header(
    1275+    btck_ChainstateManager* chainstate_manager,
    1276+    const btck_BlockHeader* header,
    1277+    btck_BlockValidationState* state)
    1278+{
    1279+   try {
    


    sedited commented at 12:18 pm on November 27, 2025:
    Nit (clang-format-diff): Missing whitespace.
  59. in src/kernel/bitcoinkernel.h:1640 in 10389bcfcf
    1633@@ -1581,6 +1634,92 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
    1634 
    1635 ///@}
    1636 
    1637+/**
    1638+ * @name Block Header
    1639+ * Functions for working with block headers.
    1640+*/
    


    sedited commented at 12:19 pm on November 27, 2025:
    Nit (clang-format-diff): Missing whitespace to align the comment close.
  60. sedited approved
  61. sedited commented at 12:20 pm on November 27, 2025: contributor
    ACK 10389bcfcf3eb92a08ff1fafab86db89749520c2
  62. DrahtBot requested review from stringintech on Nov 27, 2025
  63. DrahtBot requested review from stickies-v on Nov 27, 2025
  64. yuvicc force-pushed on Nov 27, 2025
  65. yuvicc commented at 6:00 pm on November 27, 2025: contributor
    • Addressed some clang-format nits
    • Updated the comments to use struct name instead of raw names as suggested by @stickies-v.
  66. sedited approved
  67. sedited commented at 8:11 pm on November 27, 2025: contributor
    re-ACK 30367c1b3e7e94ed59d0a3ee816da14a3ee0424f
  68. in src/kernel/bitcoinkernel.cpp:1307 in 30367c1b3e outdated
    1276+    const btck_BlockHeader* header,
    1277+    btck_BlockValidationState* state)
    1278+{
    1279+    try {
    1280+        auto& chainman = btck_ChainstateManager::get(chainstate_manager).m_chainman;
    1281+        auto result = chainman->ProcessNewBlockHeaders({&btck_BlockHeader::get(header), 1}, /*min_pow_checked=*/true, btck_BlockValidationState::get(state), /*ppindex=*/nullptr);
    


    alexanderwiederin commented at 11:23 am on December 5, 2025:

    I noticed that ProcessNewBlockHeaders is called with min_pow_checked hard-coded to true.

    Was this an intentional design choice? If callers are not supposed to to control this, it might be good to mention in the function docs that min-pow checks are never performed.

    Otherwise, should we have min_pow checks be an option for btck_chainstate_manager_process_block_header?


    sedited commented at 11:51 am on December 5, 2025:

    This is on purpose from my part. I think it is confusing and not helpful to expose. If you look at where it is used, you’ll see that all it does is invalidate a header that does not extend the pre-synced best work chain. The only case it is still used in our code is when processing unrequested blocks, but since we’re processing headers here, I don’t think that is relevant. I also don’t think that this should be documented either. The current min_pow_checked handling in our validation code is confusing and noisy, and should be refactored and improved in my opinion.

    EDIT: Also note that the same is done for the currently exposed RPC call for processing a header: https://github.com/bitcoin/bitcoin/blob/master/src/rpc/mining.cpp#L1127


    sedited commented at 5:23 pm on December 6, 2025:
    Removed the arg in #34022.
  69. alexanderwiederin commented at 11:25 am on December 5, 2025: none
    Concept ACK
  70. in src/kernel/bitcoinkernel.cpp:1345 in 30367c1b3e
    1308@@ -1260,3 +1309,58 @@ int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entr
    1309     LOCK(::cs_main);
    1310     return btck_Chain::get(chain).Contains(&btck_BlockTreeEntry::get(entry)) ? 1 : 0;
    1311 }
    1312+
    1313+btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)
    1314+{
    1315+    auto header{std::make_unique<CBlockHeader>()};
    1316+    DataStream stream{std::span{reinterpret_cast<const std::byte*>(raw_block_header), raw_block_header_len}};
    


    stringintech commented at 12:43 pm on December 16, 2025:

    It seems we have to drop BITCOINKERNEL_ARG_NONNULL from the header and add the following check (#33853):

    0if (raw_block_header == nullptr && raw_block_header_len != 0) {
    1	return nullptr;
    2}
    

    Also adding test coverage would be nice.

  71. in src/kernel/bitcoinkernel.cpp:1370 in 30367c1b3e outdated
    1336+}
    1337+
    1338+const btck_BlockHash* btck_block_header_get_prev_hash(const btck_BlockHeader* header)
    1339+{
    1340+    return btck_BlockHash::ref(&btck_BlockHeader::get(header).hashPrevBlock);
    1341+}
    


    stringintech commented at 12:48 pm on December 16, 2025:

    I am thinking (not sure) if it is better to check for zero hashPrevBlock here and return nullptr? Also:

    • Adapting the cpp wrapper to return optional (like BlockTreeEntry.GetPrevious()) and adding test coverage for genesis block.
    • Adapting the header doc to mention the behavior (like how btck_block_tree_entry_get_previous is documented)

    yuvicc commented at 5:49 am on December 18, 2025:
    friendly ping! @sedited.

    sedited commented at 11:34 am on December 18, 2025:
    I don’t think this is quite analog to the GetPrevious method. The complete genesis header is serialized with a 0 prev block, but I think that has a specific meaning. Then again, we do skip the prev block field in getblock’s output too if it is 0. I tend towards keeping it as is, because external applications can then just directly use this to initialize their own network-serializable block header, without needing to apply extra logic.
  72. in src/kernel/bitcoinkernel.h:978 in 30367c1b3e outdated
    930+ *
    931+ * @param[in] block_tree_entry Non-null.
    932+ * @return                     btck_BlockHeader, or null on error.
    933+ */
    934+BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_tree_entry_get_block_header(
    935+    const btck_BlockTreeEntry* block_tree_entry) BITCOINKERNEL_ARG_NONNULL(1);
    


    stringintech commented at 12:55 pm on December 16, 2025:
    Seems or null on error should be dropped, since this cannot return null.
  73. in src/kernel/bitcoinkernel.h:1268 in 30367c1b3e outdated
    1209+ *
    1210+ * @param[in] block Non-null block
    1211+ * @return          Block header, or null on error.
    1212+ */
    1213+BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_header(
    1214+    const btck_Block* block) BITCOINKERNEL_ARG_NONNULL(1);
    


    stringintech commented at 12:58 pm on December 16, 2025:
    Seems or null on error should be dropped, since this cannot return null.
  74. in src/kernel/bitcoinkernel.h:1733 in 30367c1b3e outdated
    1673+ *
    1674+ * @param[in] header    Non-null btck_BlockHeader
    1675+ * @return              Previous btck_BlockHash (view, do not destroy)
    1676+ */
    1677+BITCOINKERNEL_API const btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_prev_hash(
    1678+    const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    


    stringintech commented at 1:08 pm on December 16, 2025:
    Please see #33822 (review).
  75. in src/kernel/bitcoinkernel_wrapper.h:765 in 30367c1b3e
    760+
    761+    BlockHeader(const BlockHeaderView& view)
    762+        : Handle{view} {}
    763+
    764+    BlockHeader(btck_BlockHeader* ptr)
    765+        : Handle{ptr} {}
    


    stringintech commented at 1:17 pm on December 16, 2025:

    nit (to keep it consistent with the naming of other handles ctors)

    0    BlockHeader(btck_BlockHeader* header) : Handle{header} {}
    
  76. in src/kernel/bitcoinkernel_wrapper.h:945 in 30367c1b3e
    952     virtual ~ValidationInterface() = default;
    953 
    954-    virtual void BlockChecked(Block block, const BlockValidationState state) {}
    955+    virtual void BlockChecked(Block block, const BlockValidationStateView state) {}
    956 
    957     virtual void PowValidBlock(BlockTreeEntry entry, Block block) {}
    


    stringintech commented at 1:33 pm on December 16, 2025:
    I think we can drop const. We haven’t enforced it for BlockTreeEntry which is also a view. (Also for BlockChecked definitions in bitcoin-chainstate.cpp and test_kernel.cpp) It seems throughout the wrapper, we haven’t stated const-ness for functions returning views either.
  77. in src/kernel/bitcoinkernel.cpp:1313 in 30367c1b3e outdated
    1282+
    1283+        return result ? 0 : -1;
    1284+    } catch (std::exception& e) {
    1285+        LogError("Failed to process block header: %s", e.what());
    1286+        return -1;
    1287+    }
    


    stringintech commented at 1:40 pm on December 16, 2025:
    Why we catch exceptions here? or where ProcessNewBlockHeaders() might throw?

    yuvicc commented at 5:09 am on December 18, 2025:
    Correct we don’t run into exceptions here but its better to keep for defensive reason. see #33822 (review)
  78. in src/kernel/bitcoinkernel.h:1651 in 30367c1b3e
    1646+ * @param[in] raw_block_header      Non-null, serialized header data (80 bytes)
    1647+ * @param[in] raw_block_header_len  Length of serialized header (must be 80)
    1648+ * @return                          Block Header, or null on error.
    1649+ */
    1650+BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
    1651+    const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1);
    


    stringintech commented at 1:57 pm on December 16, 2025:

    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:

      0diff --git a/src/kernel/bitcoinkernel.cpp b/src/kernel/bitcoinkernel.cpp
      1--- a/src/kernel/bitcoinkernel.cpp
      2+++ b/src/kernel/bitcoinkernel.cpp
      3@@ -1310,10 +1310,10 @@ int btck_chain_contains(const btck_Chain* chain, const btck_BlockTreeEntry* entr
      4     return btck_Chain::get(chain).Contains(&btck_BlockTreeEntry::get(entry)) ? 1 : 0;
      5 }
      6 
      7-btck_BlockHeader* btck_block_header_create(const void* raw_block_header, size_t raw_block_header_len)
      8+btck_BlockHeader* btck_block_header_create(const unsigned char raw_block_header[80])
      9 {
     10     auto header{std::make_unique<CBlockHeader>()};
     11-    DataStream stream{std::span{reinterpret_cast<const std::byte*>(raw_block_header), raw_block_header_len}};
     12+    DataStream stream{std::span<const unsigned char>{raw_block_header, 80}};
     13 
     14     try {
     15         stream >> *header;
     16diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
     17index 24990772d8..10985ce7c2 100644
     18--- a/src/kernel/bitcoinkernel.h
     19+++ b/src/kernel/bitcoinkernel.h
     20@@ -1643,12 +1643,11 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
     21 /**
     22  * [@brief](/bitcoin-bitcoin/contributor/brief/) Create a btck_BlockHeader from serialized data.
     23  *
     24- * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header      Non-null, serialized header data (80 bytes)
     25- * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header_len  Length of serialized header (must be 80)
     26- * [@return](/bitcoin-bitcoin/contributor/return/)                          Block Header, or null on error.
     27+ * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header  Non-null, serialized header data
     28+ * [@return](/bitcoin-bitcoin/contributor/return/)                      Block Header, or null on error.
     29  */
     30 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
     31-    const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1);
     32+    const unsigned char raw_block_header[80]) BITCOINKERNEL_ARG_NONNULL(1);
     33 
     34 /**
     35  * [@brief](/bitcoin-bitcoin/contributor/brief/) Copy a btck_BlockHeader.
     36diff --git a/src/kernel/bitcoinkernel_wrapper.h b/src/kernel/bitcoinkernel_wrapper.h
     37index f7b956824f..2c92507a2d 100644
     38--- a/src/kernel/bitcoinkernel_wrapper.h
     39+++ b/src/kernel/bitcoinkernel_wrapper.h
     40@@ -755,14 +755,14 @@ public:
     41 class BlockHeader : public Handle<btck_BlockHeader, btck_block_header_copy, btck_block_header_destroy>, public BlockHeaderApi<BlockHeader>
     42 {
     43 public:
     44-    explicit BlockHeader(std::span<const std::byte> raw_header)
     45-        : Handle{btck_block_header_create(reinterpret_cast<const unsigned char*>(raw_header.data()), raw_header.size())} {}
     46+    explicit BlockHeader(const std::array<std::byte, 80>& raw_header)
     47+        : Handle{btck_block_header_create(reinterpret_cast<const unsigned char*>(raw_header.data()))} {}
     48 
     49     BlockHeader(const BlockHeaderView& view)
     50         : Handle{view} {}
     51 
     52     BlockHeader(btck_BlockHeader* ptr)
     53         : Handle{ptr} {}
     54 };
     55 
     56 class Block : public Handle<btck_Block, btck_block_copy, btck_block_destroy>
     57diff --git a/src/test/kernel/test_kernel.cpp b/src/test/kernel/test_kernel.cpp
     58index 01865ee9d7..239680f06d 100644
     59--- a/src/test/kernel/test_kernel.cpp
     60+++ b/src/test/kernel/test_kernel.cpp
     61@@ -61,6 +61,18 @@ std::vector<std::byte> hex_string_to_byte_vec(std::string_view hex)
     62     return bytes;
     63 }
     64 
     65+std::array<std::byte, 80> hex_string_to_block_header(std::string_view hex)
     66+{
     67+    auto vec = hex_string_to_byte_vec(hex);
     68+    if (vec.size() != 80) {
     69+        throw std::invalid_argument("Block header must be exactly 80 bytes");
     70+    }
     71+
     72+    std::array<std::byte, 80> header;
     73+    std::copy(vec.begin(), vec.end(), header.begin());
     74+    return header;
     75+}
     76+
     77 std::string byte_span_to_hex_string_reversed(std::span<const std::byte> bytes)
     78 {
     79     std::ostringstream oss;
     80@@ -585,18 +597,14 @@ BOOST_AUTO_TEST_CASE(btck_context_tests)
     81 BOOST_AUTO_TEST_CASE(btck_block_header_tests)
     82 {
     83     // Block header format: version(4) + prev_hash(32) + merkle_root(32) + timestamp(4) + bits(4) + nonce(4) = 80 bytes
     84-    BlockHeader header_0{hex_string_to_byte_vec("00e07a26beaaeee2e71d7eb19279545edbaf15de0999983626ec00000000000000000000579cf78b65229bfb93f4a11463af2eaa5ad91780f27f5d147a423bea5f7e4cdf2a47e268b4dd01173a9662ee")};
     85+    BlockHeader header_0{hex_string_to_block_header("00e07a26beaaeee2e71d7eb19279545edbaf15de0999983626ec00000000000000000000579cf78b65229bfb93f4a11463af2eaa5ad91780f27f5d147a423bea5f7e4cdf2a47e268b4dd01173a9662ee")};
     86     BOOST_CHECK_EQUAL(byte_span_to_hex_string_reversed(header_0.Hash().ToBytes()), "00000000000000000000325c7e14a4ee3b4fcb2343089a839287308a0ddbee4f");
     87-    BlockHeader header_1{hex_string_to_byte_vec("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")};
     88+    BlockHeader header_1{hex_string_to_block_header("00c00020e7cb7b4de21d26d55bd384017b8bb9333ac3b2b55bed00000000000000000000d91b4484f801b99f03d36b9d26cfa83420b67f81da12d7e6c1e7f364e743c5ba9946e268b4dd011799c8533d")};
     89     CheckHandle(header_0, header_1);
     90 
     91-    // Test error handling for invalid data
     92-    BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("00")}, std::runtime_error);
     93-
     94     // Test all header field accessors using mainnet block 1
     95     // Version: 1, Timestamp: 1231469665 (Jan 3, 2009), Bits: 0x1d00ffff, Nonce: 2573394689
     96-    auto mainnet_block_1_header = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299");
     97-    BlockHeader header{mainnet_block_1_header};
     98+    BlockHeader header{hex_string_to_block_header("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299")};
     99     BOOST_CHECK_EQUAL(header.Version(), 1);
    100     BOOST_CHECK_EQUAL(header.Timestamp(), 1231469665);
    101     BOOST_CHECK_EQUAL(header.Bits(), 0x1d00ffff);
    

    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.


    yuvicc commented at 5:47 am on December 18, 2025:
    I think the previous approach seems like a better match and consistent with the rest of the codebase.

    stringintech commented at 2:22 pm on December 18, 2025:
    Just noticed a previous related review comment: #33822 (review)
  79. in src/test/kernel/test_kernel.cpp:675 in 30367c1b3e
    593+    // Test error handling for invalid data
    594+    BOOST_CHECK_THROW(BlockHeader{hex_string_to_byte_vec("00")}, std::runtime_error);
    595+
    596+    // Test all header field accessors using mainnet block 1
    597+    // Version: 1, Timestamp: 1231469665 (Jan 3, 2009), Bits: 0x1d00ffff, Nonce: 2573394689
    598+    auto mainnet_block_1_header = hex_string_to_byte_vec("010000006fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000982051fd1e4ba744bbbe680e1fee14677ba1a3c3540bf7b1cdb606e857233e0e61bc6649ffff001d01e36299");
    


    stringintech commented at 1:59 pm on December 16, 2025:
    Second line of the comment seems redundant.
  80. in src/kernel/bitcoinkernel.h:1053 in 30367c1b3e
    1047@@ -1029,6 +1048,29 @@ BITCOINKERNEL_API void btck_chainstate_manager_options_destroy(btck_ChainstateMa
    1048 BITCOINKERNEL_API btck_ChainstateManager* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_create(
    1049     const btck_ChainstateManagerOptions* chainstate_manager_options) BITCOINKERNEL_ARG_NONNULL(1);
    1050 
    1051+/**
    1052+ * @brief Get the block tree entry whose associated block header has the most
    1053+ * known cumulative proof of work.
    


    stringintech commented at 2:51 pm on December 16, 2025:

    Some cases that using the opaque struct name might be better (there might be others):

     0diff --git a/src/kernel/bitcoinkernel.h b/src/kernel/bitcoinkernel.h
     1--- a/src/kernel/bitcoinkernel.h
     2+++ b/src/kernel/bitcoinkernel.h
     3@@ -1049,20 +1049,20 @@ BITCOINKERNEL_API btck_ChainstateManager* BITCOINKERNEL_WARN_UNUSED_RESULT btck_
     4     const btck_ChainstateManagerOptions* chainstate_manager_options) BITCOINKERNEL_ARG_NONNULL(1);
     5 
     6 /**
     7- * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the block tree entry whose associated block header has the most
     8+ * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the btck_BlockTreeEntry whose associated block header has the most
     9  * known cumulative proof of work.
    10  *
    11  * [@param](/bitcoin-bitcoin/contributor/param/)[in] chainstate_manager Non-null.
    12- * [@return](/bitcoin-bitcoin/contributor/return/)                       The block tree entry.
    13+ * [@return](/bitcoin-bitcoin/contributor/return/)                       btck_BlockTreeEntry.
    14  */
    15 BITCOINKERNEL_API const btck_BlockTreeEntry* BITCOINKERNEL_WARN_UNUSED_RESULT btck_chainstate_manager_get_best_entry(
    16     const btck_ChainstateManager* chainstate_manager) BITCOINKERNEL_ARG_NONNULL(1);
    17 
    18 /**
    19- * [@brief](/bitcoin-bitcoin/contributor/brief/) Processes and validates the provided block header.
    20+ * [@brief](/bitcoin-bitcoin/contributor/brief/) Processes and validates the provided btck_BlockHeader.
    21  *
    22  * [@param](/bitcoin-bitcoin/contributor/param/)[in] chainstate_manager        Non-null.
    23- * [@param](/bitcoin-bitcoin/contributor/param/)[in] header                    Non-null header to be validated.
    24+ * [@param](/bitcoin-bitcoin/contributor/param/)[in] header                    Non-null btck_BlockHeader to be validated.
    25  * [@param](/bitcoin-bitcoin/contributor/param/)[out] block_validation_state   The result of the header validation.
    26  * [@return](/bitcoin-bitcoin/contributor/return/)                              0 if header processing completed successfully, non-zero on error.
    27  */
    28@@ -1203,12 +1203,12 @@ BITCOINKERNEL_API const btck_Transaction* BITCOINKERNEL_WARN_UNUSED_RESULT btck_
    29     const btck_Block* block, size_t transaction_index) BITCOINKERNEL_ARG_NONNULL(1);
    30 
    31 /**
    32- * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the header from the block.
    33+ * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the btck_BlockHeader from the block.
    34  *
    35  * Creates a new block header object from the block's header data.
    36  *
    37- * [@param](/bitcoin-bitcoin/contributor/param/)[in] block Non-null block
    38- * [@return](/bitcoin-bitcoin/contributor/return/)          Block header, or null on error.
    39+ * [@param](/bitcoin-bitcoin/contributor/param/)[in] block Non-null btck_Block.
    40+ * [@return](/bitcoin-bitcoin/contributor/return/)          btck_BlockHeader, or null on error.
    41  */
    42 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_get_header(
    43     const btck_Block* block) BITCOINKERNEL_ARG_NONNULL(1);
    44@@ -1645,7 +1645,7 @@ BITCOINKERNEL_API void btck_block_hash_destroy(btck_BlockHash* block_hash);
    45  *
    46  * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header      Non-null, serialized header data (80 bytes)
    47  * [@param](/bitcoin-bitcoin/contributor/param/)[in] raw_block_header_len  Length of serialized header (must be 80)
    48- * [@return](/bitcoin-bitcoin/contributor/return/)                          Block Header, or null on error.
    49+ * [@return](/bitcoin-bitcoin/contributor/return/)                          btck_BlockHeader, or null on error.
    50  */
    51 BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_create(
    52     const void* raw_block_header, size_t raw_block_header_len) BITCOINKERNEL_ARG_NONNULL(1);
    53@@ -1662,8 +1662,8 @@ BITCOINKERNEL_API btck_BlockHeader* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_
    54 /**
    55  * [@brief](/bitcoin-bitcoin/contributor/brief/) Get the btck_BlockHash.
    56  *
    57- * [@param](/bitcoin-bitcoin/contributor/param/)[in] header    Non-null header
    58- * [@return](/bitcoin-bitcoin/contributor/return/)              Block hash.
    59+ * [@param](/bitcoin-bitcoin/contributor/param/)[in] header    Non-null btck_BlockHeader.
    60+ * [@return](/bitcoin-bitcoin/contributor/return/)              btck_BlockHash.
    61  */
    62 BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_hash(
    63     const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    
  81. DrahtBot requested review from stringintech on Dec 16, 2025
  82. DrahtBot added the label Needs rebase on Dec 27, 2025
  83. kernel: Add Handle/View pattern for BlockValidationState
    Add C API functions for managing BlockValidationState lifecycle:
      - btck_block_validation_state_create()
      - btck_block_validation_state_copy()
      - btck_block_validation_state_destroy()
    
    Introduce BlockValidationStateApi<> template to share common getter methods between BlockValidationState (Handle) and BlockValidationStateView (View) classes in the C++ wrapper. This enables external code to create and own BlockValidationState objects needed for the new process_block_header() API.
    
    Co-authored-by: TheCharlatan <seb.kung@gmail.com>
    27a3e3de72
  84. yuvicc force-pushed on Dec 29, 2025
  85. yuvicc force-pushed on Dec 29, 2025
  86. DrahtBot added the label CI failed on Dec 29, 2025
  87. DrahtBot commented at 9:09 am on December 29, 2025: contributor

    🚧 At least one of the CI tasks failed. Task lint: https://github.com/bitcoin/bitcoin/actions/runs/20568596692/job/59071182413 LLM reason (✨ experimental): Lint failure: tabs used for whitespace (tabs_whitespace) in src/kernel/bitcoinkernel.cpp, causing CI to fail.

    Try to run the tests locally, according to the documentation. However, a CI failure may still happen due to a number of reasons, for example:

    • Possibly due to a silent merge conflict (the changes in this pull request being incompatible with the current code in the target branch). If so, make sure to rebase on the latest commit of the target branch.

    • A sanitizer issue, which can only be found by compiling with the sanitizer and running the affected test.

    • An intermittent issue.

    Leave a comment here, if you need help tracking down a confusing failure.

  88. yuvicc commented at 9:14 am on December 29, 2025: contributor

    Thanks for the review @stringintech

    • Addressed nits related to opaque struct naming
    • Addressed comment on allowing null args and adding a check as well as test case for it
    • Removed const-ness from BlockChecked methods for BlockValidationStateView comment
    • Rebased
  89. DrahtBot removed the label Needs rebase on Dec 29, 2025
  90. DrahtBot removed the label CI failed on Dec 29, 2025
  91. stringintech commented at 9:10 am on January 1, 2026: contributor
    ACK 4a261e9f
  92. DrahtBot requested review from alexanderwiederin on Jan 1, 2026
  93. DrahtBot requested review from sedited on Jan 1, 2026
  94. in src/kernel/bitcoinkernel.h:1726 in 4a261e9f91
    1721+ */
    1722+BITCOINKERNEL_API btck_BlockHash* BITCOINKERNEL_WARN_UNUSED_RESULT btck_block_header_get_hash(
    1723+    const btck_BlockHeader* header) BITCOINKERNEL_ARG_NONNULL(1);
    1724+
    1725+/**
    1726+ * @brief Get the previous btck_BlockHash from btck_BlockHeader. The returned hash is unowned and only valid for the lifetime of the btck_BlockHeader.
    


    sedited commented at 9:10 pm on January 2, 2026:
    Nit: Can you break this line?
  95. sedited approved
  96. sedited commented at 9:10 pm on January 2, 2026: contributor
    Re-ACK 4a261e9f91289427ceda11cac1acac7bc26102c1
  97. kernel: Add support for block headers
    Introduces btck_BlockHeader type with accessor methods and btck_chainstate_manager_process_block_header() for validating headers without full blocks. Also, adds btck_chainstate_manager_get_best_entry() to query the header with most cumulative proof-of-work.
    
    Co-authored-by: TheCharlatan <seb.kung@gmail.com>
    9356833595
  98. yuvicc force-pushed on Jan 3, 2026
  99. yuvicc commented at 5:57 am on January 3, 2026: contributor
    Fixed nit #33822 (review).
  100. DrahtBot added the label CI failed on Jan 3, 2026
  101. sedited approved
  102. sedited commented at 7:54 am on January 3, 2026: contributor
    Re-ACK 9356833595f46a6d57d9e5f4a0504f0f8c4256c9
  103. DrahtBot requested review from stringintech on Jan 3, 2026
  104. stringintech commented at 8:14 am on January 3, 2026: contributor
    re-ACK 9356833
  105. DrahtBot removed the label CI failed on Jan 4, 2026

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-01-09 12:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me