Skip to content

Use number of dirty cache entries in flush warnings/logs#41

Closed
l0rinc wants to merge 12 commits intomasterfrom
l0rinc/warn-dirty-coin-coint
Closed

Use number of dirty cache entries in flush warnings/logs#41
l0rinc wants to merge 12 commits intomasterfrom
l0rinc/warn-dirty-coin-coint

Conversation

@l0rinc
Copy link
Copy Markdown
Owner

@l0rinc l0rinc commented Sep 30, 2025

Revival of bitcoin#31703

Since bitcoin#28280 and bitcoin#28233, the percentage of dirty entries in the cache when a flush happen may in practice be far from 100%. The log output, the decision to warn about a large flush (bitcoin#31534), and the disk-full detection, however always use the entire size of the cache.

Fix this by keeping track of the number of dirty entries in CCoinsViewCache, and using that number. I've dropped the usage of DynamicMemoryUsage as it's the wrong metric, even before the non-wiping flushes were introduced (if everything is dirty, memory usage is correlated with, but not the same as, the amount of disk space written or used). They could be improved by keeping track of proper write size estimates in a follow-up, but here I'm just using a fixed 48 bytes per entry estimate. Also covered EmplaceCoinInternalDANGER in SimulationTest

vasild and others added 8 commits June 9, 2025 10:45
`FuzzedSock::Accept()` properly returns a new socket, but it forgot to
set the output argument `addr`, like `accept(2)` is expected to.

This could lead to reading uninitialized data during testing when we
read it, e.g. from `CService::SetSockAddr()` which reads the `sa_family`
member.

Set `addr` to a fuzzed IPv4 or IPv6 address.
Now that all network calls done by `CConnman::OpenNetworkConnection()`
are done via `Sock` they can be redirected (mocked) to `FuzzedSocket`
for testing.
* Make the methods of `CThreadInterrupt` virtual and store a pointer to
  it in `CConnman`, thus making it possible to override with a mocked
  instance.
* Initialize `CConnman::m_interrupt_net` from the constructor, making it
  possible for callers to supply mocked version.
* Introduce `FuzzedThreadInterrupt` and `ConsumeThreadInterrupt()` and
  use them in `src/test/fuzz/connman.cpp` and `src/test/fuzz/i2p.cpp`.

This improves the CPU utilization of the `connman` fuzz test.

As a nice side effect, the `std::shared_ptr` used for
`CConnman::m_interrupt_net` resolves the possible lifetime issues with
it (see the removed comment for that variable).
0802398 fuzz: make it possible to mock (fuzz) CThreadInterrupt (Vasil Dimov)
6d9e5d1 fuzz: add CConnman::SocketHandler() to the tests (Vasil Dimov)
3265df6 fuzz: add CConnman::InitBinds() to the tests (Vasil Dimov)
91cbf4d fuzz: add CConnman::CreateNodeFromAcceptedSocket() to the tests (Vasil Dimov)
50da743 fuzz: add CConnman::OpenNetworkConnection() to the tests (Vasil Dimov)
e6a917c fuzz: add Fuzzed NetEventsInterface and use it in connman tests (Vasil Dimov)
e883b37 fuzz: set the output argument of FuzzedSock::Accept() (Vasil Dimov)

Pull request description:

  Extend `CConnman` fuzz tests to also exercise the methods `OpenNetworkConnection()`, `CreateNodeFromAcceptedSocket()`, `InitBinds()` and `SocketHandler()`.

  Previously fuzzing those methods would have resulted in real socket functions being called in the operating system which is undesirable during fuzzing. Now that bitcoin#21878 is complete all those are mocked to a fuzzed socket and a fuzzed DNS resolver (see how `CreateSock` and `g_dns_lookup` are replaced in the first commit).

ACKs for top commit:
  achow101:
    ACK 0802398
  jonatack:
    Review re-ACK 0802398
  dergoegge:
    Code review ACK 0802398

Tree-SHA512: a717d4e79f42bacf2b029c821fdc265e10e4e5c41af77cd4cb452cc5720ec83c62789d5b3dfafd39a22cc8c0500b18169aa7864d497dded729a32ab863dd6c4d
@l0rinc l0rinc force-pushed the l0rinc/warn-dirty-coin-coint branch from 2eccef6 to 142d2af Compare October 1, 2025 01:49
l0rinc and others added 4 commits September 30, 2025 21:58
…aceCoinInternalDANGER`

The `EmplaceCoinInternalDANGER` method was unconditionally adding to `cachedCoinsUsage`, but should only do so when `try_emplace` actually
inserts a new entry. If the entry already exists, no memory is allocated and usage should not change.

Also moves `cachedCoinsUsage = 0` inside the `if (fOk)` block in `Flush()` for consistency - the reset should only happen when the flush succeeds.

Adds test coverage by randomly calling `EmplaceCoinInternalDANGER` in `SimulationTest` to verify the accounting remains correct.

Co-authored-by: Pieter Wuille <pieter@wuille.net>
Co-authored-by: Andrew Toth <andrewstoth@gmail.com>
Refactors test code to use an explicit `AddUsage(size_t)` method instead of exposing the raw `cachedCoinsUsage` reference via `usage()`.
Adds `m_dirty_count` member to track the running count of dirty cache entries as follows:
* Incremented when entries are marked dirty via `CCoinsCacheEntry::SetDirty`
* Decremented when dirty entries are removed or cleaned
* Passed through `CoinsViewCacheCursor` and updated during iteration
* Validated in `SanityCheck()` by recomputing from scratch

The dirty count is needed because after non-wiping flushes (introduced in bitcoin#28280 and bitcoin#28233), the percentage of dirty entries in the cache may be
far below 100%. Using total cache size for flush warnings and disk space checks is therefore misleading.

Updates all test code to properly initialize and maintain the dirty count.

Co-authored-by: l0rinc <pap.lorinc@gmail.com>
…ecks

Changes flush warnings to use the actual number of dirty entries being written rather than total cache size or memory usage:
* Moves warning from `FlushStateToDisk` to `CCoinsViewDB::BatchWrite` so it applies to both regular flushes and `AssumeUTXO` snapshot writes
* Changes threshold from `WARN_FLUSH_COINS_SIZE` (1 GiB) to `WARN_FLUSH_COINS_COUNT` (10M entries), approximately equivalent - this also helps with the confusion caused by UTXO size difference on-disk vs in-memory
* Moves benchmark logging to `BatchWrite` where the actual disk I/O occurs to make sure AssumeUTXO also warns
* Uses dirty count for disk space check (48 bytes per entry estimate)
* Removes redundant `changed` counter since `dirty_count` is now tracked

This ensures users are warned appropriately even when only a fraction of the cache is dirty, and provides accurate warnings during `AssumeUTXO` loads.

Co-authored-by: l0rinc <pap.lorinc@gmail.com>
@l0rinc l0rinc force-pushed the l0rinc/warn-dirty-coin-coint branch from 142d2af to 4b31781 Compare October 1, 2025 02:16
@l0rinc l0rinc closed this Oct 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants