Summary
miden_node_store::state::State::apply_block currently performs expensive account-state SMT work twice when applying a block with public account updates.
The expensive path is:
State::apply_block() computes account and nullifier tree mutations.
- The DB apply path calls
models::queries::apply_block(), which calls upsert_accounts().
upsert_accounts() updates SQLite account state and recomputes account-level commitments:
- vault root
- storage map roots
- storage header commitment
- final account commitment validation
- After the DB transaction commits,
State::apply_block() updates the in-memory account state forest via AccountStateForest::apply_block_updates().
- The account state forest applies the same vault and storage map deltas again, recomputing the same SMT roots.
This duplicates the costly SMT work, especially for storage map updates where upsert_accounts() may need to load complete map contents from SQLite and reconstruct the Merkle tree.
Problem
upsert_accounts() currently needs to derive the updated account row values itself. For partial public account updates, that requires:
- reading latest vault assets from SQLite,
- applying the vault delta,
- recomputing the vault root,
- reading storage map entries for changed slots,
- applying storage deltas,
- recomputing storage map roots,
- producing the updated
AccountStorageHeader,
- deriving the updated account commitment.
Later, AccountStateForest::apply_block_updates() applies the same account deltas to the in-memory forest and recomputes the same vault/storage roots again.
This makes block application slower than necessary and makes the DB layer responsible for commitment computation that should already be available from the in-memory state transition machinery.
Proposed solution
Refactor block application so account state forest mutations are computed before the SQLite transaction is applied.
The desired flow would be:
- Validate the block as today.
- Compute account tree and nullifier tree mutations as today.
- Compute account state forest mutations for public account deltas before applying SQLite changes.
- This should also produce the updated vault roots and storage map root commitments needed by SQLite.
- Pass the precomputed account state data into the DB apply path.
upsert_accounts() should stop reconstructing vaults/storage maps just to compute commitments.
- It should insert/update the account row using the precomputed
vault_root, storage_header, and/or storage map root values.
- It should still persist the changed vault assets and storage map values.
- It should still validate that the derived/precomputed final account commitment matches
BlockAccountUpdate::final_state_commitment().
- Once the SQLite transaction commits, apply:
- account tree mutations,
- nullifier tree mutations,
- precomputed account state forest mutations.
Dependency / prerequisite
This assumes miden-crypto exposes a LargeSmtForest mutation API similar to the account/nullifier tree APIs, for example:
compute_mutations(...)
apply_mutations(...)
That API does not exist today, so this issue depends on adding or exposing the necessary LargeSmtForest mutation support first. 0xMiden/crypto#1009 is tracking this new API in miden-crypto.
Summary
miden_node_store::state::State::apply_blockcurrently performs expensive account-state SMT work twice when applying a block with public account updates.The expensive path is:
State::apply_block()computes account and nullifier tree mutations.models::queries::apply_block(), which callsupsert_accounts().upsert_accounts()updates SQLite account state and recomputes account-level commitments:State::apply_block()updates the in-memory account state forest viaAccountStateForest::apply_block_updates().This duplicates the costly SMT work, especially for storage map updates where
upsert_accounts()may need to load complete map contents from SQLite and reconstruct the Merkle tree.Problem
upsert_accounts()currently needs to derive the updated account row values itself. For partial public account updates, that requires:AccountStorageHeader,Later,
AccountStateForest::apply_block_updates()applies the same account deltas to the in-memory forest and recomputes the same vault/storage roots again.This makes block application slower than necessary and makes the DB layer responsible for commitment computation that should already be available from the in-memory state transition machinery.
Proposed solution
Refactor block application so account state forest mutations are computed before the SQLite transaction is applied.
The desired flow would be:
upsert_accounts()should stop reconstructing vaults/storage maps just to compute commitments.vault_root,storage_header, and/or storage map root values.BlockAccountUpdate::final_state_commitment().Dependency / prerequisite
This assumes
miden-cryptoexposes aLargeSmtForestmutation API similar to the account/nullifier tree APIs, for example:compute_mutations(...)apply_mutations(...)That API does not exist today, so this issue depends on adding or exposing the necessary
LargeSmtForestmutation support first. 0xMiden/crypto#1009 is tracking this new API inmiden-crypto.