test: cover unused mempool space in coins cache limit #35490

pull w0xlt wants to merge 1 commits into bitcoin:master from w0xlt:mempool-kernel-regression-tests changing 1 files +9 −8
  1. w0xlt commented at 12:05 AM on June 9, 2026: contributor

    This PR extends the existing unit test for Chainstate::GetCoinsCacheSizeState().

    Chainstate::GetCoinsCacheSizeState() calculates when the UTXO/coins cache is too large and should be flushed. Part of that calculation includes unused -maxmempool space. For example, if the mempool limit is 300 MiB but the mempool is mostly empty, some of that unused space can be counted toward the coins cache limit.

    The existing validation_flush_tests.cpp test checks this calculation by calling:

    chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, max_mempool_size_bytes)
    

    This change extends the test to also check the no-argument call:

    chainstate.GetCoinsCacheSizeState()
    

    That is the call used by validation code during normal operation.

    The test grows the coins cache above the coins-only limit, then checks that:

    • calling the explicit helper with max_mempool_size_bytes=0 reports CRITICAL
    • calling the normal no-argument method reports OK, because it includes unused mempool space

    This makes sure future refactors do not accidentally drop unused mempool space from the normal cache-size calculation.

  2. DrahtBot added the label Tests on Jun 9, 2026
  3. DrahtBot commented at 12:06 AM on June 9, 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/35490.

    <!--021abf342d371248e50ceaed478a90ca-->

    Reviews

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

    Type Reviewers
    ACK l0rinc, 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

    No conflicts as of last run.

    <!--5faf32d7da4f0f540f40219e4f7537a3-->

  4. sedited commented at 7:42 AM on June 9, 2026: contributor

    Concept ACK

  5. sedited requested review from l0rinc on Jun 9, 2026
  6. sedited approved
  7. sedited commented at 4:44 PM on June 29, 2026: contributor

    ACK 843f163c665787d4c1f9c5edd902e48481417b30

  8. in src/test/validation_flush_tests.cpp:85 in 843f163c66
      80 | +    for (size_t i{0}; i < MAX_ATTEMPTS && view.DynamicMemoryUsage() <= MAX_COINS_BYTES; ++i) {
      81 | +        AddTestCoin(m_rng, view);
      82 | +    }
      83 | +
      84 | +    BOOST_REQUIRE_GT(view.DynamicMemoryUsage(), MAX_COINS_BYTES);
      85 | +    BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::CRITICAL);
    


    l0rinc commented at 8:05 PM on July 2, 2026:

    Could we fold this into getcoinscachesizestate above? The existing test already grows the same cache through the relevant thresholds; resizing the chainstate cache first lets it cover the unused- mempool-space case without a second growth loop.

    diff --git a/src/test/validation_flush_tests.cpp b/src/test/validation_flush_tests.cpp
    --- a/src/test/validation_flush_tests.cpp	(revision 78f052a4053e71490cc3ac697a84c3d88a80fe20)
    +++ b/src/test/validation_flush_tests.cpp	(revision 241cb62d7a1fc0713fede5a3ca7fa0c16d74ffc9)
    @@ -18,33 +18,34 @@
     //! then with additional mempool head-room.
     BOOST_AUTO_TEST_CASE(getcoinscachesizestate)
     {
    +    constexpr uint64_t MAX_COINS_BYTES{8_MiB};
    +    constexpr uint64_t MAX_MEMPOOL_BYTES{4_MiB};
    +    constexpr uint64_t MAX_ATTEMPTS{40'000};
         Chainstate& chainstate{m_node.chainman->ActiveChainstate()};
     
         LOCK(::cs_main);
    +    BOOST_REQUIRE(chainstate.ResizeCoinsCaches(MAX_COINS_BYTES, /*coinsdb_size=*/1_MiB));
         CCoinsViewCache& view{chainstate.CoinsTip()};
     
         // Sanity: an empty cache should be ≲ 1 chunk (~ 256 KiB).
         BOOST_CHECK_LT(view.DynamicMemoryUsage() / (256 * 1024.0), 1.1);
     
    -    constexpr size_t MAX_COINS_BYTES{8_MiB};
    -    constexpr size_t MAX_MEMPOOL_BYTES{4_MiB};
    -    constexpr size_t MAX_ATTEMPTS{50'000};
     
         // Run the same growth-path twice: first with 0 head-room, then with extra head-room
    -    for (size_t max_mempool_size_bytes : {size_t{0}, MAX_MEMPOOL_BYTES}) {
    +    for (uint64_t max_mempool_size_bytes : {uint64_t{0}, MAX_MEMPOOL_BYTES}) {
             const int64_t full_cap{int64_t(MAX_COINS_BYTES + max_mempool_size_bytes)};
             const int64_t large_cap{LargeCoinsCacheThreshold(full_cap)};
     
             // OK → LARGE
             auto state{chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, max_mempool_size_bytes)};
    -        for (size_t i{0}; i < MAX_ATTEMPTS && int64_t(view.DynamicMemoryUsage()) <= large_cap; ++i) {
    +        for (uint64_t i{0}; i < MAX_ATTEMPTS && int64_t(view.DynamicMemoryUsage()) <= large_cap; ++i) {
                 BOOST_CHECK_EQUAL(state, CoinsCacheSizeState::OK);
                 AddTestCoin(m_rng, view);
                 state = chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, max_mempool_size_bytes);
             }
     
             // LARGE → CRITICAL
    -        for (size_t i{0}; i < MAX_ATTEMPTS && int64_t(view.DynamicMemoryUsage()) <= full_cap; ++i) {
    +        for (uint64_t i{0}; i < MAX_ATTEMPTS && int64_t(view.DynamicMemoryUsage()) <= full_cap; ++i) {
                 BOOST_CHECK_EQUAL(state, CoinsCacheSizeState::LARGE);
                 AddTestCoin(m_rng, view);
                 state = chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, max_mempool_size_bytes);
    @@ -52,7 +53,7 @@
             BOOST_CHECK_EQUAL(state, CoinsCacheSizeState::CRITICAL);
         }
     
    -    // Default thresholds (no explicit limits) permit many more coins.
    +    // Unused mempool space permits many more coins.
         for (int i{0}; i < 1'000; ++i) {
             AddTestCoin(m_rng, view);
             BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(), CoinsCacheSizeState::OK);
    @@ -60,30 +61,10 @@
     
         // CRITICAL → OK via Flush
         BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::CRITICAL);
    +    BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(), CoinsCacheSizeState::OK);
         view.SetBestBlock(m_rng.rand256());
         view.Flush();
         BOOST_CHECK_EQUAL(chainstate.GetCoinsCacheSizeState(MAX_COINS_BYTES, /*max_mempool_size_bytes=*/0), CoinsCacheSizeState::OK);
     }
    

    w0xlt commented at 7:43 AM on July 11, 2026:

    Taken. Thanks. Added you as co-author.


    l0rinc commented at 3:50 PM on July 11, 2026:

    It can also lower MAX_ATTEMPTS to 40'000

    looks like this isn't the case on 32 bits - thanks for adjusting

  9. l0rinc changes_requested
  10. l0rinc commented at 8:09 PM on July 2, 2026: contributor

    Concept ACK, thanks for thinking of this.

    I left a suggestion to fold the new coverage into getcoinscachesizestate, since it already grows the cache through the relevant thresholds. The merged test can assert that zero mempool headroom is CRITICAL while GetCoinsCacheSizeState() still returns OK.

    It can also lower MAX_ATTEMPTS to 40'000 and use uint64_t for the test limits/counters.

  11. w0xlt force-pushed on Jul 11, 2026
  12. test: cover unused mempool space in coins cache
    Co-authored-by: l0rinc <pap.lorinc@gmail.com>
    5d57f2cefe
  13. w0xlt force-pushed on Jul 11, 2026
  14. DrahtBot added the label CI failed on Jul 11, 2026
  15. DrahtBot commented at 8:24 AM on July 11, 2026: contributor

    <!--85328a0da195eb286784d51f73fa0af9-->

    🚧 At least one of the CI tasks failed. <sub>Task i686, no IPC: https://github.com/bitcoin/bitcoin/actions/runs/29144912556/job/86524696414</sub> <sub>LLM reason (✨ experimental): CI failed because the validation_flush_tests ctest target failed (only test suite reported as failing).</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>

  16. DrahtBot removed the label CI failed on Jul 11, 2026
  17. l0rinc approved
  18. l0rinc commented at 3:54 PM on July 11, 2026: contributor

    ACK 5d57f2cefee2acec3c8e11d6b1d5b5fe97e6cfe7

    Thanks for taking care of this - note that the PR description still talks about the old state, should be updated before merge.

  19. DrahtBot requested review from sedited on Jul 11, 2026
  20. w0xlt commented at 7:49 AM on July 12, 2026: contributor

    PR description still talks about the old state, should be updated before merge.

    Done. Thanks.

  21. sedited approved
  22. sedited commented at 8:47 AM on July 21, 2026: contributor

    ACK 5d57f2cefee2acec3c8e11d6b1d5b5fe97e6cfe7

  23. sedited merged this on Jul 21, 2026
  24. sedited closed this on Jul 21, 2026

Labels

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-22 05:50 UTC

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