txdb: reject undecodable first coin cursor key #35654

pull l0rinc wants to merge 1 commits into bitcoin:master from l0rinc:l0rinc/txdb-malformed-first-coin-cursor-key changing 2 files +22 −6
  1. l0rinc commented at 1:36 AM on July 4, 2026: contributor

    Problem: CCoinsViewDB::Cursor() already handles the case where Seek(DB_COIN) finds no coin record, but could still accept an undecodable first coin key as a valid cursor position. CCoinsViewDBCursor::Next() already invalidates the cursor for the same decode failure later in iteration, so initial cursor setup has a small correctness mismatch.

    Fix: Make initial cursor setup match Next(): keep the cached key invalid unless the first key decodes successfully.

    Fixes #35172, with credit to the issue author and previous attempts #35191 and #35248.

  2. DrahtBot added the label UTXO Db and Indexes on Jul 4, 2026
  3. DrahtBot commented at 1:36 AM on July 4, 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/35654.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

    See the guideline and AI policy for information on the review process.

    Type Reviewers
    ACK sedited

    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:

    • #34320 (coins: delegate CCoinsViewDB::HaveCoin to GetCoin by l0rinc)

    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. sedited commented at 3:08 PM on July 4, 2026: contributor

    Quoting myself from the issue: If the chainstate is corrupted to the point that the condition described here is reached, I'm not sure if the check introduced here actually improves the situation for the running node. Commit https://github.com/bitcoin/bitcoin/commit/822755a424d0abfa408dc34313f4aca4b816f54f also explicitly works around the "no valid first entry" scenario.

    The reasons stated here (crc collisions, and fork tools) also don't seem very compelling to me. If this is really something worthwhile, maybe just frame it as a correctness improvement and getting rid of a weird albeit harmless edge case?

  5. txdb: reject malformed first coin cursor key
    `CCoinsViewDB::Cursor()` already handles an empty coin keyspace after `Seek(DB_COIN)`, but could still accept an undecodable first coin key as a valid cursor position.
    `CCoinsViewDBCursor::Next()` invalidates the cursor for the same decode failure later in iteration, so the warmup path had a small malformed-chainstate consistency gap.
    
    Make initial cursor setup match `Next()`: keep the cached key invalid unless the first key decodes successfully.
    Add a unit test that writes a valid `Coin` under a malformed `DB_COIN` key and checks the cursor is invalid.
    
    Co-authored-by: Shuvam Pandey <i@shuvamp.com.np>
    Co-authored-by: Arthur Ariel Sabintsev <arthur@sabintsev.com>
    Co-authored-by: CruzMolina <7537712+CruzMolina@users.noreply.github.com>
    3837d9192a
  6. l0rinc renamed this:
    txdb: reject malformed first coin cursor key
    txdb: reject undecodable first coin cursor key
    on Jul 6, 2026
  7. l0rinc force-pushed on Jul 6, 2026
  8. l0rinc commented at 4:46 AM on July 6, 2026: contributor

    maybe just frame it as a correctness improvement and getting rid of a weird albeit harmless edge case

    Adjusted the code comment, commit message, PR description and title - let me know if this is what you meant

  9. sedited commented at 11:04 AM on July 24, 2026: contributor

    let me know if this is what you meant

    Yes, that is what I meant. I'm still not sure if the change is worthwhile. This was repeatedly flagged and picked up by AI agents. I get the impression that this is more busywork than anything, but at this point it will just be picked up again and again, which seems like even more of a time sink, so I'd rather this change get in.

    ACK 3837d9192a719b2232a2e8f330dac347bf09742d

  10. 650DataNerd commented at 10:39 AM on July 25, 2026: none

    Following up on the "is this worthwhile" question above traced through the typical consumer pattern (while (cursor->Valid()) { ...; cursor->Next(); }).

    Before this fix: a corrupted first record means one garbage entry gets processed, but Next() still runs afterward, so the rest of a valid UTXO set is still visited correctly.

    After this fix: Valid() is false immediately, so Next() is never called and the loop exits before visiting any of the (potentially many) valid coins after the bad one trading "one garbage entry mixed into an otherwise- complete result" for "reports entirely empty despite valid data existing."

    Given the project's general preference for failing loudly on corrupted state (e.g. the -reindex guidance elsewhere in this file) rather than silently continuing, an obviously-empty result may still be preferable to a subtly- wrong one. But it might be worth an explicit LogError here so operators aren't left guessing why a tool suddenly reports nothing happy to be corrected if I am missing something about how these call sites actually handle an empty cursor.


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-07-28 03:51 UTC

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