Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: update miner mempool iterator query to consider both nonces and fee rates #5541

Open
wants to merge 58 commits into
base: develop
Choose a base branch
from

Conversation

rafaelcr
Copy link

@rafaelcr rafaelcr commented Dec 7, 2024

Problem

The current query used by Stacks miners to iterate over pending mempool transactions sorts them only by fee_rate in descending order. This approach creates the following problems:

  1. Since it does not consider transaction nonces, non-mineable transactions with high fees but old (or very future) nonces go to the top of the list and get visited every time, thus wasting block construction time budget.
  2. Transactions with null fee rates are sent to the bottom of the list even if their nonces should be evaluated next, forcing the algorithm to query them separately with some probability of inclusion.

Solution

This PR adds a new mempool walk strategy (NextNonceWithHighestFeeRate) which prioritizes transactions that can be confirmed as fast as possible (next expected nonces for both origin and sponsor) with the highest fee rates as possible. This means that even if it doesn't select the transactions with the highest global fees first, it will select those that can be mined immediately therefore optimizing block building time and allowing the miner to fit in more transactions in total within the allotted time. This strategy also mixes in transactions with null fee rates in results by simulating a fee rate for the purposes of ordering only.

For easier testing, a mempool walk strategy enum value was added to the MinerConfig, which includes:

  • GlobalFeeRate: Current global fee rate sorting behavior. Enabled by default.
  • NextNonceWithHighestFeeRate: The new strategy added by this PR

@CLAassistant
Copy link

CLAassistant commented Dec 7, 2024

CLA assistant check
All committers have signed the CLA.

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@rafaelcr rafaelcr changed the title (draft) fix: update miner mempool transaction iterator query to consider fee rate and nonce fix: update miner mempool transaction iterator query to consider fee rate and nonce Dec 15, 2024
@rafaelcr rafaelcr marked this pull request as ready for review December 15, 2024 00:09
@rafaelcr rafaelcr requested a review from a team as a code owner December 15, 2024 00:09
@rafaelcr rafaelcr changed the title fix: update miner mempool transaction iterator query to consider fee rate and nonce fix: update miner mempool iterator query to consider both nonces and fee rates Dec 15, 2024
@obycode obycode added this to the 3.1.0.0.3 milestone Dec 16, 2024
@obycode obycode self-requested a review December 16, 2024 20:32
Copy link
Member

@jcnelson jcnelson left a comment

Choose a reason for hiding this comment

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

Thanks for taking this on @rafaelcr!

This is something that I think is going to need somewhat extensive real-world testing before we make it the default behavior. Do you think you could add this new mempool walk logic as an opt-in alternative, which the node operator can opt to use? This would give miners a chance to compare/contrast the new behavior with the old behavior in an easy-to-rollback manner. A subsequent PR could make the new behavior the default.

What do you think?

@rafaelcr
Copy link
Author

Great idea @jcnelson and thanks for the feedback! I'll get on it.

@rafaelcr
Copy link
Author

your new commits look great @obycode ! thanks for pushing this to the finish line 🙌

@obycode obycode force-pushed the fix/mempool-query branch from 01e183a to db4dc8c Compare March 14, 2025 21:02
@obycode
Copy link
Contributor

obycode commented Mar 17, 2025

This new mempool iteration algorithm sacrifices optimal fee-based transaction selection in order to guarantee high performance. Since transaction ordering is not consensus critical (other than nonce-ordering per account), this is allowed. There are a couple of downsides I can think of.

First is the potential for lower total fees for miners. In practice, this is not likely to be the case, because when the mempool is not very full, the order will be less optimal, but all ready transactions are likely to be included in the block anyway. When the mempool is more full, the current algorithm would stall or only generate tiny blocks, so even though the order is not perfect, miners will end up with more total fees, thanks to the selection speedup.

Next is disturbance to the fee market. With this algorithm, chained nonce transactions (where one account has multiple outstanding transactions in the mempool) can end up prioritized behind lower fee-rate transactions. The query used selects all "ready" transactions based on their nonces. If account A has transaction A1 with nonce 0 and A2 with nonce 1, both paying fees of 10 STX, and account B has transaction B0 with nonce 0 paying 0.001 STX, the selection algorithm will choose A0, then B0, then B1. This is due to the fact that on the first query, A1 is not "ready", so it is not included in the results and thus not considered. After A0 has been mined, then A1 will be "ready".

Copy link

codecov bot commented Mar 19, 2025

Codecov Report

Attention: Patch coverage is 63.77102% with 905 lines in your changes missing coverage. Please review.

Project coverage is 83.61%. Comparing base (9937c41) to head (b2503f2).
Report is 20 commits behind head on develop.

Files with missing lines Patch % Lines
...net/stacks-node/src/tests/nakamoto_integrations.rs 1.25% 553 Missing ⚠️
testnet/stacks-node/src/tests/signer/v0.rs 51.40% 224 Missing ⚠️
stackslib/src/core/util.rs 87.36% 59 Missing ⚠️
stackslib/src/core/mempool.rs 86.28% 31 Missing ⚠️
stacks-common/src/util/lru_cache.rs 90.33% 20 Missing ⚠️
stackslib/src/core/nonce_cache.rs 93.71% 13 Missing ⚠️
stackslib/src/config/mod.rs 50.00% 3 Missing ⚠️
stackslib/src/chainstate/stacks/miner.rs 94.44% 1 Missing ⚠️
.../src/chainstate/stacks/tests/block_construction.rs 99.55% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##           develop    #5541       +/-   ##
============================================
+ Coverage    68.14%   83.61%   +15.46%     
============================================
  Files          521      524        +3     
  Lines       382814   384636     +1822     
  Branches       323      323               
============================================
+ Hits        260884   321604    +60720     
+ Misses      121922    63024    -58898     
  Partials         8        8               
Files with missing lines Coverage Δ
stacks-common/src/types/sqlite.rs 100.00% <100.00%> (ø)
stacks-common/src/util/mod.rs 88.23% <ø> (+1.47%) ⬆️
stackslib/src/chainstate/stacks/tests/mod.rs 81.32% <100.00%> (+2.88%) ⬆️
stackslib/src/core/mod.rs 61.78% <ø> (+3.29%) ⬆️
stackslib/src/core/tests/mod.rs 91.49% <100.00%> (+41.78%) ⬆️
stackslib/src/net/mod.rs 78.61% <ø> (+1.36%) ⬆️
stackslib/src/net/tests/download/nakamoto.rs 96.08% <ø> (+56.95%) ⬆️
stackslib/src/net/tests/inv/nakamoto.rs 96.66% <ø> (+44.70%) ⬆️
stackslib/src/net/tests/mempool/mod.rs 100.00% <ø> (+30.62%) ⬆️
testnet/stacks-node/src/nakamoto_node/miner.rs 83.95% <100.00%> (-0.79%) ⬇️
... and 19 more

... and 294 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 6c715b5...b2503f2. Read the comment docs.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@obycode
Copy link
Contributor

obycode commented Mar 19, 2025

The remaining issue is due to the fact that the nonce cache is not getting reset after a block is rejected. I will fix this next.

@obycode
Copy link
Contributor

obycode commented Mar 20, 2025

I think the only remaining task here is to ensure that we don't get stuck if there are 11,650 problematic and ready transactions in the mempool.

@obycode
Copy link
Contributor

obycode commented Mar 20, 2025

There is room for further improvement by not resetting the nonce DB after a block is successfully mined. I think I will leave that for a future PR though, because it is a bit troublesome.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Status: 💻 In Progress
Development

Successfully merging this pull request may close these issues.

6 participants