Skip to content

perf(persistence): improve write batch for HashedPostState & TrieUpdatesSorted#19739

Merged
mediocregopher merged 4 commits intoparadigmxyz:mainfrom
duyquang6:push-mvpsukvxzvvs
Nov 17, 2025
Merged

perf(persistence): improve write batch for HashedPostState & TrieUpdatesSorted#19739
mediocregopher merged 4 commits intoparadigmxyz:mainfrom
duyquang6:push-mvpsukvxzvvs

Conversation

@duyquang6
Copy link
Contributor

@duyquang6 duyquang6 commented Nov 14, 2025

  • Batch HashedPostState & TrieUpdatesSorted in save_blocks to improve batch processing performance.

Performance Results:

  • Tested on devnet with 60k TPS raw-transfer workload, with default config (engine.persistence-thresh-hold = 3):
    • Before: ~50ms per block → ~150ms total for 3 blocks
    • After: ~50ms total for 3 blocks (3x improvement)
      Note: This assumes the number of accounts remains relatively stable across blocks, which aligns with typical production workloads.

Before:
image
*Note: p0.9 is sum of total time for all persist blocks, so it will be multiple by number of block need to persist

After:

image

Updated:

With --engine.persistence-threshold 6, so it need persist 7 blocks per interval:

For TrieUpdatesSorted:
Image

after:

Image
  • reduce from 125ms -> ~100ms

Note: If we use default config: flush 3 blocks interval, the diff is not much different
But this still a win if in case our persistence very slow, and it need persist tons of block to catch-up with the tip

@duyquang6 duyquang6 marked this pull request as ready for review November 14, 2025 05:40
@duyquang6 duyquang6 changed the title feat: improve persistence write batch for hashpoststate feat(persistence): improve write batch for hashpoststate Nov 14, 2025
Copy link
Member

@shekhirin shekhirin left a comment

Choose a reason for hiding this comment

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

LGTM, cc @mediocregopher

@github-project-automation github-project-automation bot moved this from Backlog to In Progress in Reth Tracker Nov 14, 2025
@shekhirin shekhirin added C-perf A change motivated by improving speed, memory usage or disk footprint A-db Related to the database labels Nov 14, 2025
Copy link
Member

@mediocregopher mediocregopher left a comment

Choose a reason for hiding this comment

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

One nitpick on a comment, and a suggestion for another easy win you could do here but it's optional

// * state
// * hashed state
// * hashed state (already done)
// * trie updates (cannot naively extend, need helper)
Copy link
Member

Choose a reason for hiding this comment

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

This comment isn't accurate, we can collect a TrieUpdatesSorted and extend it with the trie updates from each block, and then only do a single write_trie_updates_sorted at the end, just like you're doing here with the hashed state. Might be worth trying out in this PR?

Copy link
Contributor Author

@duyquang6 duyquang6 Nov 14, 2025

Choose a reason for hiding this comment

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

hi @mediocregopher, about comment, that is obsolete I think

Let me try benchmark and update to you again

Copy link
Contributor Author

@duyquang6 duyquang6 Nov 14, 2025

Choose a reason for hiding this comment

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

Thank for suggestion, here is bench result

I use --engine.persistence-threshold 6, so it need persist 7 blocks per interval:
before:

Image

after:

Image

reduce from 125ms -> ~100ms
Note: with default --engine.persistence-threshold 2: flush 3 blocks interval, the difference is not much

Copy link
Member

Choose a reason for hiding this comment

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

Very nice, thanks for re-benching it 🙏

@duyquang6 duyquang6 changed the title feat(persistence): improve write batch for hashpoststate feat(persistence): improve write batch for hash_post_state & trie_updates Nov 14, 2025
@duyquang6 duyquang6 changed the title feat(persistence): improve write batch for hash_post_state & trie_updates feat(persistence): improve write batch for HashedPostState & TrieUpdatesSorted Nov 14, 2025
@duyquang6 duyquang6 changed the title feat(persistence): improve write batch for HashedPostState & TrieUpdatesSorted perf(persistence): improve write batch for HashedPostState & TrieUpdatesSorted Nov 14, 2025
@mediocregopher mediocregopher added this pull request to the merge queue Nov 17, 2025
Merged via the queue into paradigmxyz:main with commit 65ca4a3 Nov 17, 2025
48 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in Reth Tracker Nov 17, 2025
@mediocregopher
Copy link
Member

@duyquang6 this had to be reverted as it caused state root mismatches.

The issue is that the writing of changesets (write_state for state, and write_trie_changesets for trie nodes) must be called with the updates for the previous block having been written, otherwise incorrect changesets get written. By aggregating updates and writing them at the end these method calls are not called on top of correct DB state.

