feat(l2): shared bridge forced inclusion#5477
Conversation
There was a problem hiding this comment.
Pull request overview
This PR implements forced inclusion of cross-chain messages for shared bridge environments. The core change ensures L2s cannot avoid processing messages from other L2s by preventing commitment of batches with non-privileged transactions until all expired messages are included. The implementation tracks message hashes per source chain and validates their inclusion through rolling hashes computed by the prover.
Key changes:
- Introduces forced inclusion mechanism where expired messages block non-privileged transaction inclusion
- Replaces merkle root verification with direct message hash tracking and rolling hash validation
- Renames privileged transaction terminology from "deposits" to "l1_in_messages" and "l2_in_messages" for clarity
Reviewed changes
Copilot reviewed 43 out of 50 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| docs/l2/fundamentals/shared_bridge.md | Documents forced inclusion mechanism and updated cross-chain message flow |
| crates/networking/p2p/rlpx/l2/messages.rs | Updates Batch serialization to include rolling hashes and remove merkle roots |
| crates/l2/utils/state_reconstruct.rs | Refactors batch reconstruction to compute rolling hashes for L1/L2 inbound messages |
| crates/l2/utils/error.rs | Adds error variants for privileged transaction and integer conversion failures |
| crates/l2/tests/shared_bridge.rs | Adds test verifying forced inclusion prevents batch verification |
| crates/l2/storage/src/store_db/sql.rs | Updates database schema to store rolling hashes and non-privileged transaction counts |
| crates/l2/storage/src/store_db/in_memory.rs | Updates in-memory storage to match SQL store changes |
| crates/l2/storage/src/store.rs | Updates store API to retrieve rolling hashes instead of message lists |
| crates/l2/storage/src/api.rs | Updates storage API signatures for rolling hash access |
| crates/l2/sequencer/l1_watcher.rs | Changes message verification from merkle proofs to pending message hash checks |
| crates/l2/sequencer/l1_committer.rs | Updates batch commitment to include rolling hashes and message hash lists |
| crates/l2/sequencer/errors.rs | Adds error for invalid privileged transactions |
| crates/l2/sequencer/block_producer/payload_builder.rs | Removes chain-specific privileged transaction filtering |
| crates/l2/sdk/src/sdk.rs | Adds functions to query pending L2 messages and removes message verification |
| crates/l2/sdk/contract_utils/src/compile.rs | Enables Solidity optimizer to manage bytecode size |
| crates/l2/prover/src/guest_program/src/output.rs | Updates prover output to include rolling hashes instead of merkle roots |
| crates/l2/prover/src/guest_program/src/execution.rs | Refactors prover to compute rolling hashes for message validation |
| crates/l2/networking/rpc/rpc.rs | Adds RPC endpoint for batch lookup by block number |
| crates/l2/networking/rpc/l2/messages.rs | Removes L2 message proof generation RPC method |
| crates/l2/networking/rpc/l2/batch.rs | Adds handler for batch retrieval by block number |
| crates/l2/networking/rpc/clients.rs | Updates client to support batch retrieval by block |
| crates/l2/monitor/widget/l1_to_l2_messages.rs | Updates widget to use renamed pending messages function |
| crates/l2/monitor/widget/batches.rs | Updates batch display to use renamed message hash field |
| crates/l2/docker-compose.yaml | Adds log level environment variable configuration |
| crates/l2/contracts/src/l1/interfaces/IRouter.sol | Updates router interface to send multiple message hashes |
| crates/l2/contracts/src/l1/interfaces/IOnChainProposer.sol | Updates proposer interface for rolling hash commitment |
| crates/l2/contracts/src/l1/interfaces/ICommonBridge.sol | Updates bridge interface for message hash tracking |
| crates/l2/contracts/src/l1/based/interfaces/IOnChainProposer.sol | Adds non-privileged transaction count to based proposer interface |
| crates/l2/contracts/src/l1/based/OnChainProposer.sol | Implements forced inclusion check in based proposer |
| crates/l2/contracts/src/l1/Router.sol | Implements multi-hash message sending and removes merkle verification |
| crates/l2/contracts/src/l1/OnChainProposer.sol | Implements rolling hash verification and forced inclusion enforcement |
| crates/l2/contracts/src/l1/CommonBridge.sol | Implements message hash tracking and expiration checking |
| crates/l2/common/src/privileged_transactions.rs | Adds function to extract L2 inbound messages from transactions |
| crates/l2/common/src/messages.rs | Updates L2Message structure and encoding to include source chain ID |
| crates/l2/based/block_fetcher.rs | Adds chain_id parameter to batch reconstruction |
| crates/common/types/transaction.rs | Includes chain_id in privileged transaction hash computation |
| crates/common/types/l2/batch.rs | Updates Batch structure with rolling hashes |
| crates/common/types/l2/balance_diff.rs | Adds message_hashes field to BalanceDiff |
| cmd/ethrex/l2/deployer.rs | Updates bridge initialization with chain_id parameter |
| cmd/ethrex/l2/command.rs | Passes chain_id to batch reconstruction |
| cmd/ethrex/cli.rs | Adds environment variable support for log level |
| .github/workflows/pr-main_l2.yaml | Adds forced inclusion test matrix and debug logging |
| .github/workflows/pr-main_l1_l2_dev.yaml | Fixes environment file location for tests |
Comments suppressed due to low confidence (4)
crates/l2/tests/shared_bridge.rs:1
- Use
line.starts_with('#')with a character literal instead of a string literal for better performance and idiomatic code.
crates/l2/tests/shared_bridge.rs:1 - Corrected spelling of 'porpuse' to 'purpose'.
crates/l2/sequencer/l1_committer.rs:1 - The function signature string spans multiple lines. Consider keeping it on a single line or using a more readable format to improve maintainability.
crates/l2/storage/src/store_db/sql.rs:1 - Corrected spelling of 'pendinL2MessagesLength' to 'pendingL2MessagesLength' in function call.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| long = "log.level", | ||
| default_value_t = Level::INFO, | ||
| value_name = "LOG_LEVEL", | ||
| env = "ETHREX_LOG_LEVEL", |
There was a problem hiding this comment.
RUST_LOG does the job too
There was a problem hiding this comment.
Here when encoding an L2Message we are not encoding the dest_chain_id. Can this be a problem given that when getting the L2 Message hash we do keccak(msg.encode())? I mean, 2 equal messages to different L2s could possibly have the same hash. Is that a problem or is it intentional?
…red_bridge_forced_inclusion
…16 and bytes32[] memory.
Motivation
In a shared bridge environment, we need a way to enforce L2s to include messages from other L2s.
We take the same approach as with deposits:
Description
l1_committerto commit thel2_out_message_hashesand the rolling hash of received processed messages in the batch.Batchstruct:l2_in_message_rolling_hashesfield.l2_message_hashes, since they are now included in theBalanceDiffstruct.l2_messages_merkle_rootrelated logic. Since we now send all message hashes, the Merkle root is no longer needed.privileged transactions | depositstol1_in_messagesthroughout the codebase. A privileged transaction represents a message from another chain (L1 or L2).depositswas also being used to refer to L1 inbound messages, but messages can be more than simple deposits.L2RollingHashes.