perf/store: optimize updating existing accounts #1567
Conversation
14dc3a6 to
5f11a29
Compare
There was a problem hiding this comment.
Pull request overview
This PR optimizes applying partial account deltas by avoiding loading full Account state (code bytes, all storage-map entries, all vault assets) during upsert_accounts, instead fetching only minimal state and computing updated headers/roots.
Changes:
- Added an optimized delta-update module to query minimal account state and compute updated
storage_header/vault_root. - Updated
upsert_accountsto use anAccountStateForInsertenum to handle private, full-state, and partial-state inserts. - Added new tests covering the optimized delta path, private upserts, and full-state delta upserts.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| crates/store/src/db/models/queries/accounts/delta.rs | New optimized queries + helpers for partial delta application (minimal state + root/header computation). |
| crates/store/src/db/models/queries/accounts/delta/tests.rs | New tests for optimized partial delta update, private account upsert, and full-state delta upsert. |
| crates/store/src/db/models/queries/accounts.rs | Integrates optimized partial-delta path into upsert_accounts; adds AccountRowInsert constructors. |
| alt_approach.txt | Documents an alternative design (precompute roots in InnerForest). |
| CHANGELOG.md | Adds a changelog entry for the performance improvement. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
6b1b40a to
a865ef0
Compare
a865ef0 to
2c632b5
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
0a9e28b to
faaad63
Compare
crates/store/src/inner_forest/mod.rs
Outdated
| /// If `is_full_state` is true, returns an empty SMT root. | ||
| fn get_latest_vault_root(&self, account_id: AccountId, is_full_state: bool) -> Word { | ||
| if is_full_state { | ||
| return Self::empty_smt_root(); |
There was a problem hiding this comment.
Always insert an empty root if it's a full account, a full state implies the previous state is all empty.
|
|
||
| let new_balance = i128::from(prev_amount) + i128::from(*amount_delta); | ||
| u64::try_from(new_balance).map_err(|_| InnerForestError::BalanceUnderflow { | ||
| account_id, |
There was a problem hiding this comment.
this is overly complicated but already changed in #1635 so not changing here
Context
Currently applying a partial delta to an existing account requires loading the full account state
consisting of code, all storage map entries, all vault assets, which is very costly - we spend ~250ms on this per block (that's a lot!).
See #1538
What
Optimizes account delta updates by avoiding loading full
Accountobjects from the database when only applying partial deltas.Core changes
module
crates/store/src/db/models/queries/accounts/delta.rsfn select_account_state_for_delta()- fetches only nonce, code_commitment, storage_header, vault_rootfn select_vault_balances_by_faucet_ids()- fetches only specific vault balances being updatedfn apply_storage_delta_with_precomputed_roots()- updates the storage header using precomputed map rootsInnerForest::apply_block_updatesnow precomputes vault and storage map roots for each account update and passes them toDb::apply_blockfor partial delta updates.fn upsert_accountsuses the optimized path for partial deltas viaenum AccountStateForInsertwith three variants:::Private- no public state::FullAccount- new account creation == "full-state delta"::PartialState- incremental update == "partial delta"AccountRowInsertconstructors:new_private(),new_from_account(),new_from_partial()Biggest Change
We reverse the flow and update - we update the
InnerForestnow and track new roots, then using these in the DB storage header update. The downside is additional tackling.