write_trie_changesets accepts an overlay argument which I think could be used with the updates aggregated so far to correctly write changesets even while aggregating. write_state does not accept an argument like this, one would need to be added to achieve the aggregation logic.

@duyquang6
Copy link
Contributor Author

duyquang6 commented Nov 21, 2025

@duyquang6 this had to be reverted as it caused state root mismatches.

The issue is that the writing of changesets (write_state for state, and write_trie_changesets for trie nodes) must be called with the updates for the previous block having been written, otherwise incorrect changesets get written. By aggregating updates and writing them at the end these method calls are not called on top of correct DB state.

write_trie_changesets accepts an overlay argument which I think could be used with the updates aggregated so far to correctly write changesets even while aggregating. write_state does not accept an argument like this, one would need to be added to achieve the aggregation logic.

Hi @mediocregopher,

I think the root cause is indeed that write_trie_changesets depends on write_trie_updates_sorted, as you mentioned.

Regarding the potential conflict between write_hashed_state and write_state, I believe it’s not relevant in this context. write_hashed_state only writes to:

  • HashedAccounts
  • HashedStorages

whereas write_state:

  • read from: BlockBodyIndices, PlainAccountState, PlainStorageState
  • write to: Receipts, PlainAccountState, PlainStorageState, StorageChangeSets, AccountChangeSets, Bytecodes

Given that they operate on separate data, batching write_hashed_state should be safe

@mediocregopher
Copy link
Member

@duyquang6

Given that they operate on separate data, batching write_hashed_state should be safe

That makes sense, I guess it was only the trie changesets which caused the state root mismatches we saw then.

@duyquang6
Copy link
Contributor Author

That makes sense, I guess it was only the trie changesets which caused the state root mismatches we saw then.

Hi sir, I'm planning to cherry-pick the write_hashed_state batching changes into a separate PR, I think that still a valuable improvement, since they're likely unrelated to the state root mismatch bug.

write_trie_changesets accepts an overlay argument which I think could be used with the updates aggregated so far to correctly write changesets even while aggregating

About this, I also had sometimes to play with this aggregate, but the bench result is not good, go one by one block still better in this step

I'll reference this discussion in the new PR

cwkang1998 added a commit to cwkang1998/reth that referenced this pull request Jan 8, 2026
Accumulates TriesUpdateSorted and batch write at at the end. Prior
benchmark done in paradigmxyz#19739 indicates this should improve batch processing
performance.

Both paradigmxyz#19739 and its succeesor paradigmxyz#19991, contains benchmarks that measures
the performance improvements. I am not really familiar on how to do
that, so if that's something that's required, would appreciate some
help.

Closes paradigmxyz#20611
cwkang1998 added a commit to cwkang1998/reth that referenced this pull request Jan 8, 2026
Accumulates TriesUpdateSorted and batch write at at the end. Prior
benchmark done in paradigmxyz#19739 indicates this should improve batch processing
performance.

Both paradigmxyz#19739 and its succeesor paradigmxyz#19991, contains benchmarks that measures
the performance improvements. I am not really familiar on how to do
that, so if that's something that's required, would appreciate some
help.

Closes paradigmxyz#20611
cwkang1998 added a commit to cwkang1998/reth that referenced this pull request Jan 9, 2026
Accumulates TriesUpdateSorted and batch write at at the end. Prior
benchmark done in paradigmxyz#19739 indicates this should improve batch processing
performance.

Both paradigmxyz#19739 and its succeesor paradigmxyz#19991, contains benchmarks that measures
the performance improvements. I am not really familiar on how to do
that, so if that's something that's required, would appreciate some
help.

Closes paradigmxyz#20611
cwkang1998 added a commit to cwkang1998/reth that referenced this pull request Jan 13, 2026
Accumulates TriesUpdateSorted and batch write at at the end. Prior
benchmark done in paradigmxyz#19739 indicates this should improve batch processing
performance.

Both paradigmxyz#19739 and its succeesor paradigmxyz#19991, contains benchmarks that measures
the performance improvements. I am not really familiar on how to do
that, so if that's something that's required, would appreciate some
help.

Closes paradigmxyz#20611
gakonst added a commit that referenced this pull request Jan 15, 2026
Accumulates TrieUpdatesSorted from all blocks and batch writes at the end.
Prior benchmark done in #19739 indicates this should improve batch processing
performance.

Key changes:
- Accumulate trie updates into a single TrieUpdatesSorted during save_blocks loop
- Pass accumulated overlay to write_trie_changesets so each block sees correct state
- Call write_trie_updates_sorted once after the loop with accumulated updates

Closes #20611
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-db Related to the database C-perf A change motivated by improving speed, memory usage or disk footprint

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants