Skip to content

starknet_committer: split commit_block into read and compute phases#14213

Merged
yoavGrs merged 1 commit into
mainfrom
yoav/split-commit-block-read-compute
May 28, 2026
Merged

starknet_committer: split commit_block into read and compute phases#14213
yoavGrs merged 1 commit into
mainfrom
yoav/split-commit-block-read-compute

Conversation

@yoavGrs
Copy link
Copy Markdown
Contributor

@yoavGrs yoavGrs commented May 27, 2026

starknet_transaction_prover: redact URL credentials in logs and add startup banner (#14164)

Adds redact_url_host which collapses a URL to scheme://host[:port],
dropping userinfo, path, and query. The CLI-override logs for
rpc_node_url and blocking_check_url and a new startup banner all
route 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

@yoavGrs yoavGrs self-assigned this May 27, 2026
@reviewable-StarkWare
Copy link
Copy Markdown

This change is Reviewable

Copy link
Copy Markdown
Contributor Author

yoavGrs commented May 27, 2026

@yoavGrs yoavGrs requested a review from ArielElp May 27, 2026 08:47
@yoavGrs yoavGrs marked this pull request as ready for review May 27, 2026 08:48
@cursor
Copy link
Copy Markdown

cursor Bot commented May 27, 2026

PR Summary

Medium Risk
Touches core Patricia trie read/commit paths and lifetime contracts across ForestReader and concurrent storage reads; behavior should be equivalent but mistakes could affect state commitment correctness.

Overview
commit_block is split into read_original_forest (DB reads, measurements under Action::Read) and compute_updated_forest (skeleton update, deleted-node detection, FilledForest hashing under Action::Compute). The public entry still runs read then compute, but the boundary lets callers overlap IO for the next block with CPU work on the current one.

To support that, ForestReader::read, read_forest, and storage-trie helpers take &HashMap / &LeafModifications instead of tying them to the forest’s 'a lifetime. Concurrent TrieReadTask uses separate 'a (sorted indices) and 'u (per-contract updates) so OriginalSkeletonForest<'a> only borrows index data, not the update maps—compute_updated_forest can then take actual_storage_updates and actual_classes_updates by value. InitialReadContext gains Sync, and read_roots uses initial_read_context.clone() in the read phase.

Reviewed by Cursor Bugbot for commit 775a5f6. Bugbot is set up for automated code reviews on this repo. Configure here.

@yoavGrs yoavGrs changed the title starknet_transaction_prover: redact URL credentials in logs and add startup banner (#14164) starknet_committer: split commit_block into read and compute phases May 27, 2026
@yoavGrs yoavGrs force-pushed the yoav/split-commit-block-read-compute branch from 8e57dd9 to 5566cc1 Compare May 27, 2026 10:31
Copy link
Copy Markdown
Contributor

@ArielElp ArielElp left a comment

Choose a reason for hiding this comment

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

@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:

  1. passes refs to phase 1 (creating the original skeleton)
  2. moves them to compute_updated_forest, as modifications are passed to multiple hash-computing threads
    Thus, compute_updated_forest needs owned LeafModificationos and a ref to the original skeleton. This means that SortedLeafIndices and LeafModifications cannot 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>
@yoavGrs yoavGrs force-pushed the yoav/split-commit-block-read-compute branch from 5566cc1 to 775a5f6 Compare May 28, 2026 07:26
Copy link
Copy Markdown
Contributor Author

@yoavGrs yoavGrs left a comment

Choose a reason for hiding this comment

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

@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_block creates and owns LeafModifications from the state diff, and:

  1. passes refs to phase 1 (creating the original skeleton)
  2. moves them to compute_updated_forest, as modifications are passed to multiple hash-computing threads
    Thus, compute_updated_forest needs owned LeafModificationos and a ref to the original skeleton. This means that SortedLeafIndices and LeafModifications cannot 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.

Copy link
Copy Markdown
Collaborator

@dorimedini-starkware dorimedini-starkware left a comment

Choose a reason for hiding this comment

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

@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 hashes

crates/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

Copy link
Copy Markdown
Contributor Author

@yoavGrs yoavGrs left a comment

Choose a reason for hiding this comment

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

@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.

Copy link
Copy Markdown
Collaborator

@dorimedini-starkware dorimedini-starkware left a comment

Choose a reason for hiding this comment

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

@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…

'u is for updates. I can rename 'a.

I mean something like 'indices, 'updates. multicharacter variable names are encouraged

Copy link
Copy Markdown
Contributor

@ArielElp ArielElp left a comment

Choose a reason for hiding this comment

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

@ArielElp reviewed 1 file and all commit messages, and resolved 2 discussions.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on yoavGrs).

Copy link
Copy Markdown
Contributor Author

@yoavGrs yoavGrs left a comment

Choose a reason for hiding this comment

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

@yoavGrs resolved 1 discussion.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on yoavGrs).

@yoavGrs yoavGrs added this pull request to the merge queue May 28, 2026
Merged via the queue into main with commit b4d5515 May 28, 2026
26 checks passed
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.

4 participants