Skip to content

Conversation

@sedited
Copy link
Contributor

@sedited sedited commented Nov 12, 2025

CCoinsViewCache::BatchWrite always returns true if called from a backed cache, so just return void instead. Also return void from ::Sync and ::Flush.

This allows for dropping a FatalError condition and simplifying some dead error handling code a bit.

Since we now no longer exercise the "error path" when returning from CCoinsView::BatchWrite, make the method clear the cache instead. This should only be exercised by tests and not change production behaviour. This might slightly improve the coins_view fuzz test's ability to generate better coverage.

@DrahtBot
Copy link
Contributor

DrahtBot commented Nov 12, 2025

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/33866.

Reviews

See the guideline for information on the review process.

Type Reviewers
ACK l0rinc, andrewtoth, w0xlt, achow101

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:

  • #34164 (validation: add reusable coins view for ConnectBlock by andrewtoth)
  • #34125 (refactor: reuse should_empty for chainstate flush condition by l0rinc)
  • #34124 (refactor: make CCoinsView a purely virtual abstract base class by l0rinc)
  • #33680 (validation: do not wipe utxo cache for stats/scans/snapshots by l0rinc)
  • #33512 (coins: use number of dirty cache entries in flush warnings/logs by l0rinc)
  • #31132 (validation: fetch block inputs on parallel threads 3x faster IBD 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.

@l0rinc
Copy link
Contributor

l0rinc commented Nov 12, 2025

big concept ACK, some tests and comments likely still need updating, but can't wait for this to be finally gone, thanks for taking care of it.

For the record this is a continuation of #33042:

CCoinsView::BatchWrite (and transitively CCoinsViewCache::Flush & CCoinsViewCache::Sync) were intentionally not changed here. While all implementations return true, the base CCoinsView::BatchWrite returns false. Changing this would cause coins_view tests to fail with:
terminating due to uncaught exception of type std::logic_error: Not all unspent flagged entries were cleared
We can fix that in a follow-up PR.

@sedited
Copy link
Contributor Author

sedited commented Nov 13, 2025

Updated 6d18188 -> d1823eb (batch_write_void_0 -> batch_write_void_1, compare)

  • Addressed @andrewtoth's comment, use NextAndMaybeErase on the cursor in BatchWrite. This avoids the extra code in the fuzz test, and might increase the fuzz test's ability to generate coverage a bit.
  • Addressed @l0rinc's comment, removed left over (and now stale) comments on false returning conditions. Also added as co-author.

src/coins.h Outdated
uint256 GetBestBlock() const override;
void SetBestBlock(const uint256 &hashBlock);
bool BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override;
void BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) override;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this change affect the error catchers, e.g.

* Writes do not need similar protection, as failure to write is handled by the caller.
?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it does, afaik a write exception through Sync or Flush is just bubbled up and then logged. But I might be missing something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but aren't read and write symmetric now in that regard?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmh, not sure what you are trying to say with that. What is the symmetry there? I think I am missing something, can you try and elaborate a bit?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment states: "shutdown on LevelDB read errors [...] Writes do not need similar protection".
So now that reads and writes both throw and don't return, do we need to adjust the error catchers - since either reads also don't need protection anymore or writes also do - if I understand the catchers' purpose...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we are changing behaviour here (though I might stand corrected still), so if a change is required to them, the error catchers would have been buggy from the beginning. I have long questioned though to how we catch the db write errors, and if it might lead to an infinite loop in some cases. The exception handling just doesn't seem very robust or thought-through to me.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that the fundamental behavior didn't change, both read and write threw instead of returning. Can we adjust the comments at least to reflect this?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can also do it in a follow-up, there's enough work in this area...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think so too :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sedited
Copy link
Contributor Author

sedited commented Dec 14, 2025

Copy link
Contributor

@andrewtoth andrewtoth left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK d35267f

@DrahtBot DrahtBot requested a review from l0rinc December 14, 2025 16:05
Copy link
Contributor

@l0rinc l0rinc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recreated the change locally and diffed it against the PR: only the mentioned formatting and doc changes differed.

src/coins.h Outdated
* to be forgotten.
* If will_reuse_cache is false, the cache will retain the same memory footprint
* after flushing and should be destroyed to deallocate.
* If false is returned, the state of this cache (and its backing view) will be undefined.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the comment should also be updated

Suggested change
* If false is returned, the state of this cache (and its backing view) will be undefined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you think it would be better if we'd mention the exception too, i.e. If an exception occurs the state of this cache (and its backing view) will be undefined.

Copy link
Contributor

@l0rinc l0rinc Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, I assume it's evident now that it's void - the definition of a side-effectful method

src/coins.cpp Outdated
uint256 CCoinsView::GetBestBlock() const { return uint256(); }
std::vector<uint256> CCoinsView::GetHeadBlocks() const { return std::vector<uint256>(); }
bool CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock) { return false; }
void CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock)
Copy link
Contributor

@l0rinc l0rinc Dec 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the formatting was already off here. Since I think you need to push again to remove an invalid method doc, could you please reformat the modified lines as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I prefer the line break. There is also the longer HaveCoin method below it that also does put everything in one line?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not the linebreak:

Suggested change
void CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256 &hashBlock)
void CCoinsView::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock)

@DrahtBot DrahtBot requested a review from l0rinc December 14, 2025 17:34
CCoinsViewCache::BatchWrite always returns true if called from a backed
cache, so just return void instead. Also return void from ::Sync and
::Flush.

This allows for dropping a FatalError condition and simplifying some
dead error handling code a bit.

Since we now no longer exercise the "error path" when returning from
`CCoinsView::BatchWrite`, make the method clear the cache instead. This
should only be exercised by tests and not change production behaviour.
This might slightly improve the coins_view fuzz test's ability to
generate better coverage.

Co-authored-by: l0rinc <[email protected]>
@l0rinc
Copy link
Contributor

l0rinc commented Dec 14, 2025

ACK 6da6f50

Thanks for taking care of this!

@DrahtBot DrahtBot requested a review from andrewtoth December 14, 2025 21:29
@sedited
Copy link
Contributor Author

sedited commented Dec 14, 2025

Updated d35267f -> 6da6f50 (batch_write_void_2 -> batch_write_void_3, compare)

  • Addressed @l0rinc's comment, re-formatted some lines that were already touched.
  • Addressed @l0rinc's comment, removed stale docstring for boolean return parameter.

@andrewtoth
Copy link
Contributor

re-ACK 6da6f50

Copy link
Contributor

@w0xlt w0xlt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 6da6f50

Good cleanup that removes dead code and simplifies the coins cache API.

@l0rinc
Copy link
Contributor

l0rinc commented Jan 1, 2026

A few other PRs depend on this, can we get this one merged? rfm?

@achow101
Copy link
Member

achow101 commented Jan 3, 2026

ACK 6da6f50

@achow101 achow101 merged commit ab23325 into bitcoin:master Jan 3, 2026
25 checks passed
l0rinc added a commit to l0rinc/bitcoin that referenced this pull request Jan 15, 2026
When `CDBWrapper::Read()` fails deserialization we silently return `false`, which makes decode failures indistinguishable from missing keys.

Drop the catch so deserialization errors fail fast.
This is in line with other recent changes where we're not trying to recover from database failures - and to make this explicit, see: bitcoin#33866
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants