miner: fix empty mempool case for waitNext() #33566

pull Sjors wants to merge 1 commits into bitcoin:master from Sjors:2025/10/wait-empty-mempool changing 3 files +27 −13
  1. Sjors commented at 2:56 pm on October 7, 2025: member

    Block template fees are calculated by looping over new_tmpl->vTxFees and return (early) once the fee_threshold is exceeded.

    This left an edge case when the mempool is empty, which this commit fixes and adds a test for.

    Also update test/functional/interface_ipc.py to reflect the new behavior,

    Fixes https://github.com/Sjors/sv2-tp/issues/9

  2. DrahtBot added the label Mining on Oct 7, 2025
  3. DrahtBot commented at 2:56 pm on October 7, 2025: contributor

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

    Reviews

    See the guideline for information on the review process.

    Type Reviewers
    ACK sipa, optout21, cedwies
    Concept ACK zaidmstrr
    Stale ACK TheCharlatan
    User requested bot ignore Raimo33

    If your review is incorrectly listed, please react with 👎 to this comment and the bot will ignore it on the next update.

    Conflicts

    Reviewers, this pull request conflicts with the following ones:

    • #33421 (node: add BlockTemplateCache by ismaelsadeeq)

    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.

  4. Sjors commented at 2:57 pm on October 7, 2025: member
    This is not worth the effort to backport imo.
  5. Sjors force-pushed on Oct 7, 2025
  6. Sjors commented at 3:25 pm on October 7, 2025: member
    @sipa I ended up updating test/functional/interface_ipc.py to reflect the new behavior, but I’m not sure what the original test tried to do in #33201.
  7. Sjors force-pushed on Oct 7, 2025
  8. TheCharlatan approved
  9. TheCharlatan commented at 1:33 pm on October 12, 2025: contributor
    ACK 2e8fff3f17366e9c2ba054023ad8bd89ac51d584
  10. Raimo33 referenced this in commit a0cc73df6c on Oct 13, 2025
  11. Raimo33 referenced this in commit c23a65414f on Oct 13, 2025
  12. Raimo33 commented at 3:41 pm on October 13, 2025: contributor

    Concept ACK. this is a subtle bug which would result in an infinite loop. Approach NACK. the proposed solution adds branching complexity for a case which is extremely unlikely.

    allow me to propose a more elegant and modern solution: c23a65414f239c0d867d13f1be02a232096c1f9d

  13. miner: fix empty mempool case for waitNext()
    Block template fees are calculated by looping over new_tmpl->vTxFees
    and return (early) once the fee_threshold is exceeded.
    
    This left an edge case when the mempool is empty, which this commit
    fixes and adds a test for. It does so by using std::accumulate instead
    of manual loops.
    
    Also update interface_ipc.py to account for the new behavior.
    
    Co-authored-by: Raimo33 <claudio.raimondi@protonmail.com>
    8f7673257a
  14. Sjors force-pushed on Oct 13, 2025
  15. Sjors commented at 4:41 pm on October 13, 2025: member
    Great idea, I integrated @Raimo33’s approach.
  16. Sjors renamed this:
    miner: empty mempool special case for waitNext()
    miner: fix empty mempool case for waitNext()
    on Oct 13, 2025
  17. Raimo33 commented at 4:42 pm on October 13, 2025: contributor

    Great idea, I integrated @Raimo33’s approach.

    please add me as co-author or cherry-pick my commit

  18. Sjors commented at 4:45 pm on October 13, 2025: member
    @Raimo33 I did, see Co-authored-by in commit message.
  19. sipa commented at 11:06 pm on October 13, 2025: member
    utACK 8f7673257a1a86717c1d83770dc857fc254df107
  20. DrahtBot requested review from TheCharlatan on Oct 13, 2025
  21. optout21 commented at 11:52 am on October 14, 2025: none

    Concept ACK

    Maybe add the new test in a first commit (showing how it fails), and then the fix in a new commit? For test change without fix, and fix in see commits 3a7e58ec81fb2caeef1cf369d47b0a247d923180 and 3220ce81b1df090895daa32dfb5a1af003d6d88b

  22. Sjors commented at 11:59 am on October 14, 2025: member
    @optout21 the test-each-commit job enforces that each commit has a passing test.
  23. optout21 commented at 12:11 pm on October 14, 2025: none

    @optout21 the test-each-commit job enforces that each commit has a passing test.

    I’m not sure I understand this correctly, but if you mean that all tests should pass with each commit – yes, first commit has test checks matching the non-fixed code (i.e. BOOST_REQUIRE(should_be_nullptr == nullptr);), and fix commit also adapts this one check. It’s more clear looking at the fix commit what is the change in behavior, if adding the test and fix are separated. Leaving in one commit is also fine in this PR IMHO.

  24. in src/node/miner.cpp:530 in 8f7673257a
    535-                new_fees += fee;
    536-                Assume(options.fee_threshold != MAX_MONEY);
    537-                if (new_fees >= current_fees + options.fee_threshold) return new_tmpl;
    538-            }
    539+            // Check if fees increased enough to return the new template
    540+            const CAmount new_fees = std::accumulate(new_tmpl->vTxFees.begin(), new_tmpl->vTxFees.end(), CAmount{0});
    


    zaidmstrr commented at 2:37 pm on October 14, 2025:
    Using std::accumulate in line 526 seems good, but using it in line 530 has some performance impact. std::accumulate search for the whole vector despite the condition already being met. With this it increases the best-case time complexity and some average-case complexity from Ω(k) (where k <= n) to Ω(n). Any caller calling this with frequent polling might face some milliseconds of performance issues in some cases. I feel like the approach in commit 2e8fff3 is more optimal than this one with the constant work of O(1).

    Raimo33 commented at 2:45 pm on October 14, 2025:

    you’re talking about theoretical complexity. but I’m almost certain that the std::accumulate approach is orders of magnitude faster in practice when you measure absolute time. this is because avoiding a branch at every iteration allows for optimizations such as SIMD vectorization, or even simply a better data access pattern which is more cache friendly.

    I’d love to see some benchmarks!


    Sjors commented at 2:53 pm on October 14, 2025:
    I think the reduced code complexity is worth losing the early return. After cluster cluster mempool this calculation will probably be replaced anyway.

    cedwies commented at 1:08 pm on October 16, 2025:

    I ran a small external python simulation to get a rough sense of how often the early-exit fee loop would actually stop much earlier than a full sum under realistic mempool conditions.

    Using a model with 3000 txs (fees = feerate × vsize, realistic feerate ranges, small per-tick mempool drift, and occasional high-fee arrivals), the results were: – threshold=0: median touch fraction ≈ 0.97, meaning in a typical run the loop still scans about 97% of transactions before returning; about 43 % of trials didn’t beat the old total at all. – threshold=100.000: median = 1.0, early exit never triggered within a tick.

    On my machine (Apple M2 Max), summing all 3000 fees takes about 0.4 µs, so the median time saved by early-exit was around 0.01 µs (10 ns) (essentially negligible). This could suggest that early-exit almost never helps in practice, while the std::accumulate has the benefits already discussed.


    zaidmstrr commented at 2:05 pm on October 16, 2025:
    Thanks for the benchmarking. But I think to simulate the actual mempool behaviour is complicated. The order of transactions inside mempool is not very deterministic based on fee. So we can’t predict that our threshold always will be hit at the last stages of search, even though it searches till the last in most of the cases, but that’s not for all. The function also uses polling, so if you increase the number of executions, the time will increase a bit. But as Sjors said, this calculation will be removed by cluster mempool work later on. So I think we can go with this for now.
  25. zaidmstrr commented at 2:38 pm on October 14, 2025: contributor
    Concept ACK 8f76732
  26. optout21 commented at 3:25 pm on October 14, 2025: none
    ACK 8f7673257a1a86717c1d83770dc857fc254df107
  27. DrahtBot requested review from zaidmstrr on Oct 14, 2025
  28. cedwies commented at 1:49 pm on October 16, 2025: none

    tACK 8f76732

    Reviewed and tested. The empty mempool case (fee_threshold==0) now behaves as expected and is covered by tests.

  29. glozow merged this on Oct 23, 2025
  30. glozow closed this on Oct 23, 2025

  31. Sjors commented at 12:24 pm on October 23, 2025: member
    @glozow thanks, can you add a backport label for 30.x?
  32. fanquake added the label Needs backport (30.x) on Oct 23, 2025
  33. fanquake referenced this in commit 3afd5a9729 on Oct 23, 2025
  34. fanquake removed the label Needs backport (30.x) on Oct 23, 2025
  35. fanquake commented at 1:51 pm on October 23, 2025: member
    Backported to 30.x in #33609.

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: 2025-11-01 00:13 UTC

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