kernel: improve BlockChecked ownership semantics #33078

pull stickies-v wants to merge 2 commits into bitcoin:master from stickies-v:2025-07/validation-interface-ownership changing 9 files +42 −33
  1. stickies-v commented at 1:38 pm on July 28, 2025: contributor

    Subscribers to the BlockChecked validation interface event may need access to the block outside of the callback scope. Currently, this is only possible by copying the block, which makes exposing this validation interface event publicly either cumbersome or with significant copy overhead.

    By using shared_ptr, we make the shared ownership explicit and allow users to safely use the block outside of the callback scope. By using a const-ref shared_ptr, no atomic reference count cost is incurred if a subscriber does not require block ownership.

    For example: in #30595, this would allow us to drop the kernel_BlockPointer handle entirely, and generalize everything into kernel_Block. This PoC is implemented in https://github.com/stickies-v/bitcoin/commits/kernel/remove-blockpointer/.


    Performance

    I have added a benchmark in a separate branch, to ensure this change does not lead to a problematic performance regression. Since most of the overhead comes from the subscribers, I have added scenarios for One, Two, and Ten subscribers. From these results, it appears there is no meaningful performance difference on my machine.

    When BlockChecked() takes a const CBlock& reference (master):

    ns/op op/s err% total benchmark
    170.09 5,879,308.26 0.3% 0.01 BlockCheckedOne
    1,603.95 623,460.10 0.5% 0.01 BlockCheckedTen
    336.00 2,976,173.37 1.1% 0.01 BlockCheckedTwo

    When BlockChecked() takes a const std::shared_ptr<const CBlock>& (this PR):

    ns/op op/s err% total benchmark
    172.20 5,807,155.33 0.1% 0.01 BlockCheckedOne
    1,596.79 626,254.52 0.0% 0.01 BlockCheckedTen
    333.38 2,999,603.17 0.3% 0.01 BlockCheckedTwo
  2. kernel: refactor: ConnectTip to pass block pointer by value
    By passing by value, we can remove the need to allocate a new pointer if
    the callsite uses move semantics. In the process, simplify naming.
    9ba1fff29e
  3. DrahtBot added the label Validation on Jul 28, 2025
  4. DrahtBot commented at 1:38 pm on July 28, 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/33078.

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK w0xlt, ryanofsky, TheCharlatan

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #30595 (kernel: Introduce initial C header API by TheCharlatan)
    • #29700 (kernel, refactor: return error status on all fatal errors by ryanofsky)

    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.

  5. stickies-v force-pushed on Jul 28, 2025
  6. DrahtBot added the label CI failed on Jul 28, 2025
  7. DrahtBot commented at 1:58 pm on July 28, 2025: contributor

    🚧 At least one of the CI tasks failed. Task no wallet, libbitcoinkernel: https://github.com/bitcoin/bitcoin/runs/46861571669 LLM reason (✨ experimental): The CI failure is caused by a compilation error due to a method override mismatch in bitcoin-chainstate.cpp.

    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. DrahtBot removed the label CI failed on Jul 28, 2025
  9. in src/validationinterface.h:153 in 742f2b5435 outdated
    149@@ -150,7 +150,7 @@ class CValidationInterface {
    150      * is guaranteed to be the current best block at the time the
    151      * callback was generated (not necessarily now).
    152      */
    153-    virtual void BlockChecked(const CBlock&, const BlockValidationState&) {}
    154+    virtual void BlockChecked(std::shared_ptr<const CBlock>, const BlockValidationState&) {}
    


    w0xlt commented at 7:08 pm on July 31, 2025:
    0    virtual void BlockChecked(const std::shared_ptr<const CBlock>, const BlockValidationState&) {}
    

    stickies-v commented at 7:52 pm on July 31, 2025:
    What’s the benefit of passing a const std::shared_ptr?

    w0xlt commented at 8:35 pm on July 31, 2025:
    Mostly for clarity and intent (with this change, cannot reassign or mutate the local shared_ptr copy). Other than that, no real effect. It is a nit, not blocking.

    maflcko commented at 11:17 am on August 1, 2025:
    I haven’t compiled or benchmarked this, but using const std::shared_ptr<const CBlock> & could avoid the copy and then subscribers are free to decide if they want read-only access, or if they want to create a copy themselves. That would also be in symmetry with the other block signals?

    stickies-v commented at 1:22 pm on August 1, 2025:
    Done, thanks. My initial idea was to use value semantics to simplify ownership, and to let the dispatcher implement move semantics where relevant, but that doesn’t work when there is one dispatcher and multiple subscribers as is the case with our validation interface. Letting the subscriber explicitly claim ownership by copying the reference makes sense and allows us to pay for what we use.
  10. in src/validation.cpp:3162 in 9ba1fff29e outdated
    3160     // Read block from disk.
    3161     const auto time_1{SteadyClock::now()};
    3162-    std::shared_ptr<const CBlock> pthisBlock;
    3163-    if (!pblock) {
    3164+    if (!block_to_connect) {
    3165         std::shared_ptr<CBlock> pblockNew = std::make_shared<CBlock>();
    


    maflcko commented at 6:58 am on August 1, 2025:
    would be easier to do this in-place? block_to_connect=std::make_shared<CBlock>();, as you mutate the copy anyway

    stickies-v commented at 8:29 am on August 1, 2025:
    I don’t think that’s possible, because block_to_connect points to a const CBlock, so we can’t pass that to ReadBlock().
  11. stickies-v commented at 9:43 am on August 1, 2025: contributor
    Note: I have updated the PR description with benchmark results for this change, indicating a modest (~10%) performance decrease which I think is acceptable? edit: no more performance penalty since force-push from 742f2b5 to 1d9f1cb
  12. kernel: improve BlockChecked ownership semantics
    Subscribers to the BlockChecked validation interface event may need
    access to the block outside of the callback scope. Currently, this
    is only possible by copying the block, which makes exposing this
    validation interface event publicly either cumbersome or with significant
    copy overhead.
    
    By using shared_ptr, we make the shared ownership explicit and allow
    users to safely use the block outside of the callback scope.
    1d9f1cb4bd
  13. stickies-v force-pushed on Aug 1, 2025
  14. stickies-v commented at 1:24 pm on August 1, 2025: contributor
    Force-pushed to call BlockChecked with const std::shared_ptr<const CBlock>&, addressing review feedback to avoid atomic reference counting overhead when the subscriber doesn’t need ownership. Benchmarks indicate this PR now no longer has a significant performance impact, on my machine.
  15. ryanofsky approved
  16. ryanofsky commented at 6:56 pm on August 8, 2025: contributor
    Code review ACK 1d9f1cb4bd6b119e1d56cbdd7f6ce4d4521fffa3. These all seem like simple changes that make sense
  17. TheCharlatan approved
  18. TheCharlatan commented at 10:12 pm on August 8, 2025: contributor
    ACK 1d9f1cb4bd6b119e1d56cbdd7f6ce4d4521fffa3

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: 2025-08-13 06:13 UTC

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