starknet_committer: split commit_block into read and compute phases#14213
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
PR SummaryMedium Risk Overview To support that, Reviewed by Cursor Bugbot for commit 775a5f6. Bugbot is set up for automated code reviews on this repo. Configure here. |
8e57dd9 to
5566cc1
Compare
ArielElp
left a comment
There was a problem hiding this comment.
@ArielElp reviewed 5 files and all commit messages, and made 2 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on yoavGrs).
crates/starknet_committer/src/block_committer/commit.rs line 93 at r1 (raw file):
measurements.start_measurement(Action::Read); let roots = trie_reader .read_roots(input.initial_read_context.clone())
Consider destructuring Input in the beginning of commit_block, and passing just the necessary refs from input to avoid cloning:
let Input { state_diff, initial_read_context, config } = input;
let (mut storage_tries_indices, mut contracts_trie_indices, mut classes_trie_indices) =
get_all_modified_indices(&state_diff);
let n_contracts_trie_modifications = contracts_trie_indices.len();
let forest_sorted_indices = ForestSortedIndices {
storage_tries_sorted_indices: storage_tries_indices
.iter_mut()
.map(|(address, indices)| (*address, SortedLeafIndices::new(indices)))
.collect(),
contracts_trie_sorted_indices: SortedLeafIndices::new(&mut contracts_trie_indices),
classes_trie_sorted_indices: SortedLeafIndices::new(&mut classes_trie_indices),
};
let actual_storage_updates = state_diff.actual_storage_updates();
let actual_classes_updates = state_diff.actual_classes_updates();
// Record the number of modifications.
measure_number_of_modifications(
measurements,
&actual_storage_updates,
n_contracts_trie_modifications,
actual_classes_updates.len(),
);
// Phase 1 - read the original forest from the DB.
let (original_forest, original_contracts_trie_leaves) = read_original_forest(
&state_diff,
initial_read_context,
&config,
&actual_storage_updates,
&actual_classes_updates,
&forest_sorted_indices,
trie_reader,
measurements,
)
.await?;
// Phase 2 - compute the new forest.
compute_updated_forest(
original_forest,
original_contracts_trie_leaves,
actual_storage_updates,
actual_classes_updates,
&state_diff,
measurements,
)
.await
crates/starknet_committer/src/db/trie_traversal.rs line 800 at r1 (raw file):
/// Holds all data needed to build one storage trie concurrently. /// Implements [StorageTask] so that [GatherableStorage::gather] can drive it. struct TrieReadTask<'a, 'u, Layout: NodeLayoutFor<StarknetStorageValue>> {
Please add docs on why I can't get away with one lifetime var. Something like:
commit_block creates and owns LeafModifications from the state diff, and:
- passes refs to phase 1 (creating the original skeleton)
- moves them to compute_updated_forest, as modifications are passed to multiple hash-computing threads
Thus,compute_updated_forestneeds owned LeafModificationos and a ref to the original skeleton. This means thatSortedLeafIndicesandLeafModificationscannot share the same lifetime, as that would disallow owning the latter in a function while the original skeleton still exists.
Could probably be improved, but IMO should be detailed as anyone encountering it later will try to get rid of one of the vars.
Extract read_original_forest (IO-bound) and compute_updated_forest (CPU-bound) so the DB is free for parallel reads during computation. Decouple the storage/classes update lifetimes from the original forest's lifetime in the read path, since the forest only borrows the sorted indices; this lets the compute phase take ownership of the update maps. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
5566cc1 to
775a5f6
Compare
yoavGrs
left a comment
There was a problem hiding this comment.
@yoavGrs made 2 comments.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on ArielElp).
crates/starknet_committer/src/block_committer/commit.rs line 93 at r1 (raw file):
Previously, ArielElp wrote…
Consider destructuring Input in the beginning of commit_block, and passing just the necessary refs from input to avoid cloning:
let Input { state_diff, initial_read_context, config } = input; let (mut storage_tries_indices, mut contracts_trie_indices, mut classes_trie_indices) = get_all_modified_indices(&state_diff); let n_contracts_trie_modifications = contracts_trie_indices.len(); let forest_sorted_indices = ForestSortedIndices { storage_tries_sorted_indices: storage_tries_indices .iter_mut() .map(|(address, indices)| (*address, SortedLeafIndices::new(indices))) .collect(), contracts_trie_sorted_indices: SortedLeafIndices::new(&mut contracts_trie_indices), classes_trie_sorted_indices: SortedLeafIndices::new(&mut classes_trie_indices), }; let actual_storage_updates = state_diff.actual_storage_updates(); let actual_classes_updates = state_diff.actual_classes_updates(); // Record the number of modifications. measure_number_of_modifications( measurements, &actual_storage_updates, n_contracts_trie_modifications, actual_classes_updates.len(), ); // Phase 1 - read the original forest from the DB. let (original_forest, original_contracts_trie_leaves) = read_original_forest( &state_diff, initial_read_context, &config, &actual_storage_updates, &actual_classes_updates, &forest_sorted_indices, trie_reader, measurements, ) .await?; // Phase 2 - compute the new forest. compute_updated_forest( original_forest, original_contracts_trie_leaves, actual_storage_updates, actual_classes_updates, &state_diff, measurements, ) .await
I'm cloning the config - 2 booleans, and the initia_read_context - this is the signature of ForestReader::read, destructuring won't change it.
crates/starknet_committer/src/db/trie_traversal.rs line 800 at r1 (raw file):
Previously, ArielElp wrote…
Please add docs on why I can't get away with one lifetime var. Something like:
commit_blockcreates and owns LeafModifications from the state diff, and:
- passes refs to phase 1 (creating the original skeleton)
- moves them to compute_updated_forest, as modifications are passed to multiple hash-computing threads
Thus,compute_updated_forestneeds owned LeafModificationos and a ref to the original skeleton. This means thatSortedLeafIndicesandLeafModificationscannot share the same lifetime, as that would disallow owning the latter in a function while the original skeleton still exists.Could probably be improved, but IMO should be detailed as anyone encountering it later will try to get rid of one of the vars.
Done.
dorimedini-starkware
left a comment
There was a problem hiding this comment.
@dorimedini-starkware reviewed 5 files and all commit messages, and made 2 comments.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on ArielElp and yoavGrs).
crates/starknet_committer/src/block_committer/commit.rs line 120 at r2 (raw file):
} /// Computes the updated forest topology, its new hashes, and the nodes deleted by the state diff.
you are not computing hashes here, right? that's the updated->filled forest part
Code quote:
Computes the updated forest topology, its new hashescrates/starknet_committer/src/db/trie_traversal.rs at r2 (raw file):
in a separate PR: consider renaming the lifetime params to indicate what they are for.
not necessary (or blocking), may be nicer though
yoavGrs
left a comment
There was a problem hiding this comment.
@yoavGrs made 2 comments.
Reviewable status: all files reviewed, 4 unresolved discussions (waiting on ArielElp and dorimedini-starkware).
crates/starknet_committer/src/block_committer/commit.rs line 120 at r2 (raw file):
Previously, dorimedini-starkware wrote…
you are not computing hashes here, right? that's the updated->filled forest part
I do. The computing is original -> updated -> filled.
crates/starknet_committer/src/db/trie_traversal.rs at r2 (raw file):
Previously, dorimedini-starkware wrote…
in a separate PR: consider renaming the lifetime params to indicate what they are for.
not necessary (or blocking), may be nicer though
'u is for updates. I can rename 'a.
dorimedini-starkware
left a comment
There was a problem hiding this comment.
@dorimedini-starkware made 2 comments and resolved 1 discussion.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on ArielElp and yoavGrs).
crates/starknet_committer/src/block_committer/commit.rs line 120 at r2 (raw file):
Previously, yoavGrs wrote…
I do. The computing is original -> updated -> filled.
ah, my bad
crates/starknet_committer/src/db/trie_traversal.rs at r2 (raw file):
Previously, yoavGrs wrote…
'uis for updates. I can rename'a.
I mean something like 'indices, 'updates. multicharacter variable names are encouraged
ArielElp
left a comment
There was a problem hiding this comment.
@ArielElp reviewed 1 file and all commit messages, and resolved 2 discussions.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on yoavGrs).
yoavGrs
left a comment
There was a problem hiding this comment.
@yoavGrs resolved 1 discussion.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on yoavGrs).

starknet_transaction_prover: redact URL credentials in logs and add startup banner (#14164)
Adds
redact_url_hostwhich collapses a URL toscheme://host[:port],dropping userinfo, path, and query. The CLI-override logs for
rpc_node_urlandblocking_check_urland a new startup banner allroute through it so credentials embedded in those URLs cannot reach a log
sink.
Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com
deployment: add override values to envs (#14198)
release: upgrade cairo, native, proving-utils (#14200)
starknet_os_flow_tests: drive commitment keys from compute_accessed_keys (#14106)
Replace the legacy initial_reads.keys() input to StateCommitmentInfos::new
with the same accessed-keys aggregate the batcher writes — validating
end-to-end that what the batcher persists is sufficient for the OS to
replay the block. ProofFacts block numbers are extracted from the block's
BlockifierTransactions (via create_tx_info -> Current -> proof_facts ->
ProofFactsVariant::Snos) and passed through to AccessedKeys::new.
Virtual-OS mode skips the alias-contract entries since the executor doesn't
run allocate_aliases_in_storage there. The resulting StateChangesKeys is
built via From.
Co-authored-by: Claude Opus 4.7 (1M context) noreply@anthropic.com
starknet_patricia_storage: two layer storage (#13990)
blockifier: sha512 syscall (#14072)
starknet_committer: split commit_block into read and compute phases
Extract read_original_forest (IO-bound) and compute_updated_forest
(CPU-bound) so the DB is free for parallel reads during computation.
Decouple the storage/classes update lifetimes from the original forest's
lifetime in the read path, since the forest only borrows the sorted
indices; this lets the compute phase take ownership of the update maps.
Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com