Skip to content

Comments

perf/store: optimize updating existing accounts #1567

Open
drahnr wants to merge 13 commits intonextfrom
bernhard-do-not-load-full-account
Open

perf/store: optimize updating existing accounts #1567
drahnr wants to merge 13 commits intonextfrom
bernhard-do-not-load-full-account

Conversation

@drahnr
Copy link
Contributor

@drahnr drahnr commented Jan 22, 2026

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 Account objects from the database when only applying partial deltas.

Core changes

  • module crates/store/src/db/models/queries/accounts/delta.rs

    • fn select_account_state_for_delta() - fetches only nonce, code_commitment, storage_header, vault_root
    • fn select_vault_balances_by_faucet_ids() - fetches only specific vault balances being updated
    • fn apply_storage_delta_with_precomputed_roots() - updates the storage header using precomputed map roots
  • InnerForest::apply_block_updates now precomputes vault and storage map roots for each account update and passes them to
    Db::apply_block for partial delta updates.

  • fn upsert_accounts uses the optimized path for partial deltas via enum AccountStateForInsert with three variants:

    • ::Private - no public state
    • ::FullAccount - new account creation == "full-state delta"
    • ::PartialState - incremental update == "partial delta"
  • AccountRowInsert constructors: new_private(), new_from_account(), new_from_partial()

Biggest Change

We reverse the flow and update - we update the InnerForest now and track new roots, then using these in the DB storage header update. The downside is additional tackling.

@drahnr drahnr marked this pull request as draft January 22, 2026 08:36
@drahnr drahnr force-pushed the bernhard-do-not-load-full-account branch 3 times, most recently from 14dc3a6 to 5f11a29 Compare January 22, 2026 15:16
@drahnr drahnr requested a review from Copilot February 3, 2026 15:47
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

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_accounts to use an AccountStateForInsert enum 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.

@drahnr drahnr force-pushed the bernhard-do-not-load-full-account branch from 6b1b40a to a865ef0 Compare February 16, 2026 15:01
@drahnr drahnr force-pushed the bernhard-do-not-load-full-account branch from a865ef0 to 2c632b5 Compare February 16, 2026 15:48
@drahnr drahnr marked this pull request as ready for review February 16, 2026 16:45
@drahnr drahnr requested a review from Copilot February 16, 2026 18:08
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

drahnr and others added 2 commits February 17, 2026 10:03
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
@drahnr drahnr force-pushed the bernhard-do-not-load-full-account branch from 0a9e28b to faaad63 Compare February 23, 2026 12:55
@drahnr drahnr requested a review from sergerad February 24, 2026 19:09
/// 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();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

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,
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is overly complicated but already changed in #1635 so not changing here

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants