validation: merge `PeekCoin` into `GetCoin` #35078

pull l0rinc wants to merge 3 commits into bitcoin:master from l0rinc:l0rinc/peekcoin-getcoin-merge changing 10 files +42 −63
  1. l0rinc commented at 10:29 PM on April 14, 2026: contributor

    Problem

    Review on #34124 made it clear that the new PeekCoin method is hard to distinguish from the existing GetCoin at call sites where caching does not matter.

    Fix

    Merge PeekCoin into GetCoin by adding a peek_only flag to the CCoinsView interface and removing the separate virtual method. This preserves the non-caching lookup behavior in CCoinsViewCache and CoinsViewOverlay, while allowing backends without caches to ignore the flag.

    Details

    Tests and fuzz scaffolding now call GetCoin(..., true) only where side-effect-free reads matter, and CCoinsViewCache now shares the common result handling between peeking and caching lookups. The post-Flush() overlay assertions use plain GetCoin() because they only check the flushed spentness and do not need to preserve parent cache state.

    Context

    The unclear boundary between PeekCoin and GetCoin was flagged during review by:

  2. DrahtBot added the label Validation on Apr 14, 2026
  3. DrahtBot commented at 10:30 PM on April 14, 2026: contributor

    <!--e57a25ab6845829454e8d69fc972939a-->

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

    <!--006a51241073e994b41acfe9ec718e94-->

    Code Coverage & Benchmarks

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

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    Concept NACK optout21
    Concept ACK ryanofsky

    If your review is incorrectly listed, please copy-paste <code>&lt;!--meta-tag:bot-skip--&gt;</code> into the comment that the bot should ignore.

    <!--174a7506f384e20aa4161008e828411d-->

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #34864 (coins: make cache freshness imply dirtiness and remove invalid test states by l0rinc)
    • #31132 (validation: fetch block inputs on parallel threads by andrewtoth)

    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.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. l0rinc marked this as ready for review on Apr 15, 2026
  5. test: use `GetCoin()` in overlay post-flush assertions
    The `coinsviewoverlay_tests` post-`Flush()` checks only verify that the spent state reached `main_cache`.
    A plain `GetCoin()` miss does not populate the cache, so `PeekCoin()` does not provide extra coverage there.
    
    Use `GetCoin()` now to keep the later `PeekCoin` removal focused on the call sites that still need side-effect-free reads.
    30f2bfb313
  6. l0rinc force-pushed on Apr 15, 2026
  7. l0rinc force-pushed on Apr 15, 2026
  8. DrahtBot added the label CI failed on Apr 15, 2026
  9. DrahtBot commented at 9:23 PM on April 15, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task test ancestor commits: https://github.com/bitcoin/bitcoin/actions/runs/24478465952/job/71536804214</sub> <sub>LLM reason (✨ experimental): CI failed due to a C++ build/compilation error while compiling txdb.cpp for bitcoin_node (bitcoin_node.dir/txdb.cpp.o).</sub>

    <details><summary>Hints</summary>

    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.

    </details>

  10. validation: add `peek_only` to `GetCoin` overrides
    The `CCoinsView` hierarchy currently exposes peeking through a separate virtual method.
    Add a `peek_only` parameter to `GetCoin()` declarations and overrides so a later commit can route peeking and fetching through one interface.
    
    This commit does not change lookup behavior yet.
    
    Co-authored-by: Anthony Towns <aj@erisian.com.au>
    23c60fb4b7
  11. validation: merge `PeekCoin` into `GetCoin`
    Review on https://github.com/bitcoin/bitcoin/pull/34124 made it clear that `PeekCoin()` is hard to distinguish from `GetCoin()` at call sites where caching does not matter.
    Now that `GetCoin()` already accepts a `peek_only` parameter, remove `PeekCoin()` and let callers request the non-caching path directly through `GetCoin(..., true)`.
    
    `CCoinsViewCache` keeps the existing non-caching lookup behavior for `peek_only=true`, and `CoinsViewOverlay` continues to avoid populating parent caches by forwarding `true` to its base view.
    Fuzz call sites where the caching behavior is irrelevant now randomize `peek_only` via `ConsumeBool()` for broader coverage.
    
    This simplification was suggested by:
    * Rus Yanofsky in https://github.com/bitcoin/bitcoin/pull/34165#pullrequestreview-3828444258
    * Anthony Towns in https://github.com/bitcoin/bitcoin/pull/34124#issuecomment-4037752227
    
    Co-authored-by: ryanofsky <ryan@ofsky.org>
    Co-authored-by: Anthony Towns <aj@erisian.com.au>
    8892881963
  12. l0rinc force-pushed on Apr 16, 2026
  13. l0rinc closed this on Apr 16, 2026

  14. l0rinc reopened this on Apr 16, 2026

  15. purpleKarrot commented at 1:56 PM on April 16, 2026: contributor

    This is known as a Boolean Trap. Many design guidelines forbid the use of boolean parameters and instead recommend having separate functions. This PR seems to go into the opposite direction.

  16. l0rinc commented at 2:13 PM on April 16, 2026: contributor

    @purpleKarrot, I agree, it's an anti-pattern, it's why we avoided it originally, but in this case the end-result is easier to work with and several reviewers mentioned they would prefer it. Can you suggest a third version that's better than these two?

  17. purpleKarrot commented at 2:25 PM on April 16, 2026: contributor

    Maybe a Non-Virtual Interface? You could make the virtual function private and call it from two public functions.

  18. ryanofsky commented at 2:53 PM on April 16, 2026: contributor

    Maybe a Non-Virtual Interface? You could make the virtual function private and call it from two public functions.

    Yeah, my original suggestion (https://github.com/bitcoin/bitcoin/commit/642fa06f0af7321d35959f599e2edf74e72c6bd9 #34165 (review)) was to make GetCoin PeekCoin and HaveCoin nonvirtual and implement them in terms of virtual hooks for subclasses. I also gave further suggestions there for enforcing GetCoin/PeekCoin distinction at compile time with const, but these would require separating the coin lookup interface from the coin writing interface.

    In any case 88928819632513b800b3415598bb4896037d60e8 seems like an improvement over status quo. IMO the booleans are not a significant problem, and could also be avoided with minimal changes by passing enum class values like CacheUpdate::Yes CacheUpdate::No.

    So concept ACK for 88928819632513b800b3415598bb4896037d60e8 or anything similar. (Would maybe just clarify the citation in the description since I did suggest a different approach.)

  19. l0rinc commented at 3:34 PM on April 16, 2026: contributor

    Would maybe just clairfy description since I'm mentioned that I did suggest a different approach

    Thanks for the reminder, I have updated the PR description, please let me know if it reflects your opinion accurately.

    these would require separating the coin lookup interface from the coin writing interface

    I rechecked your approach; splitting the reader and writer is something I would like to move toward. One of the goals of these cleanups was segregating the interface. Do you think this current PR gets us closer there? It makes a few other coins refactors simpler (noticed while rebasing them). I'm curious what others think - I don't mind pushing a full alternative PR based on @ryanofsky's prototype - I'd like to do it in small incremental steps.

  20. ryanofsky commented at 3:51 PM on April 16, 2026: contributor

    Do you think this current PR gets us closer there?

    Yes I think current PR is a basically a strict improvement. I just wanted to mention some other possible alternatives and goals. The only possible downside I see of current PR is that if you combine caching and noncaching lookups into one method it may require a few extra call sites to be updated later if separate const and non-const lookup methods are added. But this does not seem like a big deal since there is no const protection for the cache now. I guess I have a pretty clear idea of how I would design this API differently but many approaches seem reasonable here.

    I do plan to review this too soon.

  21. DrahtBot removed the label CI failed on Apr 16, 2026
  22. l0rinc marked this as a draft on Apr 30, 2026
  23. l0rinc commented at 8:53 AM on April 30, 2026: contributor

    Drafting to receive more conceptual review: does the existing split make sense (similarly to the existing flush/sync split) or should we unify similar methods to minimize needless overwrites? If we're going towards splitting the reader and writer behavior (and the caching and other side-effects), merging these two (just to re-split them later) would be wasteful. Ping: @ryanofsky, @andrewtoth, @ajtowns, @optout21

  24. ajtowns commented at 3:44 PM on May 5, 2026: contributor

    Ditto #35078 (comment)

    Changing the argument to an enum class (PEEK_ONLY ?) might be better if we're really worried about boolean arguments.

    I think having cache/peek behaviour be part of the type/interface (dbcache->GetROView() vs dbcache->GetWritableView() or something) might be better, and would likely obsolete this change, but a change like that is probably a lot more work and will take a while, so doing something like this PR in the meantime would be worthwhile. YMMV.

  25. optout21 commented at 1:36 PM on May 7, 2026: contributor

    Concept NACK 88928819632513b800b3415598bb4896037d60e8

    Considering the pros and cons, I feel that the benefits are small. Moreover, this change would preclude the possibility of separating the immutable parts of the interface, hence I'd argue against it.

    Background. The implementation of parallel input fetch (#31132) called for a non-caching version of GetCoin(), so PeekCoin() was introduced recently as a separate method (#34165).

    My pro/con analysis:

    Pro:

    • One less method in the interface(s), some less source code lines
    • Minimal performance: one less entry in coins cache instances' vtable.
    • Unified implementation of the two flavors

    Con:

    • Less clear conceptual separation between the two flavors.
    • Minimal performance: some overhead due to an extra bool parameter.

    However, my main issue is that with a common method it is not possible to place them in separate interfaces, should it be separated into 2 (or 3) levels based on mutability (immutable read, cache-mutable read & write). I've made a comment on [#31132](/bitcoin-bitcoin/31132/) that it would be nice if there was some extra code-level safeguard that the multithreaded accesses make only cache-immutable calls. One way to do this is separating off the cache-immutable read part of the CCoinsViewCache interface (e.g. see https://github.com/optout21/bitcoin/commit/a15d2f9ca4899efd24994fadac49d6c6e0fb6c49). The present PR would make it impossible to separate the non-caching and caching versions into different interfaces. (Note: another experiment at interface separation in: https://github.com/optout21/bitcoin/pull/6 .)

  26. l0rinc commented at 1:10 PM on May 8, 2026: contributor

    Thanks, I will investigate if we can split out the sub-interfaces without needing to merge these two - drafted in the meantime.


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-05-15 15:12 UTC

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