Skip to content

Conversation

@gianbelinche
Copy link
Contributor

Motivation
We want to add the performance improvement done in L1 with the block pipelining also for the L2.

Description
Adds the add_l2_block_pipeline function to the blockchain and uses it for regenerating the blockchain from checkpoints.

Copilot AI review requested due to automatic review settings December 4, 2025 21:04
@github-actions github-actions bot added the L2 Rollup client label Dec 4, 2025
@gianbelinche gianbelinche changed the title feat(l2): Add l2 block pipelined feat(l2): add l2 block pipelined Dec 4, 2025
@github-actions
Copy link

github-actions bot commented Dec 4, 2025

Lines of code report

Total lines added: 30
Total lines removed: 42
Total lines changed: 72

Detailed view
+-------------------------------------------------------+-------+------+
| File                                                  | Lines | Diff |
+-------------------------------------------------------+-------+------+
| ethrex/crates/blockchain/blockchain.rs                | 1604  | +27  |
+-------------------------------------------------------+-------+------+
| ethrex/crates/l2/sequencer/l1_committer.rs            | 1194  | -42  |
+-------------------------------------------------------+-------+------+
| ethrex/crates/networking/p2p/rlpx/l2/l2_connection.rs | 468   | +3   |
+-------------------------------------------------------+-------+------+

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 introduces L2 block pipelining to improve performance when processing L2 blocks, similar to the existing L1 block pipelining optimization. The implementation adds a new add_l2_block_pipeline function that executes and merkleizes blocks concurrently in separate threads, leveraging a pre-initialized VM for re-executing already validated blocks from checkpoints.

Key Changes

  • Added execute_l2_block_pipeline and add_l2_block_pipeline functions to the blockchain that take a pre-initialized VM and parent header for efficient block re-execution
  • Refactored checkpoint regeneration in L1 committer to use the new pipelined approach instead of manual execution and merkleization
  • Updated block processing in P2P connections and command-line operations to use the pipelined variant for performance gains

Reviewed changes

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

File Description
crates/blockchain/blockchain.rs Adds execute_l2_block_pipeline and add_l2_block_pipeline functions that implement concurrent execution and merkleization for L2 blocks using a pre-initialized VM
crates/l2/sequencer/l1_committer.rs Refactors checkpoint generation and batch production to use add_l2_block_pipeline instead of manual block execution and state updates, simplifying the code and improving performance
crates/networking/p2p/rlpx/l2/l2_connection.rs Updates block processing to use add_block_pipeline instead of add_block for performance improvement
cmd/ethrex/l2/command.rs Changes checkpoint import to use add_block_pipeline instead of add_block for faster block execution

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

Comment on lines 1145 to 1162
pub fn add_l2_block_pipeline(
&self,
block: Block,
parent_header: &BlockHeader,
vm: &mut Evm,
) -> Result<(), ChainError> {
let (res, account_updates_list) =
self.execute_l2_block_pipeline(&block, parent_header, vm)?;

self.store_block(
block,
account_updates_list,
BlockExecutionResult {
receipts: res.receipts,
requests: vec![],
},
)
}
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

Missing documentation for this public function. Consider adding a doc comment that explains:

  • The purpose of this L2-specific pipeline variant
  • Why it takes a pre-initialized VM and parent_header as parameters (unlike add_block_pipeline)
  • When it should be used (e.g., for checkpoint regeneration/re-execution of already validated blocks)

Copilot uses AI. Check for mistakes.
Comment on lines 191 to 241
fn execute_l2_block_pipeline(
&self,
block: &Block,
parent_header: &BlockHeader,
vm: &mut Evm,
) -> Result<(BlockExecutionResult, AccountUpdatesList), ChainError> {
let queue_length = AtomicUsize::new(0);
let queue_length_ref = &queue_length;
let mut max_queue_length = 0;
let (execution_result, account_updates_list) = std::thread::scope(|s| {
let max_queue_length_ref = &mut max_queue_length;
let (tx, rx) = channel();
let execution_handle = std::thread::Builder::new()
.name("block_executor_execution".to_string())
.spawn_scoped(s, move || -> Result<_, ChainError> {
let execution_result =
vm.execute_block_pipeline(block, tx, queue_length_ref)?;

Ok(execution_result)
})
.expect("Failed to spawn block_executor exec thread");
let parent_header_ref = &parent_header; // Avoid moving to thread
let merkleize_handle = std::thread::Builder::new()
.name("block_executor_merkleizer".to_string())
.spawn_scoped(s, move || -> Result<_, StoreError> {
let account_updates_list = self.handle_merkleization(
s,
rx,
parent_header_ref,
queue_length_ref,
max_queue_length_ref,
)?;
Ok(account_updates_list)
})
.expect("Failed to spawn block_executor merkleizer thread");
(
execution_handle.join().unwrap_or_else(|_| {
Err(ChainError::Custom("execution thread panicked".to_string()))
}),
merkleize_handle.join().unwrap_or_else(|_| {
Err(StoreError::Custom(
"merklization thread panicked".to_string(),
))
}),
)
});
let execution_result = execution_result?;
let account_updates_list = account_updates_list?;

Ok((execution_result, account_updates_list))
}
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

Missing documentation for this private function. Consider adding a doc comment explaining:

  • The purpose of this L2-specific execution pipeline
  • Why it differs from execute_block_pipeline (no validation, takes pre-initialized VM)
  • The threading/pipelining strategy being employed

Copilot uses AI. Check for mistakes.
Comment on lines 1157 to 1160
BlockExecutionResult {
receipts: res.receipts,
requests: vec![],
},
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

The requests from the execution result (res.requests) are being discarded and replaced with an empty vector. While this maintains the existing behavior from the refactored code, consider:

  1. Using res directly (like add_block_pipeline does on line 1175) if requests should be preserved
  2. Adding a comment explaining why requests are intentionally discarded for L2 blocks if this is the intended behavior
Suggested change
BlockExecutionResult {
receipts: res.receipts,
requests: vec![],
},
res,

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

L2 Rollup client

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants