Skip to content

Conversation

@ilitteri
Copy link
Contributor

@ilitteri ilitteri commented Nov 13, 2025

Motivation

Our guest program library is used for both L1 and L2 block proving, and the logic for it is very coupled. A first step towards decoupling this is separating the guest program inputs for L1 and L2. This also improves the UX for users that only care about proving L1 blocks.

Description

Guest program inputs for L1

pub struct ProgramInput {
    /// Block to execute
    pub block: Block,
    /// database containing all the data necessary to execute
    pub execution_witness: ExecutionWitness,
}

Guest program inputs for L2

pub struct ProgramInput {
    /// blocks to execute
    pub blocks: Vec<Block>,
    /// database containing all the data necessary to execute
    pub execution_witness: ExecutionWitness,
    /// value used to calculate base fee
    pub elasticity_multiplier: u64,
    /// Configuration for L2 fees used for each block
    pub fee_configs: Vec<ethrex_common::types::fee_config::FeeConfig>,
    /// KZG commitment to the blob data
    #[serde_as(as = "[_; 48]")]
    pub blob_commitment: ethrex_common::types::blobs_bundle::Commitment,
    /// KZG opening for a challenge over the blob commitment
    #[serde_as(as = "[_; 48]")]
    pub blob_proof: ethrex_common::types::blobs_bundle::Proof,
}

@ilitteri ilitteri self-assigned this Nov 13, 2025
Copilot AI review requested due to automatic review settings November 13, 2025 01:56
@ilitteri ilitteri requested a review from a team as a code owner November 13, 2025 01:56
@github-actions github-actions bot added the L2 Rollup client label Nov 13, 2025
@github-actions
Copy link

github-actions bot commented Nov 13, 2025

Lines of code report

Total lines added: 46
Total lines removed: 0
Total lines changed: 46

Detailed view
+------------------------------------------------------------+-------+------+
| File                                                       | Lines | Diff |
+------------------------------------------------------------+-------+------+
| ethrex/crates/l2/prover/src/guest_program/src/execution.rs | 467   | +11  |
+------------------------------------------------------------+-------+------+
| ethrex/crates/l2/prover/src/guest_program/src/input.rs     | 39    | +5   |
+------------------------------------------------------------+-------+------+
| ethrex/crates/l2/prover/src/guest_program/src/output.rs    | 52    | +21  |
+------------------------------------------------------------+-------+------+
| ethrex/crates/l2/prover/src/prover.rs                      | 160   | +9   |
+------------------------------------------------------------+-------+------+

Copy link
Contributor

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 decouples the guest program input/output structures for L1 and L2 proving by creating separate type definitions based on feature flags. This improves modularity and user experience for developers who only need L1 block proving capabilities.

Key Changes:

  • Separated ProgramInput into L1 (single block) and L2 (multiple blocks with additional fields) variants
  • Separated ProgramOutput into L1 (basic fields) and L2 (with additional L2-specific fields) variants
  • Refactored execution_program() function to have distinct implementations for L1 and L2

Reviewed Changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
crates/l2/prover/src/guest_program/src/input.rs Defines separate ProgramInput structures for L1 (with single block field) and L2 (with blocks vector and additional L2-specific fields like elasticity_multiplier, blob_commitment, etc.)
crates/l2/prover/src/guest_program/src/output.rs Creates distinct ProgramOutput structures for L1 (with basic fields) and L2 (with additional L2-specific fields like l1messages_merkle_root, privileged_transactions_hash, and blob_versioned_hash) along with separate encode() implementations
crates/l2/prover/src/guest_program/src/execution.rs Separates execution_program() into L1 and L2 variants with appropriate parameter handling; L1 version now uses the constant ELASTICITY_MULTIPLIER and converts single block to slice
crates/l2/prover/src/prover.rs Updates ProgramInput construction to conditionally extract single block for L1 or use full blocks vector for L2 based on feature flags

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

serde::Serialize, serde::Deserialize, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive,
)]
pub struct ProgramInput {
/// blocks to execute
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

The comment starts with a lowercase letter "blocks to execute" while the corresponding L1 comment starts with an uppercase "Block to execute". For consistency, consider capitalizing this to "Blocks to execute".

Suggested change
/// blocks to execute
/// Blocks to execute

Copilot uses AI. Check for mistakes.
Comment on lines +43 to +73

/// Public output variables exposed by the zkVM execution program. Some of these are part of
/// the program input.
#[cfg(not(feature = "l2"))]
#[derive(Serialize, Deserialize)]
pub struct ProgramOutput {
/// initial state trie root hash
pub initial_state_hash: H256,
/// final state trie root hash
pub final_state_hash: H256,
/// hash of the last block in a batch
pub last_block_hash: H256,
/// chain_id of the network
pub chain_id: U256,
/// amount of non-privileged transactions
pub non_privileged_count: U256,
}

#[cfg(not(feature = "l2"))]
impl ProgramOutput {
pub fn encode(&self) -> Vec<u8> {
[
self.initial_state_hash.to_fixed_bytes(),
self.final_state_hash.to_fixed_bytes(),
self.last_block_hash.to_fixed_bytes(),
self.chain_id.to_big_endian(),
self.non_privileged_count.to_big_endian(),
]
.concat()
}
}
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

[nitpick] The L1 ProgramOutput struct and its encode() implementation are duplicated from the L2 version. Consider using a macro or shared implementation to reduce code duplication and make maintenance easier. For example, you could define common fields in a macro and compose the different variants.

Copilot uses AI. Check for mistakes.
pub initial_state_hash: H256,
/// final state trie root hash
pub final_state_hash: H256,
/// hash of the last block in a batch
Copy link

Copilot AI Nov 13, 2025

Choose a reason for hiding this comment

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

The comment says "hash of the last block in a batch", but in the L1 context (non-l2 feature), only a single block is processed, not a batch. Consider updating the comment to reflect this, e.g., "hash of the block" or "hash of the last block".

Suggested change
/// hash of the last block in a batch
/// hash of the block

Copilot uses AI. Check for mistakes.
ilitteri and others added 2 commits November 13, 2025 13:10
ilitteri added 3 commits November 14, 2025 19:21
h
:w
erge branch 'decouple_guest_io' of github.com:lambdaclass/ethrex into decouple_guest_io
@jrchatruc jrchatruc added this pull request to the merge queue Nov 19, 2025
Merged via the queue into main with commit 926247b Nov 19, 2025
36 checks passed
@jrchatruc jrchatruc deleted the decouple_guest_io branch November 19, 2025 14:51
ilitteri added a commit that referenced this pull request Nov 19, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L2 Rollup client

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

4 participants