diff --git a/.github/workflows/main_prover.yaml b/.github/workflows/main_prover.yaml index 1987cebed4d..6c009a49058 100644 --- a/.github/workflows/main_prover.yaml +++ b/.github/workflows/main_prover.yaml @@ -51,7 +51,7 @@ jobs: # if: ${{ always() && github.event_name == 'merge_group' }} run: | cd crates/l2 - make build-prover + make build-prover PROVER=sp1 - name: Build test # if: ${{ always() && github.event_name == 'merge_group' }} @@ -61,11 +61,11 @@ jobs: - name: Start L1 & Deploy contracts # if: ${{ always() && github.event_name == 'merge_group' }} run: | - touch cmd/.env + touch .env cd crates/l2 DOCKER_ETHREX_WORKDIR=/usr/local/bin \ - ETHREX_DEPLOYER_DEPLOY_RICH=true \ - ETHREX_DEPLOYER_SP1_DEPLOY_VERIFIER=true \ + ETHREX_DEPLOYER_DEPLOY_SP1_VERIFIER=true \ + ETHREX_DEPLOYER_SP1_VERIFICATION_KEY=$(cat prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk) \ docker compose up --build contract_deployer - name: Ensure admin permissions in _work @@ -79,7 +79,7 @@ jobs: ETHREX_PROPOSER_BLOCK_TIME=12000 \ ETHREX_COMMITTER_COMMIT_TIME=30000 \ ETHREX_WATCHER_WATCH_INTERVAL=1000 \ - docker compose up --build --detach --no-deps ethrex_l2 + docker compose up --detach --no-deps ethrex_l2 - name: Run test # if: ${{ always() && github.event_name == 'merge_group' }} diff --git a/.github/workflows/pr-main_l2.yaml b/.github/workflows/pr-main_l2.yaml index a553cececdc..3ff50b3e32b 100644 --- a/.github/workflows/pr-main_l2.yaml +++ b/.github/workflows/pr-main_l2.yaml @@ -40,10 +40,13 @@ jobs: ~/.risc0/bin/rzup install risc0-groth16 ~/.risc0/bin/rzup install rust - - name: Create placeholder SP1 ELF + - name: Create placeholder for SP1 and RISC0 VKs run: | mkdir -p crates/l2/prover/src/guest_program/src/sp1/out touch crates/l2/prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-elf + touch crates/l2/prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk + mkdir -p crates/l2/prover/src/guest_program/src/risc0/out + touch crates/l2/prover/src/guest_program/src/risc0/out/riscv32im-risc0-vk - name: Run cargo check run: cargo check --workspace @@ -141,15 +144,14 @@ jobs: - name: Start L1 & Deploy contracts run: | - touch cmd/.env + touch .env cd crates/l2 DOCKER_ETHREX_WORKDIR=/usr/local/bin \ - ETHREX_DEPLOYER_DEPLOY_RICH=true \ - ETHREX_DEPLOYER_PICO_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_SP1_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_RISC0_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ + docker compose up -d ethrex_l1 + DOCKER_ETHREX_WORKDIR=/usr/local/bin \ ETHREX_L2_VALIDIUM=${{ matrix.validium }} \ - docker compose up contract_deployer + ETHREX_DEPLOYER_BRIDGE_OWNER_ADDRESS=0x4417092B70a3E5f10Dc504d0947DD256B965fc62 \ + docker compose up --no-deps --exit-code-from contract_deployer contract_deployer - name: Start Sequencer run: | @@ -205,16 +207,14 @@ jobs: - name: Start L1 & Deploy contracts run: | - touch cmd/.env + touch .env cd crates/l2 DOCKER_ETHREX_WORKDIR=/usr/local/bin \ - ETHREX_DEPLOYER_DEPLOY_RICH=true \ - ETHREX_DEPLOYER_PICO_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_SP1_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_RISC0_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ + docker compose up -d ethrex_l1 + DOCKER_ETHREX_WORKDIR=/usr/local/bin \ ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS=true \ - COMPILE_CONTRACTS=true \ - docker compose up contract_deployer + ETHREX_DEPLOYER_BRIDGE_OWNER_ADDRESS=0x4417092B70a3E5f10Dc504d0947DD256B965fc62 \ + docker compose up --no-deps --exit-code-from contract_deployer contract_deployer - name: Install rex run: | @@ -227,7 +227,6 @@ jobs: - name: Register sequencer run: | - cd cmd SEQUENCER_REGISTRY=$(grep ETHREX_DEPLOYER_SEQUENCER_REGISTRY .env | cut -d= -f2) export SEQUENCER_REGISTRY @@ -240,13 +239,11 @@ jobs: - name: Start Sequencer run: | - cd cmd SEQUENCER_REGISTRY=$(grep ETHREX_DEPLOYER_SEQUENCER_REGISTRY .env | cut -d= -f2) export SEQUENCER_REGISTRY - cd ../crates/l2 + cd crates/l2 DOCKER_ETHREX_WORKDIR=/usr/local/bin \ - ETHREX_COMMITTER_VALIDIUM=false \ ETHREX_COMMITTER_COMMIT_TIME=15000 \ ETHREX_WATCHER_BLOCK_DELAY=0 \ ETHREX_BASED=true \ @@ -320,23 +317,37 @@ jobs: cd crates/l2/tee/quote-gen make image.raw - - name: Start L1 & Deploy contracts + - name: Start L1 run: | - touch cmd/.env + touch .env cd crates/l2 - make init-l1-docker; - ETHREX_DEPLOYER_DEPLOY_RICH=true \ - ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER=true \ + make init-l1-docker + + - name: Deploy TDX contracts + run: | + cd crates/l2/tee/contracts + # This address is result of a CREATE2 deploy. Should be replaced if the contract change + ON_CHAIN_PROPOSER=0x937bc1a524f22de858203b2cbbad073a98fff0b5 \ + RPC_URL=http://localhost:8545 \ + PRIVATE_KEY=0x941e103320615d394a55708be13e45994c7d93b932b064dbcb2b511fe3254e2e \ ETHREX_TDX_DEV_MODE=true \ + make deploy-all + + - name: Deploy L1 contracts + run: | + cd crates/l2 + ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER_ADDRESS=$(cat tee/contracts/deploydeps/automata-dcap-attestation/evm/deployment/TDXVerifier) \ make deploy-l1 - name: Start Sequencer and test run: | cd crates/l2 + make rm-db-l2 ETHREX_WATCHER_BLOCK_DELAY=0 \ PROOF_COORDINATOR_ADDRESS=0.0.0.0 \ ETHREX_COMMITTER_COMMIT_TIME=15000 \ ETHREX_PROOF_COORDINATOR_TDX_PRIVATE_KEY=0x39725efee3fb28614de3bacaffe4cc4bd8c436257e2c8bb887c4b5c4be45e76d \ + ETHREX_NO_MONITOR=true \ make init-l2 & sleep 30 cd tee/quote-gen/ @@ -384,15 +395,13 @@ jobs: - name: Start L1 & Deploy contracts run: | - touch cmd/.env + touch .env cd crates/l2 DOCKER_ETHREX_WORKDIR=/usr/local/bin \ - ETHREX_DEPLOYER_DEPLOY_RICH=true \ - ETHREX_DEPLOYER_PICO_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_SP1_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - ETHREX_DEPLOYER_RISC0_CONTRACT_ADDRESS=0x00000000000000000000000000000000000000aa \ - COMPILE_CONTRACTS=true \ - docker compose up contract_deployer + docker compose up -d ethrex_l1 + DOCKER_ETHREX_WORKDIR=/usr/local/bin \ + ETHREX_DEPLOYER_BRIDGE_OWNER_ADDRESS=0x4417092B70a3E5f10Dc504d0947DD256B965fc62 \ + docker compose up --no-deps --exit-code-from contract_deployer contract_deployer - name: Run tests run: | diff --git a/cmd/ethrex/l2/command.rs b/cmd/ethrex/l2/command.rs index e9782f0a47e..b230c0d0664 100644 --- a/cmd/ethrex/l2/command.rs +++ b/cmd/ethrex/l2/command.rs @@ -202,8 +202,8 @@ pub enum Command { #[arg( long, value_parser = parse_private_key, - env = "SEQUENCER_PRIVATE_KEY", - help = "The private key of the sequencer", + env = "SEQUENCER_PRIVATE_KEY", + help = "The private key of the sequencer", help_heading = "Sequencer account options", group = "sequencer_signing", )] diff --git a/cmd/ethrex/l2/deployer.rs b/cmd/ethrex/l2/deployer.rs index f0ccf7c2633..bc745e17a99 100644 --- a/cmd/ethrex/l2/deployer.rs +++ b/cmd/ethrex/l2/deployer.rs @@ -1,342 +1,364 @@ use std::{ fs::{File, OpenOptions, read_to_string}, - io::{BufWriter, Write}, + io::{BufReader, BufWriter, Write}, path::PathBuf, process::{Command, Stdio}, str::FromStr, }; use bytes::Bytes; -use clap::Parser; +use clap::{ArgAction, Parser}; use ethrex_common::{ - Address, U256, + Address, H160, U256, types::{Genesis, TxType}, }; -use ethrex_l2::utils::test_data_io::read_genesis_file; -use ethrex_l2_common::{calldata::Value, utils::get_address_from_secret_key}; +use ethrex_config::networks::LOCAL_DEVNETL2_GENESIS_CONTENTS; +use ethrex_l2::sequencer::utils::DEV_MODE_ADDRESS; +use ethrex_l2_common::calldata::Value; use ethrex_l2_rpc::signer::{LocalSigner, Signer}; use ethrex_l2_sdk::{ - build_generic_tx, calldata::encode_calldata, create2_deploy_from_bytecode, - deploy_with_proxy_from_bytecode, initialize_contract, send_generic_transaction, - wait_for_transaction_receipt, + DeployError, build_generic_tx, call_contract, deploy_contract, deploy_with_proxy, + send_generic_transaction, }; use ethrex_rpc::{ EthClient, - clients::Overrides, + clients::{EthClientError, Overrides, eth::errors::CalldataEncodeError}, types::block_identifier::{BlockIdentifier, BlockTag}, }; use keccak_hash::H256; use tracing::{debug, error, info, trace, warn}; -use ethrex_l2_sdk::DeployError; -use ethrex_rpc::clients::{EthClientError, eth::errors::CalldataEncodeError}; - -use clap::ArgAction; -use ethrex_common::H160; -use hex::FromHexError; use secp256k1::SecretKey; -use ethrex_config::networks::{ - LOCAL_DEVNET_GENESIS_CONTENTS, LOCAL_DEVNET_PRIVATE_KEYS, LOCAL_DEVNETL2_GENESIS_CONTENTS, -}; +use crate::{l2::EthOptions, utils::parse_private_key}; + +/// Bytecode of the OnChainProposer contract. +/// This is generated by the [build script](./build.rs). +const ON_CHAIN_PROPOSER_BYTECODE: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/contracts/solc_out/OnChainProposer.bytecode" +)); + +/// Bytecode of the CommonBridge contract. +/// This is generated by the [build script](./build.rs). +const COMMON_BRIDGE_BYTECODE: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/contracts/solc_out/CommonBridge.bytecode" +)); + +/// Bytecode of the based OnChainProposer contract. +/// This is generated by the [build script](./build.rs). +const ON_CHAIN_PROPOSER_BASED_BYTECODE: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/contracts/solc_out/OnChainProposerBased.bytecode" +)); + +/// Bytecode of the SequencerRegistry contract. +/// This is generated by the [build script](./build.rs). +const SEQUENCER_REGISTRY_BYTECODE: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/contracts/solc_out/SequencerRegistry.bytecode" +)); + +/// Bytecode of the SP1Verifier contract. +/// This is generated by the [build script](./build.rs). +const SP1_VERIFIER_BYTECODE: &[u8] = include_bytes!(concat!( + env!("OUT_DIR"), + "/contracts/solc_out/SP1Verifier.bytecode" +)); + +/// SP1 verification key. +#[cfg(feature = "sp1")] +const SP1_VERIFICATION_KEY: Option<&str> = Some(include_str!(concat!( + "../../../crates/l2/prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk" +))); +#[cfg(not(feature = "sp1"))] +const SP1_VERIFICATION_KEY: Option<&str> = None; + +/// RISC0 verification key. +#[cfg(feature = "risc0")] +const RISC0_VERIFICATION_KEY: Option<&str> = Some(include_str!(concat!( + "../../../crates/l2/prover/src/guest_program/src/risc0/out/riscv32im-risc0-vk" +))); +#[cfg(not(feature = "risc0"))] +const RISC0_VERIFICATION_KEY: Option<&str> = None; + +const INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE_BASED: &str = "initialize(bool,address,address,address,address,address,bytes32,bytes32,bytes32,address,uint256)"; +const INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE: &str = "initialize(bool,address,address,address,address,address,bytes32,bytes32,bytes32,address[],uint256)"; +const INITIALIZE_BRIDGE_ADDRESS_SIGNATURE: &str = "initializeBridgeAddress(address)"; +const TRANSFER_OWNERSHIP_SIGNATURE: &str = "transferOwnership(address)"; +const ACCEPT_OWNERSHIP_SIGNATURE: &str = "acceptOwnership()"; +const INITIALIZE_COMMON_BRIDGE_SIGNATURE: &str = "initialize(address,address,uint256)"; +const INITIALIZE_SEQUENCER_REGISTRY_SIGNATURE: &str = "initialize(address,address)"; #[derive(Parser)] pub struct DeployerOptions { + #[command(flatten)] + pub eth_options: EthOptions, + // Deployer options + /// Private key from which the contracts will be deployed from. #[arg( - long = "eth-rpc-url", - value_name = "RPC_URL", - env = "ETHREX_ETH_RPC_URL", - help_heading = "Eth options" - )] - pub rpc_url: String, - #[arg( - long, - default_value = "10000000000", - value_name = "UINT64", - env = "ETHREX_MAXIMUM_ALLOWED_MAX_FEE_PER_GAS", - help_heading = "Eth options" - )] - pub maximum_allowed_max_fee_per_gas: u64, - #[arg( - long, - default_value = "10000000000", - value_name = "UINT64", - env = "ETHREX_MAXIMUM_ALLOWED_MAX_FEE_PER_BLOB_GAS", - help_heading = "Eth options" - )] - pub maximum_allowed_max_fee_per_blob_gas: u64, - #[arg( - long, + long = "deployer.private-key", value_name = "PRIVATE_KEY", value_parser = parse_private_key, env = "ETHREX_DEPLOYER_L1_PRIVATE_KEY", help_heading = "Deployer options", - help = "Private key corresponding of a funded account that will be used for L1 contract deployment.", )] pub private_key: SecretKey, + /// Write the addresses of deployed contracts in a .env file format. #[arg( - long, - default_value = "10", - value_name = "UINT64", - env = "ETHREX_ETH_MAX_NUMBER_OF_RETRIES", - help_heading = "Eth options" - )] - pub max_number_of_retries: u64, - #[arg( - long, - default_value = "2", - value_name = "UINT64", - env = "ETHREX_ETH_BACKOFF_FACTOR", - help_heading = "Eth options" - )] - pub backoff_factor: u64, - #[arg( - long, - default_value = "96", - value_name = "UINT64", - env = "ETHREX_ETH_MIN_RETRY_DELAY", - help_heading = "Eth options" - )] - pub min_retry_delay: u64, - #[arg( - long, - default_value = "1800", - value_name = "UINT64", - env = "ETHREX_ETH_MAX_RETRY_DELAY", - help_heading = "Eth options" - )] - pub max_retry_delay: u64, - #[arg( - long, + long = "deployer.env-file", value_name = "PATH", env = "ETHREX_DEPLOYER_ENV_FILE_PATH", - help_heading = "Deployer options", - help = "Path to the .env file." + help_heading = "Deployer options" )] pub env_file_path: Option, + /// Path to a file containing a list private keys, one per line. + /// + /// If set, a deposit will be done from those accounts via the newly created bridge. + /// Used for dev purposes. #[arg( - long, - default_value = "false", - value_name = "BOOLEAN", - env = "ETHREX_DEPLOYER_DEPLOY_RICH", - action = ArgAction::SetTrue, - help_heading = "Deployer options", - help = "If set to true, it will deposit ETH from L1 rich wallets to L2 accounts." - )] - pub deposit_rich: bool, - #[arg( - long, - value_name = "PATH", - env = "ETHREX_DEPLOYER_PRIVATE_KEYS_FILE_PATH", - required_if_eq("deposit_rich", "true"), - help_heading = "Deployer options", - help = "Path to the file containing the private keys of the rich accounts. The default is ../../fixtures/keys/private_keys_l1.txt" - )] - pub private_keys_file_path: Option, - #[arg( - long, + long = "deployer.deposit-accounts", value_name = "PATH", - env = "ETHREX_DEPLOYER_GENESIS_L1_PATH", - required_if_eq("deposit_rich", "true"), - help_heading = "Deployer options", - help = "Path to the genesis file. The default is ../../fixtures/genesis/l1-dev.json" + env = "ETHREX_DEPLOYER_DEPOSIT_PRIVATE_KEYS_FILE_PATH", + help_heading = "Deployer options" )] - pub genesis_l1_path: Option, + pub deposit_private_keys_file: Option, + /// Salt to use with CREATE2 deterministic deployer. Defaults to random. #[arg( - long, - value_name = "PATH", - env = "ETHREX_DEPLOYER_GENESIS_L2_PATH", - help_heading = "Deployer options", - help = "Path to the l2 genesis file. The default is ../../fixtures/genesis/l2.json" + long = "deployer.deterministic-salt", + value_name = "H256", + env = "ETHREX_DEPLOYER_DETERMINISTIC_SALT", + help_heading = "Deployer options" )] - pub genesis_l2_path: PathBuf, + pub create2_salt: Option, + /// Address of the OnChainProposer's owner. Defaults to the deployer account. #[arg( - long = "committer.l1-address", - default_value = "0x3d1e15a1a55578f7c920884a9943b3b35d0d885b", + long = "deployer.on-chain-proposer-owner", value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_COMMITTER_L1_ADDRESS", - help_heading = "Deployer options", - help = "Address of the L1 committer account. This is the address of the account that commits the batches in L1." + env = "ETHREX_DEPLOYER_ON_CHAIN_PROPOSER_OWNER_ADDRESS", + help_heading = "Deployer options" )] - pub committer_l1_address: Address, + pub on_chain_proposer_owner: Option
, + /// Private key of the OnChainProposer's owner, used for accepting the ownership. #[arg( - long = "proof-sender.l1-address", - default_value = "0xE25583099BA105D9ec0A67f5Ae86D90e50036425", - value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_PROOF_SENDER_L1_ADDRESS", - help_heading = "Deployer options", - help = "Address of the L1 proof sender account. This is the address of the account that sends the proofs to be verified in L1." + long = "deployer.on-chain-proposer-owner-pk", + value_name = "PRIVATE_KEY", + env = "ETHREX_DEPLOYER_ON_CHAIN_PROPOSER_OWNER_PK", + conflicts_with = "on_chain_proposer_owner", + help_heading = "Deployer options" )] - pub proof_sender_l1_address: Address, - // TODO: This should work side by side with a risc0_deploy_verifier flag. + pub on_chain_proposer_owner_pk: Option, + /// Address of the CommonBridge' owner. Defaults to the deployer account. #[arg( - long = "risc0.verifier-address", + long = "deployer.bridge-owner", value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER", - required = true, // TODO: This should be required_unless_present = "risc0_deploy_verifier", - help_heading = "Deployer options", - help = "If set to 0xAA skip proof verification -> Only use in dev mode." + env = "ETHREX_DEPLOYER_BRIDGE_OWNER_ADDRESS", + help_heading = "Deployer options" )] - pub risc0_verifier_address: Option
, + pub bridge_owner: Option
, + /// Deploy the SP1 verifier contract and use its address. #[arg( - long = "sp1.verifier-address", - value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER", - required_if_eq("sp1_deploy_verifier", "false"), + long = "deployer.deploy-sp1", + value_name = "BOOL", + default_value = "false", + default_missing_value = "true", + num_args = 0..=1, + require_equals = true, + action = ArgAction::Set, + hide_possible_values = true, + env = "ETHREX_DEPLOYER_DEPLOY_SP1_VERIFIER", + conflicts_with = "sp1_verifier_address", help_heading = "Deployer options", - help = "If set to 0xAA skip proof verification -> Only use in dev mode." )] - pub sp1_verifier_address: Option
, + pub deploy_sp1_verifier: bool, + /// Deploy the TDX verifier contracts and use its address. #[arg( - long = "sp1.deploy-verifier", + long = "deployer.deploy-tdx", + value_name = "BOOL", default_value = "false", - value_name = "BOOLEAN", - action = ArgAction::SetTrue, - env = "ETHREX_DEPLOYER_SP1_DEPLOY_VERIFIER", - required_unless_present = "sp1_verifier_address", + default_missing_value = "true", + num_args = 0..=1, + require_equals = true, + action = ArgAction::Set, + hide_possible_values = true, + env = "ETHREX_DEPLOYER_DEPLOY_TDX_VERIFIER", + conflicts_with = "tdx_verifier_address", help_heading = "Deployer options", - help = "If set to true, it will deploy the contract and override the address above with the deployed one.", )] - pub sp1_deploy_verifier: bool, + pub deploy_tdx_verifier: bool, + + // L2 options + /// Path to the L2 genesis file #[arg( - long = "tdx.verifier-address", - value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER", - required_if_eq("tdx_deploy_verifier", "false"), - help_heading = "Deployer options", - help = "If set to 0xAA skip proof verification -> Only use in dev mode." + long = "l2.genesis", + value_name = "PATH", + env = "ETHREX_DEPLOYER_GENESIS_L2_PATH", + required_unless_present = "use_dev_genesis", + required_if_eq("use_dev_genesis", "false"), + help_heading = "L2 options" )] - pub tdx_verifier_address: Option
, + pub genesis_l2_path: Option, + /// Use a development-purpose genesis instead of a custom one. #[arg( - long = "tdx.deploy-verifier", + long = "l2.dev-genesis", + value_name = "BOOL", default_value = "false", - value_name = "BOOLEAN", - action = ArgAction::SetTrue, - env = "ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER", - required_unless_present = "tdx_verifier_address", - help_heading = "Deployer options", - help = "If set to true, it will deploy the contract and override the address above with the deployed one.", + default_missing_value = "true", + num_args = 0..=1, + require_equals = true, + action = ArgAction::Set, + hide_possible_values = true, + env = "ETHREX_DEPLOYER_DEV_GENESIS", + help_heading = "L2 options", )] - pub tdx_deploy_verifier: bool, + pub use_dev_genesis: bool, + /// Address of the account that commits the batches to L1. #[arg( - long = "aligned.aggregator-address", + long = "l2.l1-committer", + default_value = "0x3d1e15a1a55578f7c920884a9943b3b35d0d885b", value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS", - required = true, - help_heading = "Deployer options", - help = "If set to 0xAA skip proof verification -> Only use in dev mode." + env = "ETHREX_DEPLOYER_L1_COMMITTER_ADDRESS", + help_heading = "L2 options" )] - pub aligned_aggregator_address: Address, + pub l1_committer: Address, + /// Address of the account that sends the proofs to L1 to be verified. #[arg( - long, - default_value = "false", - value_name = "BOOLEAN", - action = ArgAction::SetTrue, - env = "ETHREX_DEPLOYER_RANDOMIZE_CONTRACT_DEPLOYMENT", - help_heading = "Deployer options", - help = "If set to false, the deployed contract addresses will be deterministic." + long = "l2.l1-proof-sender", + default_value = "0xE25583099BA105D9ec0A67f5Ae86D90e50036425", + value_name = "ADDRESS", + env = "ETHREX_DEPLOYER_L1_PROOF_SENDER_ADDRESS", + help_heading = "L2 options" )] - pub randomize_contract_deployment: bool, + pub l1_proof_sender: Address, + /// Run on validium mode, meaning it will not publish state diffs to the L1. #[arg( - long, + long = "l2.validium", + value_name = "BOOL", default_value = "false", - value_name = "BOOLEAN", - env = "ETHREX_L2_VALIDIUM", - help_heading = "Deployer options", - help = "If true, L2 will run on validium mode as opposed to the default rollup mode, meaning it will not publish state diffs to the L1." + default_missing_value = "true", + num_args = 0..=1, + require_equals = true, + action = ArgAction::Set, + hide_possible_values = true, + env = "ETHREX_DEPLOYER_VALIDIUM", + help_heading = "L2 options", )] pub validium: bool, + /// Deadline, in seconds, for the sequencer to process a privileged transaction. #[arg( - long, - value_name = "ADDRESS", - env = "ETHREX_ON_CHAIN_PROPOSER_OWNER", - help_heading = "Deployer options", - help = "Address of the owner of the OnChainProposer contract, who can upgrade the contract." + long = "l2.inclusion-max-wait", + value_name = "SECONDS", + default_value = "3000", + env = "ETHREX_DEPLOYER_ON_CHAIN_PROPOSER_INCUSION_MAX_WAIT", + help_heading = "L2 options" )] - pub on_chain_proposer_owner: Address, + pub inclusion_max_wait: u64, + + // Verifiers options + /// L1 address of the RISC0 verifier. If not set, contract will omit RISC0 verification. + // TODO: This should work side by side with a risc0_deploy_verifier flag. #[arg( - long, + long = "verifier.risc0", value_name = "ADDRESS", - env = "ETHREX_BRIDGE_OWNER", - help_heading = "Deployer options", - help = "Address of the owner of the CommonBridge contract, who can upgrade the contract." + env = "ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER_ADDRESS", + help_heading = "Verifiers options" )] - pub bridge_owner: Address, + pub risc0_verifier_address: Option
, + /// RISC0 Image ID (verification key). #[arg( - long, - value_name = "PRIVATE_KEY", - env = "ETHREX_ON_CHAIN_PROPOSER_OWNER_PK", - help_heading = "Deployer options", - help = "Private key of the owner of the OnChainProposer contract. If set, the deployer will send a transaction to accept the ownership.", - requires = "on_chain_proposer_owner" + long = "verifier.risc0-vk", + value_name = "PATH", + env = "ETHREX_DEPLOYER_RISC0_VERIFICATION_KEY", + conflicts_with = "risc0_vk_path", + help_heading = "Verifiers options" )] - pub on_chain_proposer_owner_pk: Option, + pub risc0_vk: Option, + /// Path to the RISC0 Image ID (verification key). #[arg( - long, - default_value_t = format!("{}/../../crates/l2/prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk", env!("CARGO_MANIFEST_DIR")), + long = "verifier.risc0-vk-path", value_name = "PATH", - env = "ETHREX_SP1_VERIFICATION_KEY_PATH", - help_heading = "Deployer options", - help = "Path to the SP1 verification key. This is used for proof verification." + env = "ETHREX_DEPLOYER_RISC0_VERIFICATION_KEY_PATH", + conflicts_with = "risc0_vk", + help_heading = "Verifiers options" )] - pub sp1_vk_path: String, + pub risc0_vk_path: Option, + /// L1 address of the SP1 verifier. If not set, contract will omit SP1 verification. #[arg( - long, - default_value_t = format!("{}/../../crates/l2/prover/src/guest_program/src/risc0/out/riscv32im-risc0-vk", env!("CARGO_MANIFEST_DIR")), + long = "verifier.sp1", + value_name = "ADDRESS", + env = "ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER_ADDRESS", + conflicts_with = "sp1_deploy_verifier", + help_heading = "Verifiers options" + )] + pub sp1_verifier_address: Option
, + /// SP1 verification key. + #[arg( + long = "verifier.sp1-vk", value_name = "PATH", - env = "ETHREX_RISC0_VERIFICATION_KEY_PATH", - help_heading = "Deployer options", - help = "Path to the Risc0 image id / verification key. This is used for proof verification." + env = "ETHREX_DEPLOYER_SP1_VERIFICATION_KEY", + conflicts_with = "sp1_vk_path", + help_heading = "Verifiers options" )] - pub risc0_vk_path: String, + pub sp1_vk: Option, + /// Path to the SP1 verification key. #[arg( - long, - default_value = "false", - value_name = "BOOLEAN", - env = "ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS", - action = ArgAction::SetTrue, - help_heading = "Deployer options", - help = "If set to true, it will deploy the SequencerRegistry contract and a modified OnChainProposer contract." + long = "verifier.sp1-vk-path", + value_name = "PATH", + env = "ETHREX_DEPLOYER_SP1_VERIFICATION_KEY_PATH", + conflicts_with = "sp1_vk", + help_heading = "Verifiers options" )] - pub deploy_based_contracts: bool, + pub sp1_vk_path: Option, + /// L1 address of the TDX verifier. If not set, contract will omit TDX verification. #[arg( - long, + long = "verifier.tdx", value_name = "ADDRESS", - env = "ETHREX_DEPLOYER_SEQUENCER_REGISTRY_OWNER", - required_if_eq("deploy_based_contracts", "true"), - help_heading = "Deployer options", - help = "Address of the owner of the SequencerRegistry contract, who can upgrade the contract." + env = "ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER_ADDRESS", + conflicts_with = "tdx_deploy_verifier", + help_heading = "Verifiers options" )] - pub sequencer_registry_owner: Option
, + pub tdx_verifier_address: Option
, + /// L1 address of the Aligned Aggregator. If not set, contract will omit Aligned verification. #[arg( - long, - default_value = "3000", - env = "ETHREX_ON_CHAIN_PROPOSER_INCUSION_MAX_WAIT", - help_heading = "Deployer options", - help = "Deadline in seconds for the sequencer to process a privileged transaction." + long = "verifier.aligned-aggregator", + value_name = "ADDRESS", + env = "ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS", + help_heading = "Verifiers options" )] - pub inclusion_max_wait: u64, + pub aligned_aggregator_address: Option
, + + // L2 Based options + /// Deploy the SequencerRegistry contract and the based version of OnChainProposer. #[arg( - long, + long = "deployer.based", + value_name = "BOOL", default_value = "false", - env = "ETHREX_USE_COMPILED_GENESIS", - help_heading = "Deployer options", - help = "Genesis data is extracted at compile time, used for development" + default_missing_value = "true", + num_args = 0..=1, + require_equals = true, + action = ArgAction::Set, + hide_possible_values = true, + env = "ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS", + help_heading = "L2 Based options", + )] + pub deploy_based_contracts: bool, + /// Address of the SequencerRegistry' owner. Defaults to the deployer account. + #[arg( + long = "deployer.sequencer-registry-owner", + value_name = "ADDRESS", + env = "ETHREX_DEPLOYER_SEQUENCER_REGISTRY_OWNER_ADDRESS", + help_heading = "L2 Based options" )] - pub use_compiled_genesis: bool, + pub sequencer_registry_owner: Option
, } impl Default for DeployerOptions { fn default() -> Self { Self { - rpc_url: "http://localhost:8545".to_string(), - maximum_allowed_max_fee_per_gas: 10_000_000_000, - maximum_allowed_max_fee_per_blob_gas: 10_000_000_000, - max_number_of_retries: 10, - backoff_factor: 2, - min_retry_delay: 96, - max_retry_delay: 1800, + eth_options: EthOptions::default(), #[allow(clippy::unwrap_used)] + // 0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 private_key: SecretKey::from_slice( H256([ 0x38, 0x5c, 0x54, 0x64, 0x56, 0xb6, 0xa6, 0x03, 0xa1, 0xcf, 0xca, 0xa9, 0xec, @@ -347,80 +369,41 @@ impl Default for DeployerOptions { ) .unwrap(), env_file_path: Some(PathBuf::from(".env")), - deposit_rich: true, - private_keys_file_path: None, - genesis_l1_path: Some("../../fixtures/genesis/l1-dev.json".into()), - genesis_l2_path: "../../fixtures/genesis/l2.json".into(), + deposit_private_keys_file: None, + genesis_l2_path: None, // 0x3d1e15a1a55578f7c920884a9943b3b35d0d885b - committer_l1_address: H160([ + l1_committer: H160([ 0x3d, 0x1e, 0x15, 0xa1, 0xa5, 0x55, 0x78, 0xf7, 0xc9, 0x20, 0x88, 0x4a, 0x99, 0x43, 0xb3, 0xb3, 0x5d, 0x0d, 0x88, 0x5b, ]), // 0xE25583099BA105D9ec0A67f5Ae86D90e50036425 - proof_sender_l1_address: H160([ + l1_proof_sender: H160([ 0xe2, 0x55, 0x83, 0x09, 0x9b, 0xa1, 0x05, 0xd9, 0xec, 0x0a, 0x67, 0xf5, 0xae, 0x86, 0xd9, 0x0e, 0x50, 0x03, 0x64, 0x25, ]), - risc0_verifier_address: Some(H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, - ])), - sp1_verifier_address: Some(H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, - ])), - sp1_deploy_verifier: false, - tdx_verifier_address: Some(H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, - ])), - tdx_deploy_verifier: false, - aligned_aggregator_address: H160([ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, - ]), - randomize_contract_deployment: false, + risc0_verifier_address: None, + sp1_verifier_address: None, + deploy_sp1_verifier: false, + tdx_verifier_address: None, + deploy_tdx_verifier: false, + aligned_aggregator_address: None, + create2_salt: None, validium: false, - // 0x4417092b70a3e5f10dc504d0947dd256b965fc62 - // Private Key: 0x941e103320615d394a55708be13e45994c7d93b932b064dbcb2b511fe3254e2e - // (also found on fixtures/keys/private_keys_l1.txt) - on_chain_proposer_owner: H160([ - 0x44, 0x17, 0x09, 0x2b, 0x70, 0xa3, 0xe5, 0xf1, 0x0d, 0xc5, 0x04, 0xd0, 0x94, 0x7d, - 0xd2, 0x56, 0xb9, 0x65, 0xfc, 0x62, - ]), - // 0x4417092b70a3e5f10dc504d0947dd256b965fc62 - bridge_owner: H160([ - 0x44, 0x17, 0x09, 0x2b, 0x70, 0xa3, 0xe5, 0xf1, 0x0d, 0xc5, 0x04, 0xd0, 0x94, 0x7d, - 0xd2, 0x56, 0xb9, 0x65, 0xfc, 0x62, - ]), + on_chain_proposer_owner: None, on_chain_proposer_owner_pk: None, - sp1_vk_path: format!( - "{}/../prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk", - env!("CARGO_MANIFEST_DIR") - ), - risc0_vk_path: format!( - "{}/../prover/src/guest_program/src/risc0/out/riscv32im-risc0-vk", - env!("CARGO_MANIFEST_DIR") - ), + bridge_owner: None, + sp1_vk: None, + risc0_vk: None, + sp1_vk_path: None, + risc0_vk_path: None, deploy_based_contracts: false, sequencer_registry_owner: None, inclusion_max_wait: 3000, - use_compiled_genesis: true, + use_dev_genesis: true, } } } -pub fn parse_private_key(s: &str) -> eyre::Result { - Ok(SecretKey::from_slice(&parse_hex(s)?)?) -} - -pub fn parse_hex(s: &str) -> eyre::Result { - match s.strip_prefix("0x") { - Some(s) => hex::decode(s).map(Into::into), - None => hex::decode(s).map(Into::into), - } -} - #[derive(Debug, thiserror::Error)] pub enum DeployerError { #[error("The path is not a valid utf-8 string")] @@ -445,53 +428,10 @@ pub enum DeployerError { "Contract bytecode not found. Make sure to compile the deployer with `COMPILE_CONTRACTS` set." )] BytecodeNotFound, - #[error("Failed to parse genesis")] - Genesis, + #[error("Failed to read or parse genesis: {0}")] + GenesisError(String), } -/// Bytecode of the OnChainProposer contract. -/// This is generated by the [build script](./build.rs). -const ON_CHAIN_PROPOSER_BYTECODE: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/contracts/solc_out/OnChainProposer.bytecode" -)); - -/// Bytecode of the CommonBridge contract. -/// This is generated by the [build script](./build.rs). -const COMMON_BRIDGE_BYTECODE: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/contracts/solc_out/CommonBridge.bytecode" -)); - -/// Bytecode of the based OnChainProposer contract. -/// This is generated by the [build script](./build.rs). -const ON_CHAIN_PROPOSER_BASED_BYTECODE: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/contracts/solc_out/OnChainProposerBased.bytecode" -)); - -/// Bytecode of the SequencerRegistry contract. -/// This is generated by the [build script](./build.rs). -const SEQUENCER_REGISTRY_BYTECODE: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/contracts/solc_out/SequencerRegistry.bytecode" -)); - -/// Bytecode of the SP1Verifier contract. -/// This is generated by the [build script](./build.rs). -const SP1_VERIFIER_BYTECODE: &[u8] = include_bytes!(concat!( - env!("OUT_DIR"), - "/contracts/solc_out/SP1Verifier.bytecode" -)); - -const INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE_BASED: &str = "initialize(bool,address,address,address,address,address,bytes32,bytes32,bytes32,address,uint256)"; -const INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE: &str = "initialize(bool,address,address,address,address,address,bytes32,bytes32,bytes32,address[],uint256)"; - -const INITIALIZE_BRIDGE_ADDRESS_SIGNATURE: &str = "initializeBridgeAddress(address)"; -const TRANSFER_OWNERSHIP_SIGNATURE: &str = "transferOwnership(address)"; -const ACCEPT_OWNERSHIP_SIGNATURE: &str = "acceptOwnership()"; -const BRIDGE_INITIALIZER_SIGNATURE: &str = "initialize(address,address,uint256)"; - #[derive(Clone, Copy)] pub struct ContractAddresses { pub on_chain_proposer_address: Address, @@ -506,24 +446,51 @@ pub struct ContractAddresses { pub async fn deploy_l1_contracts( opts: DeployerOptions, ) -> Result { - info!("Starting deployer binary"); + debug!("Starting deployer binary"); + + #[cfg(not(feature = "sp1"))] + if (opts.deploy_sp1_verifier || opts.sp1_verifier_address.is_some()) + && opts.sp1_vk.is_none() + && opts.sp1_vk_path.is_none() + && SP1_VERIFICATION_KEY.is_none() + { + return Err(DeployerError::ConfigValueNotSet( + "--verifier.sp1-vk and --verifier.sp1-vk-path".to_string(), + )); + } + + #[cfg(not(feature = "risc0"))] + if opts.risc0_verifier_address.is_some() + && opts.risc0_vk.is_none() + && opts.risc0_vk_path.is_none() + && RISC0_VERIFICATION_KEY.is_none() + { + return Err(DeployerError::ConfigValueNotSet( + "--verifier.risc0-vk and --verifier.risc0-vk-path".to_string(), + )); + } + let signer: Signer = LocalSigner::new(opts.private_key).into(); let eth_client = EthClient::new_with_config( - vec![&opts.rpc_url], - opts.max_number_of_retries, - opts.backoff_factor, - opts.min_retry_delay, - opts.max_retry_delay, - Some(opts.maximum_allowed_max_fee_per_gas), - Some(opts.maximum_allowed_max_fee_per_blob_gas), + opts.eth_options + .rpc_url + .iter() + .map(|url| url.as_str()) + .collect(), + opts.eth_options.max_number_of_retries, + opts.eth_options.backoff_factor, + opts.eth_options.min_retry_delay, + opts.eth_options.max_retry_delay, + Some(opts.eth_options.maximum_allowed_max_fee_per_gas), + Some(opts.eth_options.maximum_allowed_max_fee_per_blob_gas), )?; let contract_addresses = deploy_contracts(ð_client, &opts, &signer).await?; initialize_contracts(contract_addresses, ð_client, &opts, &signer).await?; - if opts.deposit_rich { + if opts.deposit_private_keys_file.is_some() { let _ = make_deposits(contract_addresses.bridge_address, ð_client, &opts) .await .inspect_err(|err| { @@ -531,13 +498,12 @@ pub async fn deploy_l1_contracts( }); } - write_contract_addresses_to_env(contract_addresses, opts.env_file_path)?; - info!("Deployer binary finished successfully"); - Ok(contract_addresses) -} + if let Some(env_file_path) = opts.env_file_path { + write_contract_addresses_to_env(contract_addresses, env_file_path)?; + } -lazy_static::lazy_static! { - static ref SALT: std::sync::Mutex = std::sync::Mutex::new(H256::zero()); + debug!("Deployer binary finished successfully"); + Ok(contract_addresses) } async fn deploy_contracts( @@ -545,24 +511,14 @@ async fn deploy_contracts( opts: &DeployerOptions, deployer: &Signer, ) -> Result { - trace!("Deploying contracts"); - info!("Deploying OnChainProposer"); - let salt = if opts.randomize_contract_deployment { - H256::random().as_bytes().to_vec() - } else { - SALT.lock() - .map_err(|_| DeployerError::InternalError("failed unwrapping salt lock".to_string()))? - .as_bytes() - .to_vec() - }; + let salt = opts.create2_salt.as_ref().map(|salt| salt.as_bytes()); - trace!("Attempting to deploy OnChainProposer contract"); let bytecode = if opts.deploy_based_contracts { - ON_CHAIN_PROPOSER_BASED_BYTECODE.to_vec() + ON_CHAIN_PROPOSER_BASED_BYTECODE } else { - ON_CHAIN_PROPOSER_BYTECODE.to_vec() + ON_CHAIN_PROPOSER_BYTECODE }; if bytecode.is_empty() { @@ -570,89 +526,88 @@ async fn deploy_contracts( } let on_chain_proposer_deployment = - deploy_with_proxy_from_bytecode(deployer, eth_client, &bytecode, &salt).await?; + deploy_with_proxy(eth_client, deployer, bytecode, salt).await?; info!( - "OnChainProposer deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", - on_chain_proposer_deployment.proxy_address, - on_chain_proposer_deployment.proxy_tx_hash, - on_chain_proposer_deployment.implementation_address, - on_chain_proposer_deployment.implementation_tx_hash, + address =? on_chain_proposer_deployment.implementation_address, + tx_hash =? on_chain_proposer_deployment.implementation_tx_hash, + "OnChainProposer implementation deployed" + ); + info!( + address =? on_chain_proposer_deployment.proxy_address, + tx_hash =? on_chain_proposer_deployment.proxy_tx_hash, + "OnChainProposer proxy deployed" ); info!("Deploying CommonBridge"); let bridge_deployment = - deploy_with_proxy_from_bytecode(deployer, eth_client, COMMON_BRIDGE_BYTECODE, &salt) - .await?; + deploy_with_proxy(eth_client, deployer, COMMON_BRIDGE_BYTECODE, salt).await?; info!( - "CommonBridge deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", - bridge_deployment.proxy_address, - bridge_deployment.proxy_tx_hash, - bridge_deployment.implementation_address, - bridge_deployment.implementation_tx_hash, + address =? bridge_deployment.implementation_address, + tx_hash =? bridge_deployment.implementation_tx_hash, + "CommonBridge implementation deployed" + ); + info!( + address =? bridge_deployment.proxy_address, + tx_hash =? bridge_deployment.proxy_tx_hash, + "CommonBridge proxy deployed" ); let sequencer_registry_deployment = if opts.deploy_based_contracts { info!("Deploying SequencerRegistry"); - let sequencer_registry_deployment = deploy_with_proxy_from_bytecode( - deployer, - eth_client, - SEQUENCER_REGISTRY_BYTECODE, - &salt, - ) - .await?; + let sequencer_registry_deployment = + deploy_with_proxy(eth_client, deployer, SEQUENCER_REGISTRY_BYTECODE, salt).await?; info!( - "SequencerRegistry deployed:\n Proxy -> address={:#x}, tx_hash={:#x}\n Impl -> address={:#x}, tx_hash={:#x}", - sequencer_registry_deployment.proxy_address, - sequencer_registry_deployment.proxy_tx_hash, - sequencer_registry_deployment.implementation_address, - sequencer_registry_deployment.implementation_tx_hash, + address =? sequencer_registry_deployment.implementation_address, + tx_hash =? sequencer_registry_deployment.implementation_tx_hash, + "SequencerRegistry implementation deployed" + ); + info!( + address =? sequencer_registry_deployment.proxy_address, + tx_hash =? sequencer_registry_deployment.proxy_tx_hash, + "SequencerRegistry proxy deployed" ); sequencer_registry_deployment } else { Default::default() }; - let sp1_verifier_address = if opts.sp1_deploy_verifier { - info!("Deploying SP1Verifier (if sp1_deploy_verifier is true)"); - let (verifier_deployment_tx_hash, sp1_verifier_address) = - create2_deploy_from_bytecode(&[], SP1_VERIFIER_BYTECODE, deployer, &salt, eth_client) - .await?; + // TODO: Add Risc0Verifier deployment + let risc0_verifier_address = opts.risc0_verifier_address.unwrap_or(DEV_MODE_ADDRESS); - info!(address = %format!("{sp1_verifier_address:#x}"), tx_hash = %format!("{verifier_deployment_tx_hash:#x}"), "SP1Verifier deployed"); - sp1_verifier_address + let sp1_verifier_address = if opts.deploy_sp1_verifier { + info!("Deploying SP1 verifier"); + deploy_contract( + eth_client, + deployer, + SP1_VERIFIER_BYTECODE, + &[], + Overrides::default(), + salt, + ) + .await + .map(|(tx_hash, address)| { + info!(?address, ?tx_hash, "SP1 verifier deployed"); + address + })? } else { - opts.sp1_verifier_address - .ok_or(DeployerError::InternalError( - "SP1Verifier address is not set and sp1_deploy_verifier is false".to_string(), - ))? + opts.sp1_verifier_address.unwrap_or(DEV_MODE_ADDRESS) }; - // TODO: Add Risc0Verifier deployment - let risc0_verifier_address = - opts.risc0_verifier_address - .ok_or(DeployerError::InternalError( - "Risc0Verifier address is not set and risc0_deploy_verifier is false".to_string(), - ))?; - - let tdx_verifier_address = if opts.tdx_deploy_verifier { - info!("Deploying TDXVerifier (if tdx_deploy_verifier is true)"); - let tdx_verifier_address = - deploy_tdx_contracts(opts, on_chain_proposer_deployment.proxy_address)?; - - info!(address = %format!("{tdx_verifier_address:#x}"), "TDXVerifier deployed"); - tdx_verifier_address + let tdx_verifier_address = if opts.deploy_tdx_verifier { + info!("Deploying TDX verifier"); + deploy_tdx_contracts(opts, on_chain_proposer_deployment.proxy_address) + .inspect(|address| info!(?address, "TDX verifier deployed"))? } else { - opts.tdx_verifier_address - .ok_or(DeployerError::InternalError( - "TDXVerifier address is not set and tdx_deploy_verifier is false".to_string(), - ))? + opts.tdx_verifier_address.unwrap_or(DEV_MODE_ADDRESS) }; - trace!( + let aligned_aggregator_address = opts.aligned_aggregator_address.unwrap_or(DEV_MODE_ADDRESS); + + debug!( on_chain_proposer_proxy_address = ?on_chain_proposer_deployment.proxy_address, bridge_proxy_address = ?bridge_deployment.proxy_address, on_chain_proposer_implementation_address = ?on_chain_proposer_deployment.implementation_address, @@ -662,6 +617,7 @@ async fn deploy_contracts( tdx_verifier_address = ?tdx_verifier_address, "Contracts deployed" ); + Ok(ContractAddresses { on_chain_proposer_address: on_chain_proposer_deployment.proxy_address, bridge_address: bridge_deployment.proxy_address, @@ -669,7 +625,7 @@ async fn deploy_contracts( risc0_verifier_address, tdx_verifier_address, sequencer_registry_address: sequencer_registry_deployment.proxy_address, - aligned_aggregator_address: opts.aligned_aggregator_address, + aligned_aggregator_address, }) } @@ -680,7 +636,15 @@ fn deploy_tdx_contracts( Command::new("make") .arg("deploy-all") .env("PRIVATE_KEY", hex::encode(opts.private_key.as_ref())) - .env("RPC_URL", &opts.rpc_url) + .env( + "RPC_URL", + opts.eth_options + .rpc_url + .first() + .ok_or(DeployerError::ConfigValueNotSet( + "--eth.rpc-url".to_string(), + ))?, + ) .env("ON_CHAIN_PROPOSER", format!("{on_chain_proposer:#x}")) .current_dir("tee/contracts") .stdout(Stdio::null()) @@ -705,24 +669,33 @@ fn read_tdx_deployment_address(name: &str) -> Address { Address::from_str(&contents).unwrap_or(Address::zero()) } -fn read_vk(path: &str) -> Bytes { +fn read_vk(path: &PathBuf) -> H256 { let Ok(str) = std::fs::read_to_string(path) else { warn!( ?path, "Failed to read verification key file, will use 0x00..00, this is expected in dev mode" ); - return Bytes::from(vec![0u8; 32]); + return H256::zero(); }; let cleaned = str.trim().strip_prefix("0x").unwrap_or(&str); - hex::decode(cleaned).map(Bytes::from).unwrap_or_else(|e| { - warn!( - ?path, - "Failed to decode hex string, will use 0x00..00, this is expected in dev mode: {}", e - ); - Bytes::from(vec![0u8; 32]) - }) + hex::decode(cleaned) + .and_then(|bytes| { + if bytes.len() == 32 { + Ok(H256::from_slice(&bytes)) + } else { + Err(hex::FromHexError::InvalidStringLength) + } + }) + .unwrap_or_else(|err| { + warn!( + ?path, + ?err, + "Failed to decode hex string, will use 0x00..00. This is expected in dev mode", + ); + H256::zero() + }) } async fn initialize_contracts( @@ -733,23 +706,37 @@ async fn initialize_contracts( ) -> Result<(), DeployerError> { trace!("Initializing contracts"); - trace!(committer_l1_address = %opts.committer_l1_address, "Using committer L1 address for OnChainProposer initialization"); - - let genesis: Genesis = if opts.use_compiled_genesis { - serde_json::from_str(LOCAL_DEVNETL2_GENESIS_CONTENTS).map_err(|_| DeployerError::Genesis)? + let genesis: Genesis = if opts.use_dev_genesis { + serde_json::from_str(LOCAL_DEVNETL2_GENESIS_CONTENTS) + .map_err(|e| DeployerError::GenesisError(e.to_string()))? } else { read_genesis_file( - opts.genesis_l2_path - .to_str() - .ok_or(DeployerError::FailedToGetStringFromPath)?, - ) + &opts + .genesis_l2_path + .clone() + .ok_or(DeployerError::ConfigValueNotSet("--l2.genesis".to_string()))?, + )? }; - let sp1_vk = read_vk(&opts.sp1_vk_path); - let risc0_vk = read_vk(&opts.risc0_vk_path); - - let deployer_address = - get_address_from_secret_key(&opts.private_key).map_err(DeployerError::InternalError)?; + let sp1_vk = opts + .sp1_vk_path + .as_ref() + .map(read_vk) + .or(opts.sp1_vk) + .or(SP1_VERIFICATION_KEY + .map(|vk| H256::from_str(vk).expect("Invalid embeded SP1 verification key"))) + .unwrap_or(H256::zero()); + + let risc0_vk = opts + .risc0_vk_path + .as_ref() + .map(read_vk) + .or(opts.risc0_vk) + .or(RISC0_VERIFICATION_KEY + .map(|vk| H256::from_str(vk).expect("Invalid embeded RISC0 verification key"))) + .unwrap_or(H256::zero()); + + let initializer_address = initializer.address(); info!("Initializing OnChainProposer"); @@ -757,176 +744,194 @@ async fn initialize_contracts( // Initialize OnChainProposer with Based config and SequencerRegistry let calldata_values = vec![ Value::Bool(opts.validium), - Value::Address(deployer_address), + Value::Address(initializer_address), Value::Address(contract_addresses.risc0_verifier_address), Value::Address(contract_addresses.sp1_verifier_address), Value::Address(contract_addresses.tdx_verifier_address), Value::Address(contract_addresses.aligned_aggregator_address), - Value::FixedBytes(sp1_vk), - Value::FixedBytes(risc0_vk), + Value::FixedBytes(sp1_vk.0.to_vec().into()), + Value::FixedBytes(risc0_vk.0.to_vec().into()), Value::FixedBytes(genesis.compute_state_root().0.to_vec().into()), Value::Address(contract_addresses.sequencer_registry_address), Value::Uint(genesis.config.chain_id.into()), ]; - trace!(calldata_values = ?calldata_values, "OnChainProposer initialization calldata values"); - let on_chain_proposer_initialization_calldata = encode_calldata( + trace!("OnChainProposer initialization calldata values: {calldata_values:?}"); + + let initialize_tx_hash = call_contract( + eth_client, + initializer, + contract_addresses.on_chain_proposer_address, INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE_BASED, - &calldata_values, - )?; + calldata_values, + ) + .await?; - let deployer = Signer::Local(LocalSigner::new(opts.private_key)); + info!(tx_hash =? initialize_tx_hash, "OnChainProposer initialized"); + info!("Initializing SequencerRegistry"); - let initialize_tx_hash = initialize_contract( - contract_addresses.on_chain_proposer_address, - on_chain_proposer_initialization_calldata, - &deployer, + let calldata_values = vec![ + Value::Address(opts.sequencer_registry_owner.unwrap_or(initializer_address)), + Value::Address(contract_addresses.on_chain_proposer_address), + ]; + + trace!("SequencerRegistry initialization calldata values: {calldata_values:?}"); + + let initialize_tx_hash = call_contract( eth_client, + initializer, + contract_addresses.sequencer_registry_address, + INITIALIZE_SEQUENCER_REGISTRY_SIGNATURE, + calldata_values, ) .await?; - info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); - - info!("Initializing SequencerRegistry"); - let initialize_tx_hash = { - let calldata_values = vec![ - Value::Address(opts.sequencer_registry_owner.ok_or( - DeployerError::ConfigValueNotSet("--sequencer-registry-owner".to_string()), - )?), - Value::Address(contract_addresses.on_chain_proposer_address), - ]; - let sequencer_registry_initialization_calldata = - encode_calldata("initialize(address,address)", &calldata_values)?; - - initialize_contract( - contract_addresses.sequencer_registry_address, - sequencer_registry_initialization_calldata, - &deployer, - eth_client, - ) - .await? - }; - info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "SequencerRegistry initialized"); + info!(tx_hash =? initialize_tx_hash, "SequencerRegistry initialized"); } else { // Initialize only OnChainProposer without Based config let calldata_values = vec![ Value::Bool(opts.validium), - Value::Address(deployer_address), + Value::Address(initializer_address), Value::Address(contract_addresses.risc0_verifier_address), Value::Address(contract_addresses.sp1_verifier_address), Value::Address(contract_addresses.tdx_verifier_address), Value::Address(contract_addresses.aligned_aggregator_address), - Value::FixedBytes(sp1_vk), - Value::FixedBytes(risc0_vk), + Value::FixedBytes(sp1_vk.0.to_vec().into()), + Value::FixedBytes(risc0_vk.0.to_vec().into()), Value::FixedBytes(genesis.compute_state_root().0.to_vec().into()), Value::Array(vec![ - Value::Address(opts.committer_l1_address), - Value::Address(opts.proof_sender_l1_address), + Value::Address(opts.l1_committer), + Value::Address(opts.l1_proof_sender), ]), Value::Uint(genesis.config.chain_id.into()), ]; - trace!(calldata_values = ?calldata_values, "OnChainProposer initialization calldata values"); - let on_chain_proposer_initialization_calldata = - encode_calldata(INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE, &calldata_values)?; - let initialize_tx_hash = initialize_contract( - contract_addresses.on_chain_proposer_address, - on_chain_proposer_initialization_calldata, - initializer, + trace!("OnChainProposer initialization calldata values: {calldata_values:?}"); + + let initialize_tx_hash = call_contract( eth_client, + initializer, + contract_addresses.on_chain_proposer_address, + INITIALIZE_ON_CHAIN_PROPOSER_SIGNATURE, + calldata_values, ) .await?; - info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "OnChainProposer initialized"); + + info!(tx_hash =? initialize_tx_hash, "OnChainProposer initialized"); } - let initialize_bridge_address_tx_hash = { - let calldata_values = vec![Value::Address(contract_addresses.bridge_address)]; - let on_chain_proposer_initialization_calldata = - encode_calldata(INITIALIZE_BRIDGE_ADDRESS_SIGNATURE, &calldata_values)?; + let calldata_values = vec![Value::Address(contract_addresses.bridge_address)]; - initialize_contract( - contract_addresses.on_chain_proposer_address, - on_chain_proposer_initialization_calldata, - initializer, - eth_client, - ) - .await? - }; + trace!("OnChainProposer bridge address initialization calldata values: {calldata_values:?}"); + + let initialize_bridge_address_tx_hash = call_contract( + eth_client, + initializer, + contract_addresses.on_chain_proposer_address, + INITIALIZE_BRIDGE_ADDRESS_SIGNATURE, + calldata_values, + ) + .await?; info!( - tx_hash = %format!("{initialize_bridge_address_tx_hash:#x}"), + tx_hash =? initialize_bridge_address_tx_hash, "OnChainProposer bridge address initialized" ); - if opts.on_chain_proposer_owner != initializer.address() { - let transfer_ownership_tx_hash = { - let owener_transfer_calldata = encode_calldata( - TRANSFER_OWNERSHIP_SIGNATURE, - &[Value::Address(opts.on_chain_proposer_owner)], - )?; - - initialize_contract( - contract_addresses.on_chain_proposer_address, - owener_transfer_calldata, - initializer, - eth_client, - ) - .await? - }; + if let Some(owner_pk) = opts.on_chain_proposer_owner_pk { + let owner: Signer = LocalSigner::new(owner_pk).into(); - if let Some(owner_pk) = opts.on_chain_proposer_owner_pk { - let signer = Signer::Local(LocalSigner::new(owner_pk)); - let accept_ownership_calldata = encode_calldata(ACCEPT_OWNERSHIP_SIGNATURE, &[])?; - let accept_tx = build_generic_tx( - eth_client, - TxType::EIP1559, - contract_addresses.on_chain_proposer_address, - opts.on_chain_proposer_owner, - accept_ownership_calldata.into(), - Overrides::default(), - ) - .await?; - let accept_tx_hash = send_generic_transaction(eth_client, accept_tx, &signer).await?; - - wait_for_transaction_receipt(accept_tx_hash, eth_client, 100).await?; + let tx_hash = transfer_ownership( + eth_client, + initializer, + owner.address(), + contract_addresses.on_chain_proposer_address, + ) + .await?; - info!( - transfer_tx_hash = %format!("{transfer_ownership_tx_hash:#x}"), - accept_tx_hash = %format!("{accept_tx_hash:#x}"), - "OnChainProposer ownership transfered" - ); - } else { - info!( - transfer_tx_hash = %format!("{transfer_ownership_tx_hash:#x}"), - "OnChainProposer ownership transfered but not accepted yet" - ); - } - } + info!(?tx_hash, to =? owner, "OnChainProposer ownership transfered but not accepted yet"); - info!("Initializing CommonBridge"); - let initialize_tx_hash = { - let calldata_values = vec![ - Value::Address(opts.bridge_owner), - Value::Address(contract_addresses.on_chain_proposer_address), - Value::Uint(opts.inclusion_max_wait.into()), - ]; - let bridge_initialization_calldata = - encode_calldata(BRIDGE_INITIALIZER_SIGNATURE, &calldata_values)?; + let tx_hash = accept_ownership( + eth_client, + &owner, + contract_addresses.on_chain_proposer_address, + ) + .await?; - initialize_contract( - contract_addresses.bridge_address, - bridge_initialization_calldata, - initializer, + info!(?tx_hash, "OnChainProposer ownership accepted"); + } else if let Some(owner) = opts.on_chain_proposer_owner { + let tx_hash = transfer_ownership( eth_client, + initializer, + owner, + contract_addresses.on_chain_proposer_address, ) - .await? - }; - info!(tx_hash = %format!("{initialize_tx_hash:#x}"), "CommonBridge initialized"); + .await?; + info!(?tx_hash, to =? owner, "OnChainProposer ownership transfered but not accepted yet"); + } + + info!("Initializing CommonBridge"); + + let bridge_owner = opts.bridge_owner.unwrap_or(initializer_address); + let calldata_values = vec![ + Value::Address(bridge_owner), + Value::Address(contract_addresses.on_chain_proposer_address), + Value::Uint(opts.inclusion_max_wait.into()), + ]; + + trace!("CommonBridge initialization calldata values: {calldata_values:?}"); + + let initialize_tx_hash = call_contract( + eth_client, + initializer, + contract_addresses.bridge_address, + INITIALIZE_COMMON_BRIDGE_SIGNATURE, + calldata_values, + ) + .await?; + + info!(tx_hash =? initialize_tx_hash, "CommonBridge initialized"); trace!("Contracts initialized"); + Ok(()) } +async fn transfer_ownership( + eth_client: &EthClient, + from: &Signer, + to: Address, + contract: Address, +) -> Result { + let tx_hash = call_contract( + eth_client, + from, + contract, + TRANSFER_OWNERSHIP_SIGNATURE, + vec![Value::Address(to)], + ) + .await?; + + Ok(tx_hash) +} + +async fn accept_ownership( + eth_client: &EthClient, + new_owner: &Signer, + contract: Address, +) -> Result { + let tx_hash = call_contract( + eth_client, + new_owner, + contract, + ACCEPT_OWNERSHIP_SIGNATURE, + vec![], + ) + .await?; + + Ok(tx_hash) +} + async fn make_deposits( bridge: Address, eth_client: &EthClient, @@ -934,46 +939,24 @@ async fn make_deposits( ) -> Result<(), DeployerError> { trace!("Making deposits"); - let genesis: Genesis = if opts.use_compiled_genesis { - serde_json::from_str(LOCAL_DEVNET_GENESIS_CONTENTS).map_err(|_| DeployerError::Genesis)? - } else { - read_genesis_file( - opts.genesis_l1_path - .clone() - .ok_or(DeployerError::ConfigValueNotSet( - "--genesis-l1-path".to_string(), - ))? - .to_str() - .ok_or(DeployerError::FailedToGetStringFromPath)?, - ) - }; - - let pks = if let Some(path) = &opts.private_keys_file_path { - &read_to_string(path).map_err(|_| DeployerError::FailedToGetStringFromPath)? - } else { - LOCAL_DEVNET_PRIVATE_KEYS - }; - + let pks = read_to_string(opts.deposit_private_keys_file.clone().ok_or( + DeployerError::ConfigValueNotSet("--deployer.deposit-accounts".to_string()), + )?) + .map_err(|_| DeployerError::FailedToGetStringFromPath)?; let private_keys: Vec = pks .lines() .filter(|line| !line.trim().is_empty()) .map(|line| line.trim().to_string()) .collect(); + let mut successful_deposits = 0; + for pk in private_keys.iter() { let secret_key = parse_private_key(pk).map_err(|_| { DeployerError::DecodingError("Error while parsing private key".to_string()) })?; let signer = Signer::Local(LocalSigner::new(secret_key)); - let Some(_) = genesis.alloc.get(&signer.address()) else { - debug!( - address =? signer.address(), - "Skipping deposit for address as it is not in the genesis file" - ); - continue; - }; - let get_balance = eth_client .get_balance(signer.address(), BlockIdentifier::Tag(BlockTag::Latest)) .await?; @@ -999,7 +982,8 @@ async fn make_deposits( match send_generic_transaction(eth_client, build, &signer).await { Ok(hash) => { - info!( + successful_deposits += 1; + debug!( address =? signer.address(), ?value_to_deposit, ?hash, @@ -1012,89 +996,65 @@ async fn make_deposits( } } } - trace!("Deposits finished"); + + info!( + total_accounts = private_keys.len(), + successful_deposits, "Deposits finished" + ); + Ok(()) } fn write_contract_addresses_to_env( contract_addresses: ContractAddresses, - env_file_path: Option, + path: PathBuf, ) -> Result<(), DeployerError> { trace!("Writing contract addresses to .env file"); - let env_file_path = - env_file_path.unwrap_or_else(|| PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../.env")); // ethrex/cmd/.env - if !env_file_path.exists() { - File::create(&env_file_path).map_err(|err| { + if !path.is_file() { + File::create(&path).map_err(|err| { DeployerError::InternalError(format!( "Failed to create .env file at {}: {err}", - env_file_path.display() + path.display() )) })?; } - let env_file = OpenOptions::new() - .write(true) - .truncate(true) - .open(&env_file_path)?; // ethrex/crates/l2/.env + let env_file = OpenOptions::new().write(true).truncate(true).open(&path)?; let mut writer = BufWriter::new(env_file); - writeln!( - writer, - "ETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS={:#x}", - contract_addresses.on_chain_proposer_address - )?; - writeln!( - writer, - "ETHREX_WATCHER_BRIDGE_ADDRESS={:#x}", - contract_addresses.bridge_address - )?; - writeln!( - writer, - "ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER={:#x}", - contract_addresses.sp1_verifier_address - )?; writeln!( writer, - "ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER={:#x}", - contract_addresses.risc0_verifier_address - )?; - writeln!( - writer, - "ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS={:#x}", - contract_addresses.aligned_aggregator_address + r#"ETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS={:#x} +ETHREX_WATCHER_BRIDGE_ADDRESS={:#x} +ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER_ADDRESS={:#x} +ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER_ADDRESS={:#x} +ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS={:#x} +ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER_ADDRESS={:#x} +ENCLAVE_ID_DAO={:#x} +FMSPC_TCB_DAO={:#x} +PCK_DAO={:#x} +PCS_DAO={:#x} +ETHREX_DEPLOYER_SEQUENCER_REGISTRY_ADDRESS={:#x}"#, + contract_addresses.on_chain_proposer_address, + contract_addresses.bridge_address, + contract_addresses.sp1_verifier_address, + contract_addresses.risc0_verifier_address, + contract_addresses.aligned_aggregator_address, + contract_addresses.tdx_verifier_address, + read_tdx_deployment_address("AutomataEnclaveIdentityDao"), + read_tdx_deployment_address("AutomataFmspcTcbDao"), + read_tdx_deployment_address("AutomataPckDao"), + read_tdx_deployment_address("AutomataPcsDao"), + contract_addresses.sequencer_registry_address, )?; - writeln!( - writer, - "ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER={:#x}", - contract_addresses.tdx_verifier_address - )?; - // TDX aux contracts, qpl-tool depends on exact env var naming - writeln!( - writer, - "ENCLAVE_ID_DAO={:#x}", - read_tdx_deployment_address("AutomataEnclaveIdentityDao") - )?; - writeln!( - writer, - "FMSPC_TCB_DAO={:#x}", - read_tdx_deployment_address("AutomataFmspcTcbDao") - )?; - writeln!( - writer, - "PCK_DAO={:#x}", - read_tdx_deployment_address("AutomataPckDao") - )?; - writeln!( - writer, - "PCS_DAO={:#x}", - read_tdx_deployment_address("AutomataPcsDao") - )?; - writeln!( - writer, - "ETHREX_DEPLOYER_SEQUENCER_REGISTRY_ADDRESS={:#x}", - contract_addresses.sequencer_registry_address - )?; - trace!(?env_file_path, "Contract addresses written to .env"); + + trace!(?path, "Contract addresses written to .env"); Ok(()) } + +pub fn read_genesis_file(path: &PathBuf) -> Result { + let file = File::open(path).map_err(|e| DeployerError::GenesisError(e.to_string()))?; + let genesis_reader = BufReader::new(file); + serde_json::from_reader(genesis_reader).map_err(|e| DeployerError::GenesisError(e.to_string())) +} diff --git a/cmd/ethrex/l2/options.rs b/cmd/ethrex/l2/options.rs index 80644ec3896..1e50f393ffe 100644 --- a/cmd/ethrex/l2/options.rs +++ b/cmd/ethrex/l2/options.rs @@ -249,6 +249,7 @@ pub struct EthOptions { long = "eth.rpc-url", value_name = "RPC_URL", env = "ETHREX_ETH_RPC_URL", + default_value = "http://localhost:8545", help = "List of rpc urls to use.", help_heading = "Eth options", num_args = 1.. diff --git a/crates/l2/Makefile b/crates/l2/Makefile index f3a86a843b8..4b8e310290a 100644 --- a/crates/l2/Makefile +++ b/crates/l2/Makefile @@ -49,8 +49,8 @@ PROOF_COORDINATOR_ADDRESS?=127.0.0.1 # Matches the ports used by the blockchain/metrics dir L2_PROMETHEUS_METRICS_PORT = 3702 -DEFAULT_BRIDGE_ADDRESS=$$(grep ETHREX_WATCHER_BRIDGE_ADDRESS ../../cmd/.env | cut -d= -f2) -DEFAULT_ON_CHAIN_PROPOSER_ADDRESS=$$(grep ETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS ../../cmd/.env | cut -d= -f2) +DEFAULT_BRIDGE_ADDRESS=$$(grep ETHREX_WATCHER_BRIDGE_ADDRESS ../../.env | cut -d= -f2) +DEFAULT_ON_CHAIN_PROPOSER_ADDRESS=$$(grep ETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS ../../.env | cut -d= -f2) PROVER_SRC_FILES := $(shell find prover/src -type f) @@ -83,42 +83,33 @@ rm-db-l1: ## 🛑 Removes the DB used by the L1 deploy-l1: ## 📜 Deploys the L1 contracts COMPILE_CONTRACTS=true \ cargo run --release --bin ethrex --manifest-path ../../Cargo.toml -- l2 deploy \ - --eth-rpc-url ${L1_RPC_URL} \ - --private-key ${L1_PRIVATE_KEY} \ - --risc0.verifier-address 0x00000000000000000000000000000000000000aa \ - --sp1.verifier-address 0x00000000000000000000000000000000000000aa \ - --tdx.verifier-address 0x00000000000000000000000000000000000000aa \ - --aligned.aggregator-address 0x00000000000000000000000000000000000000aa \ - --on-chain-proposer-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ - --bridge-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ - --deposit-rich \ - --private-keys-file-path ../../fixtures/keys/private_keys_l1.txt \ - --genesis-l1-path ../../fixtures/genesis/l1-dev.json \ - --genesis-l2-path ../../fixtures/genesis/l2.json + --eth.rpc-url ${L1_RPC_URL} \ + --deployer.private-key ${L1_PRIVATE_KEY} \ + --deployer.on-chain-proposer-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ + --deployer.bridge-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ + --deployer.deposit-accounts ../../fixtures/keys/private_keys_l1.txt \ + --deployer.env-file ../../.env \ + --l2.dev-genesis ## Same as deploy-l1 but deploys the SP1 verifier deploy-l1-sp1: ## 📜 Deploys the L1 contracts COMPILE_CONTRACTS=true \ cargo run --release --bin ethrex --manifest-path ../../Cargo.toml -- l2 deploy \ - --eth-rpc-url ${L1_RPC_URL} \ - --private-key ${L1_PRIVATE_KEY} \ - --risc0.verifier-address 0x00000000000000000000000000000000000000aa \ + --eth.rpc-url ${L1_RPC_URL} \ + --deployer.private-key ${L1_PRIVATE_KEY} \ --sp1.deploy-verifier \ - --tdx.verifier-address 0x00000000000000000000000000000000000000aa \ - --aligned.aggregator-address 0x00000000000000000000000000000000000000aa \ - --on-chain-proposer-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ - --bridge-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ - --deposit-rich \ - --private-keys-file-path ../../fixtures/keys/private_keys_l1.txt \ - --genesis-l1-path ../../fixtures/genesis/l1-dev.json \ - --genesis-l2-path ../../fixtures/genesis/l2.json + --deployer.on-chain-proposer-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ + --deployer.bridge-owner 0x4417092b70a3e5f10dc504d0947dd256b965fc62 \ + --deployer.deposit-accounts ../../fixtures/keys/private_keys_l1.txt \ + --deployer.env-file ../../.env \ + --l2.dev-genesis # ============================================================================== # L2 # ============================================================================== init-l2: ## 🚀 Initializes an L2 Lambda ethrex Client - export $(shell cat ../../cmd/.env | xargs); \ + export $(shell cat ../../.env | xargs); \ cargo run --release --manifest-path ../../Cargo.toml --bin ethrex -- \ l2 \ --watcher.block-delay 0 \ @@ -152,6 +143,7 @@ down-metrics: ## 🛑 Shuts down the metrics' containers restart-metrics: down-metrics init-metrics ## 🔄 Restarts the metrics' containers down-l2: ## 🛑 Shuts down the L2 Lambda ethrex Client + docker compose down ethrex_l2 pgrep -a -f "ethrex l2" | awk '!/prover/ {print $1}' | xargs -r kill -s SIGINT rm-db-l2: ## 🛑 Removes the DB used by the L2 @@ -216,7 +208,7 @@ test: ## 🚧 Runs the L2's integration test, run `make init` and in a new termi integration-test: rm-db-l2 rm-db-l1 # We create an empty .env file simply because if the file # does not exist, the container fails to write to it. - touch .env + touch ../../.env docker compose down DOCKER_ETHREX_WORKDIR=${DOCKER_ETHREX_WORKDIR} \ ETHREX_L2_VALIDIUM=${ETHREX_L2_VALIDIUM} \ @@ -230,7 +222,7 @@ integration-test: rm-db-l2 rm-db-l1 # We create an empty .env file simply becaus integration-test-gpu: rm-db-l2 rm-db-l1 # We create an empty .env file simply because if the file # does not exists, the container fails to write to it. - touch .env + touch ../../.env docker compose down DOCKER_ETHREX_WORKDIR=${DOCKER_ETHREX_WORKDIR} \ ETHREX_BLOCK_PRODUCER_BLOCK_TIME=${ETHREX_BLOCK_PRODUCER_BLOCK_TIME} \ @@ -242,7 +234,7 @@ integration-test-gpu: rm-db-l2 rm-db-l1 # State reconstruction tests state-diff-test: - touch .env + touch ../../.env cargo run --release --manifest-path ../../Cargo.toml -- \ l2 reconstruct \ -g ../../fixtures/genesis/l2.json \ diff --git a/crates/l2/docker-compose.yaml b/crates/l2/docker-compose.yaml index 0c0565d192c..a0a13c7ffa3 100644 --- a/crates/l2/docker-compose.yaml +++ b/crates/l2/docker-compose.yaml @@ -16,45 +16,37 @@ services: volumes: # NOTE: DOCKER_ETHREX_WORKDIR is defined in crates/l2/Makefile - ./contracts:${DOCKER_ETHREX_WORKDIR}/contracts - - ../../cmd/.env:${DOCKER_ETHREX_WORKDIR}/.env - - ../../fixtures/genesis/l1-dev.json:${DOCKER_ETHREX_WORKDIR}/fixtures/genesis/l1-dev.json + - ../../.env:${DOCKER_ETHREX_WORKDIR}/.env - ../../fixtures/genesis/l2.json:${DOCKER_ETHREX_WORKDIR}/fixtures/genesis/l2.json - ../../fixtures/keys/private_keys_l1.txt:${DOCKER_ETHREX_WORKDIR}/fixtures/keys/private_keys_l1.txt - - ./prover/src/guest_program/src/sp1/out/riscv32im-succinct-zkvm-vk:${DOCKER_ETHREX_WORKDIR}/riscv32im-succinct-zkvm-vk - - ./prover/src/guest_program/src/risc0/out/riscv32im-risc0-vk:${DOCKER_ETHREX_WORKDIR}/riscv32im-risc0-vk environment: - ETHREX_ETH_RPC_URL=http://ethrex_l1:8545 # NOTE: The paths in the env variables must match those # specified in the `volumes:` section - ETHREX_DEPLOYER_L1_PRIVATE_KEY=${ETHREX_DEPLOYER_PRIVATE_KEY:-0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924} - ETHREX_DEPLOYER_ENV_FILE_PATH=${DOCKER_ETHREX_WORKDIR}/.env - - ETHREX_DEPLOYER_GENESIS_L1_PATH=${DOCKER_ETHREX_WORKDIR}/fixtures/genesis/l1-dev.json - ETHREX_DEPLOYER_GENESIS_L2_PATH=${DOCKER_ETHREX_WORKDIR}/fixtures/genesis/l2.json - - ETHREX_DEPLOYER_PRIVATE_KEYS_FILE_PATH=${DOCKER_ETHREX_WORKDIR}/fixtures/keys/private_keys_l1.txt - - ETHREX_DEPLOYER_DEPLOY_RICH=${ETHREX_DEPLOYER_DEPLOY_RICH:-true} - - ETHREX_DEPLOYER_PICO_CONTRACT_VERIFIER=${ETHREX_DEPLOYER_PICO_CONTRACT_VERIFIER:-0x00000000000000000000000000000000000000aa} - - ETHREX_DEPLOYER_PICO_DEPLOY_VERIFIER=${ETHREX_DEPLOYER_PICO_DEPLOY_VERIFIER:-false} - - ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER=${ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER:-0x00000000000000000000000000000000000000aa} - - ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER=${ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER:-0x00000000000000000000000000000000000000aa} - - ETHREX_DEPLOYER_SP1_DEPLOY_VERIFIER=${ETHREX_DEPLOYER_SP1_DEPLOY_VERIFIER:-false} - - ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS=${ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS:-0x00000000000000000000000000000000000000aa} - - ETHREX_SP1_VERIFICATION_KEY_PATH=${DOCKER_ETHREX_WORKDIR}/riscv32im-succinct-zkvm-vk - - ETHREX_RISC0_VERIFICATION_KEY_PATH=${DOCKER_ETHREX_WORKDIR}/riscv32im-risc0-vk - - ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER=${ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER:-0x00000000000000000000000000000000000000aa} - - ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER=${ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER:-false} - - ETHREX_TDX_DEV_MODE=${ETHREX_TDX_DEV_MODE:-false} - - ETHREX_ON_CHAIN_PROPOSER_OWNER=0x4417092b70a3e5f10dc504d0947dd256b965fc62 - - ETHREX_BRIDGE_OWNER=0x4417092b70a3e5f10dc504d0947dd256b965fc62 - - ETHREX_DEPLOYER_SEQUENCER_REGISTRY_OWNER=0x4417092b70a3e5f10dc504d0947dd256b965fc62 + - ETHREX_DEPLOYER_DEPOSIT_PRIVATE_KEYS_FILE_PATH=${ETHREX_DEPLOYER_DEPOSIT_PRIVATE_KEYS_FILE_PATH:-${DOCKER_ETHREX_WORKDIR}/fixtures/keys/private_keys_l1.txt} + - ETHREX_DEPLOYER_DETERMINISTIC_SALT + - ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER_ADDRESS + - ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER_ADDRESS + - ETHREX_DEPLOYER_DEPLOY_SP1_VERIFIER=${ETHREX_DEPLOYER_DEPLOY_SP1_VERIFIER:-false} + - ETHREX_DEPLOYER_ALIGNED_AGGREGATOR_ADDRESS + - ETHREX_DEPLOYER_TDX_CONTRACT_VERIFIER_ADDRESS + - ETHREX_DEPLOYER_DEPLOY_TDX_VERIFIER=${ETHREX_DEPLOYER_DEPLOY_TDX_VERIFIER:-false} + - ETHREX_DEPLOYER_SP1_VERIFICATION_KEY + - ETHREX_DEPLOYER_RISC0_VERIFICATION_KEY + - ETHREX_DEPLOYER_ON_CHAIN_PROPOSER_OWNER_ADDRESS + - ETHREX_DEPLOYER_BRIDGE_OWNER_ADDRESS + - ETHREX_DEPLOYER_SEQUENCER_REGISTRY_OWNER_ADDRESS - ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS=${ETHREX_DEPLOYER_DEPLOY_BASED_CONTRACTS:-false} - - ETHREX_L2_VALIDIUM=${ETHREX_L2_VALIDIUM:-false} + - ETHREX_DEPLOYER_VALIDIUM=${ETHREX_L2_VALIDIUM:-false} - COMPILE_CONTRACTS=true depends_on: - ethrex_l1 command: > l2 deploy - --randomize-contract-deployment ethrex_l2: container_name: ethrex_l2 @@ -70,17 +62,16 @@ services: - ETHREX_ETH_RPC_URL=http://ethrex_l1:8545 - ETHREX_L2_VALIDIUM=${ETHREX_L2_VALIDIUM:-false} - ETHREX_BLOCK_PRODUCER_BLOCK_TIME=${ETHREX_BLOCK_PRODUCER_BLOCK_TIME:-5000} - - ETHREX_DEPLOYER_PICO_DEPLOY_VERIFIER=${ETHREX_DEPLOYER_PICO_DEPLOY_VERIFIER:-false} - ETHREX_WATCHER_BLOCK_DELAY=${ETHREX_WATCHER_BLOCK_DELAY:-0} - ETHREX_BASED=${ETHREX_BASED:-false} - - ETHREX_STATE_UPDATER_SEQUENCER_REGISTRY=${ETHREX_STATE_UPDATER_SEQUENCER_REGISTRY:-0x0000000000000000000000000000000000000000} + - ETHREX_STATE_UPDATER_SEQUENCER_REGISTRY - ETHREX_COMMITTER_COMMIT_TIME=${ETHREX_COMMITTER_COMMIT_TIME:-60000} - ETHREX_WATCHER_WATCH_INTERVAL=${ETHREX_WATCHER_WATCH_INTERVAL:-12000} env_file: - - ../../cmd/.env + - ../../.env volumes: - ../../fixtures/genesis/l2.json:/genesis/l2.json - - ../../cmd/.env:/.env:ro + - ../../.env:/.env:ro # ETHREX_WATCHER_BRIDGE_ADDRESS and ETHREX_COMMITTER_ON_CHAIN_PROPOSER_ADDRESS are set in the .env file by the contract_deployer service. command: > l2 diff --git a/crates/l2/sdk/src/sdk.rs b/crates/l2/sdk/src/sdk.rs index b3ff24ed8fd..8e4f6af9859 100644 --- a/crates/l2/sdk/src/sdk.rs +++ b/crates/l2/sdk/src/sdk.rs @@ -8,21 +8,25 @@ use ethrex_common::{ WrappedEIP4844Transaction, }, }; +use ethrex_rpc::{ + clients::eth::{EthClient, Overrides, errors::EthClientError}, + types::{ + block_identifier::{BlockIdentifier, BlockTag}, + receipt::RpcReceipt, + }, +}; + use ethrex_l2_common::{calldata::Value, l1_messages::L1MessageProof}; use ethrex_l2_rpc::{ clients::get_message_proof, signer::{LocalSigner, Signable, Signer}, }; use ethrex_rlp::encode::RLPEncode; -use ethrex_rpc::clients::eth::{EthClient, Overrides, errors::EthClientError}; -use ethrex_rpc::types::block_identifier::{BlockIdentifier, BlockTag}; -use ethrex_rpc::types::receipt::RpcReceipt; use keccak_hash::keccak; use secp256k1::SecretKey; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::ops::{Add, Div}; use std::str::FromStr; -use std::{fs::read_to_string, path::Path}; use tracing::{error, warn}; pub mod calldata; @@ -387,22 +391,26 @@ pub enum DeployError { ProxyBytecodeNotFound, } +// Deploy functions +/// Deploy a contract using `CREATE` pub async fn create_deploy( client: &EthClient, deployer: &Signer, - init_code: Bytes, - overrides: Overrides, -) -> Result<(H256, Address), EthClientError> { - let mut deploy_overrides = overrides; - deploy_overrides.to = Some(TxKind::Create); + bytecode: &[u8], + constructor_args: &[u8], + mut overrides: Overrides, +) -> Result<(H256, Address), DeployError> { + let init_code = [bytecode, constructor_args].concat(); + + overrides.to = Some(TxKind::Create); let deploy_tx = build_generic_tx( client, TxType::EIP1559, Address::zero(), deployer.address(), - init_code, - deploy_overrides, + init_code.into(), + overrides, ) .await?; let deploy_tx_hash = send_generic_transaction(client, deploy_tx, deployer).await?; @@ -423,92 +431,125 @@ pub async fn create_deploy( Ok((deploy_tx_hash, deployed_address)) } -pub async fn create2_deploy_from_path( - constructor_args: &[u8], - contract_path: &Path, +/// Deploys a contract using `CREATE2` +pub async fn create2_deploy( + client: &EthClient, deployer: &Signer, + bytecode: &[u8], + constructor_args: &[u8], + mut overrides: Overrides, salt: &[u8], - eth_client: &EthClient, ) -> Result<(H256, Address), DeployError> { - let bytecode = hex::decode(read_to_string(contract_path)?)?; - create2_deploy_from_bytecode(constructor_args, &bytecode, deployer, salt, eth_client).await + let init_code = [bytecode, constructor_args].concat(); + let calldata = [salt, &init_code].concat(); + + overrides.to = Some(TxKind::Call(DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS)); + + let deploy_tx = build_generic_tx( + client, + TxType::EIP1559, + DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS, + deployer.address(), + calldata.into(), + overrides, + ) + .await?; + + let deploy_tx_hash = send_tx_bump_gas_exponential_backoff(client, deploy_tx, deployer).await?; + + wait_for_transaction_receipt(deploy_tx_hash, client, 10).await?; + + let deployed_address = create2_address(salt, keccak(init_code)); + + Ok((deploy_tx_hash, deployed_address)) } -pub async fn create2_deploy_from_bytecode( - constructor_args: &[u8], - bytecode: &[u8], +/// Deploy a contract from the bytecode directly. +/// If `salt` is provided, the contract will be deployed using `CREATE2`, +/// otherwise `CREATE` will be used. +pub async fn deploy_contract( + client: &EthClient, deployer: &Signer, - salt: &[u8], - eth_client: &EthClient, + bytecode: &[u8], + constructor_args: &[u8], + overrides: Overrides, + salt: Option<&[u8]>, ) -> Result<(H256, Address), DeployError> { - let init_code = [bytecode, constructor_args].concat(); - let (deploy_tx_hash, contract_address) = - create2_deploy(salt, &init_code, deployer, eth_client).await?; - Ok((deploy_tx_hash, contract_address)) + match salt { + Some(salt) => { + create2_deploy( + client, + deployer, + bytecode, + constructor_args, + overrides, + salt, + ) + .await + } + None => create_deploy(client, deployer, bytecode, constructor_args, overrides).await, + } } -/// Deploys a contract behind an OpenZeppelin's `ERC1967Proxy`. +/// Deploys an OpenZeppelin's `ERC1967Proxy`. +/// If `salt` is provided, the proxy will be deployed using `CREATE2`, +/// otherwise `CREATE` will be used. +/// /// The embedded `ERC1967_PROXY_BYTECODE` may be empty if the crate was compiled /// without the `COMPILE_CONTRACTS` env var set. In that case, this function /// will return `DeployError::ProxyBytecodeNotFound`. async fn deploy_proxy( - deployer: &Signer, eth_client: &EthClient, + deployer: &Signer, implementation_address: Address, - salt: &[u8], + salt: Option<&[u8]>, ) -> Result<(H256, Address), DeployError> { #[allow(clippy::const_is_empty)] if ERC1967_PROXY_BYTECODE.is_empty() { return Err(DeployError::ProxyBytecodeNotFound); } - let mut init_code = ERC1967_PROXY_BYTECODE.to_vec(); - - init_code.extend(H256::from(implementation_address).0); - init_code.extend(H256::from_low_u64_be(0x40).0); - init_code.extend(H256::zero().0); + let constructor_args = [ + H256::from(implementation_address).0, + H256::from_low_u64_be(0x40).0, + H256::zero().0, + ] + .concat(); - let (deploy_tx_hash, proxy_address) = - create2_deploy(salt, &Bytes::from(init_code), deployer, eth_client) - .await - .map_err(DeployError::from)?; + let (deploy_tx_hash, proxy_address) = deploy_contract( + eth_client, + deployer, + ERC1967_PROXY_BYTECODE, + &constructor_args, + Overrides::default(), + salt, + ) + .await?; Ok((deploy_tx_hash, proxy_address)) } /// Deploys a contract behind an OpenZeppelin's `ERC1967Proxy`. +/// If `salt` is provided, both the implementation and the proxy +/// will be deployed using `CREATE2`, otherwise `CREATE` will be used. pub async fn deploy_with_proxy( - deployer: &Signer, eth_client: &EthClient, - contract_path: &Path, - salt: &[u8], -) -> Result { - let (implementation_tx_hash, implementation_address) = - create2_deploy_from_path(&[], contract_path, deployer, salt, eth_client).await?; - - let (proxy_tx_hash, proxy_address) = - deploy_proxy(deployer, eth_client, implementation_address, salt).await?; - - Ok(ProxyDeployment { - proxy_address, - proxy_tx_hash, - implementation_address, - implementation_tx_hash, - }) -} - -/// Same as `deploy_with_proxy`, but takes the contract bytecode directly instead of a path. -pub async fn deploy_with_proxy_from_bytecode( deployer: &Signer, - eth_client: &EthClient, bytecode: &[u8], - salt: &[u8], + salt: Option<&[u8]>, ) -> Result { - let (implementation_tx_hash, implementation_address) = - create2_deploy_from_bytecode(&[], bytecode, deployer, salt, eth_client).await?; + let (implementation_tx_hash, implementation_address) = deploy_contract( + eth_client, + deployer, + bytecode, + &[], + Overrides::default(), + salt, + ) + .await?; let (proxy_tx_hash, proxy_address) = - deploy_proxy(deployer, eth_client, implementation_address, salt).await?; + deploy_proxy(eth_client, deployer, implementation_address, salt).await?; Ok(ProxyDeployment { proxy_address, @@ -518,45 +559,6 @@ pub async fn deploy_with_proxy_from_bytecode( }) } -async fn create2_deploy( - salt: &[u8], - init_code: &[u8], - deployer: &Signer, - eth_client: &EthClient, -) -> Result<(H256, Address), EthClientError> { - let calldata = [salt, init_code].concat(); - let gas_price = eth_client - .get_gas_price_with_extra(20) - .await? - .try_into() - .map_err(|_| { - EthClientError::InternalError("Failed to convert gas_price to a u64".to_owned()) - })?; - - let deploy_tx = build_generic_tx( - eth_client, - TxType::EIP1559, - DETERMINISTIC_DEPLOYMENT_PROXY_ADDRESS, - deployer.address(), - calldata.into(), - Overrides { - max_fee_per_gas: Some(gas_price), - max_priority_fee_per_gas: Some(gas_price), - ..Default::default() - }, - ) - .await?; - - let deploy_tx_hash = - send_tx_bump_gas_exponential_backoff(eth_client, deploy_tx, deployer).await?; - - wait_for_transaction_receipt(deploy_tx_hash, eth_client, 10).await?; - - let deployed_address = create2_address(salt, keccak(init_code)); - - Ok((deploy_tx_hash, deployed_address)) -} - #[allow(clippy::indexing_slicing)] fn create2_address(salt: &[u8], init_code_hash: H256) -> Address { Address::from_slice( diff --git a/crates/l2/sequencer/utils.rs b/crates/l2/sequencer/utils.rs index d00d7833300..136b2c4d815 100644 --- a/crates/l2/sequencer/utils.rs +++ b/crates/l2/sequencer/utils.rs @@ -18,7 +18,7 @@ use std::{str::FromStr, time::UNIX_EPOCH}; use tokio::time::sleep; use tracing::info; -const DEV_MODE_ADDRESS: H160 = H160([ +pub const DEV_MODE_ADDRESS: H160 = H160([ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xAA, ]); diff --git a/crates/l2/tee/quote-gen/Cargo.lock b/crates/l2/tee/quote-gen/Cargo.lock index a3631f96bbd..eaf2cb41570 100644 --- a/crates/l2/tee/quote-gen/Cargo.lock +++ b/crates/l2/tee/quote-gen/Cargo.lock @@ -2107,6 +2107,7 @@ name = "ethrex-l2" version = "0.1.0" dependencies = [ "aligned-sdk", + "axum", "bincode", "bytes", "cfg-if 1.0.3", diff --git a/crates/l2/tests/tests.rs b/crates/l2/tests/tests.rs index a988e2542aa..ef428e90dfc 100644 --- a/crates/l2/tests/tests.rs +++ b/crates/l2/tests/tests.rs @@ -2,24 +2,23 @@ #![allow(clippy::expect_used)] use anyhow::{Context, Result}; use bytes::Bytes; -use ethrex_common::types::TxType; -use ethrex_common::{Address, H160, H256, U256}; -use ethrex_l2::monitor::widget::l2_to_l1_messages::{L2ToL1MessageKind, L2ToL1MessageStatus}; -use ethrex_l2::monitor::widget::{L2ToL1MessagesTable, l2_to_l1_messages::L2ToL1MessageRow}; +use ethrex_common::{Address, H160, H256, U256, types::TxType}; +use ethrex_l2::monitor::widget::{ + L2ToL1MessagesTable, + l2_to_l1_messages::{L2ToL1MessageKind, L2ToL1MessageRow, L2ToL1MessageStatus}, +}; use ethrex_l2::sequencer::l1_watcher::PrivilegedTransactionData; -use ethrex_l2_common::calldata::Value; -use ethrex_l2_common::l1_messages::L1MessageProof; -use ethrex_l2_common::utils::get_address_from_secret_key; +use ethrex_l2_common::{ + calldata::Value, l1_messages::L1MessageProof, utils::get_address_from_secret_key, +}; use ethrex_l2_rpc::signer::{LocalSigner, Signer}; use ethrex_l2_sdk::{ - COMMON_BRIDGE_L2_ADDRESS, bridge_address, calldata::encode_calldata, claim_erc20withdraw, - claim_withdraw, compile_contract, create_deploy, deposit_erc20, get_address_alias, - get_erc1967_slot, git_clone, l1_to_l2_tx_data::L1ToL2TransactionData, + COMMON_BRIDGE_L2_ADDRESS, bridge_address, build_generic_tx, calldata::encode_calldata, + claim_erc20withdraw, claim_withdraw, compile_contract, create_deploy, deposit_erc20, + get_address_alias, get_erc1967_slot, get_last_verified_batch, git_clone, + l1_to_l2_tx_data::L1ToL2TransactionData, send_generic_transaction, wait_for_message_proof, wait_for_transaction_receipt, }; -use ethrex_l2_sdk::{ - build_generic_tx, get_last_verified_batch, send_generic_transaction, wait_for_message_proof, -}; use ethrex_rpc::{ clients::eth::{EthClient, Overrides}, types::{ @@ -1618,13 +1617,8 @@ async fn test_deploy( .get_balance(deployer.address(), BlockIdentifier::Tag(BlockTag::Latest)) .await?; - let (deploy_tx_hash, contract_address) = create_deploy( - l2_client, - &deployer, - init_code.to_vec().into(), - Overrides::default(), - ) - .await?; + let (deploy_tx_hash, contract_address) = + create_deploy(l2_client, &deployer, init_code, &[], Overrides::default()).await?; let deploy_tx_receipt = ethrex_l2_sdk::wait_for_transaction_receipt(deploy_tx_hash, l2_client, 5).await?; @@ -1668,7 +1662,8 @@ async fn test_deploy_l1( let (deploy_tx_hash, contract_address) = create_deploy( client, &deployer_signer, - init_code.to_vec().into(), + init_code, + &[], Overrides::default(), ) .await?; @@ -1847,7 +1842,7 @@ async fn wait_for_l2_deposit_receipt( } pub fn read_env_file_by_config() { - let env_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../cmd/.env"); + let env_file_path = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../.env"); let reader = BufReader::new(File::open(env_file_path).expect("Failed to open .env file")); for line in reader.lines() { @@ -1924,11 +1919,11 @@ fn test_private_keys_path() -> PathBuf { } fn rich_keys_file_path() -> PathBuf { - match std::env::var("ETHREX_DEPLOYER_PRIVATE_KEYS_FILE_PATH") { + match std::env::var("ETHREX_DEPLOYER_DEPOSIT_PRIVATE_KEYS_FILE_PATH") { Ok(path) => PathBuf::from(path), Err(_) => { println!( - "ETHREX_DEPLOYER_PRIVATE_KEYS_FILE_PATH not set, using default: {DEFAULT_RICH_KEYS_FILE_PATH}", + "ETHREX_DEPLOYER_DEPOSIT_PRIVATE_KEYS_FILE_PATH not set, using default: {DEFAULT_RICH_KEYS_FILE_PATH}", ); PathBuf::from(DEFAULT_RICH_KEYS_FILE_PATH) } diff --git a/crates/l2/utils/mod.rs b/crates/l2/utils/mod.rs index d65ea6be061..9b97a4a9ab6 100644 --- a/crates/l2/utils/mod.rs +++ b/crates/l2/utils/mod.rs @@ -1,3 +1,2 @@ pub mod error; pub mod parse; -pub mod test_data_io; diff --git a/crates/l2/utils/test_data_io.rs b/crates/l2/utils/test_data_io.rs deleted file mode 100644 index 8917d5dc5c2..00000000000 --- a/crates/l2/utils/test_data_io.rs +++ /dev/null @@ -1,74 +0,0 @@ -#![allow(clippy::unwrap_used)] -#![allow(clippy::expect_used)] - -use ethrex_common::types::{Block, Genesis}; -use ethrex_rlp::{decode::RLPDecode, encode::RLPEncode}; -use ethrex_storage::Store; -use tracing::info; - -use std::{ - fs::File, - io::{BufReader, Read as _, Write}, - path::PathBuf, -}; - -// From cmd/ethrex -pub fn read_chain_file(chain_rlp_path: &str) -> Vec { - let chain_file = File::open(chain_rlp_path).expect("Failed to open chain rlp file"); - _chain_file(chain_file).expect("Failed to decode chain rlp file") -} - -// From cmd/ethrex -pub fn read_genesis_file(genesis_file_path: &str) -> Genesis { - let genesis_file = std::fs::File::open(genesis_file_path).expect("Failed to open genesis file"); - _genesis_file(genesis_file).expect("Failed to decode genesis file") -} - -/// Generates a `test.rlp` file for use by the prover during testing. -/// Place this in the `proposer/mod.rs` file, -/// specifically in the `start` function, -/// before calling `send_commitment()` to send the block commitment. -pub async fn generate_rlp( - up_to_block_number: u64, - store: &Store, -) -> Result<(), Box> { - if store.get_latest_block_number().await? == up_to_block_number { - let mut path = PathBuf::from(env!("CARGO_MANIFEST_DIR")); - let file_name = "l2-test.rlp"; - - path.push(file_name); - - let mut file = std::fs::File::create(path.to_str().unwrap())?; - for i in 1..up_to_block_number { - let body = store.get_block_body(i).await?.unwrap(); - let header = store.get_block_header(i)?.unwrap(); - - let block = Block::new(header, body); - let vec = block.encode_to_vec(); - file.write_all(&vec)?; - } - - info!("TEST RLP GENERATED AT: {path:?}"); - } - Ok(()) -} - -// From cmd/ethrex/decode.rs -fn _chain_file(file: File) -> Result, Box> { - let mut chain_rlp_reader = BufReader::new(file); - let mut buf = vec![]; - chain_rlp_reader.read_to_end(&mut buf)?; - let mut blocks = Vec::new(); - while !buf.is_empty() { - let (item, rest) = Block::decode_unfinished(&buf)?; - blocks.push(item); - buf = rest.to_vec(); - } - Ok(blocks) -} - -// From cmd/ethrex/decode.rs -fn _genesis_file(file: File) -> Result { - let genesis_reader = BufReader::new(file); - serde_json::from_reader(genesis_reader) -} diff --git a/docs/l2/architecture/prover.md b/docs/l2/architecture/prover.md index 61518e6d1af..1de92b7c522 100644 --- a/docs/l2/architecture/prover.md +++ b/docs/l2/architecture/prover.md @@ -124,14 +124,14 @@ Two servers are required: one for the `Prover` and another for the `sequencer`. ETHREX_PROOF_COORDINATOR_L1_PRIVATE_KEY= // Used to handle TCP communication with other servers from any network interface. ETHREX_PROOF_COORDINATOR_LISTEN_ADDRESS=0.0.0.0 - // Set to true to randomize the salt. - ETHREX_DEPLOYER_RANDOMIZE_CONTRACT_DEPLOYMENT=true + // Salt to use with CREATE2 deterministic deployer. Defaults to random. + ETHREX_DEPLOYER_DETERMINISTIC_SALT= // Check if the contract is deployed in your preferred network or set to `true` to deploy it. - ETHREX_DEPLOYER_SP1_DEPLOY_VERIFIER=true + ETHREX_DEPLOYER_DEPLOY_SP1_VERIFIER=true // Check the if the contract is present on your preferred network. - ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER=
+ ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER_ADDRESS=
// It can be deployed. Check the if the contract is present on your preferred network. - ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER=
+ ETHREX_DEPLOYER_SP1_CONTRACT_VERIFIER_ADDRESS=
// Set to any L1 endpoint. ETHREX_ETH_RPC_URL= ``` @@ -176,7 +176,7 @@ Two servers are required: one for the `Prover` and another for the `sequencer`. ```bash bash contracts/script/manage DeployEstopGroth16Verifier --broadcast ``` - 1. if the deployment was successful you should see the contract address in the output of the command, you will need to pass this as an argument to the L2 contract deployer, or via the `ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER=
` env. variable. + 1. if the deployment was successful you should see the contract address in the output of the command, you will need to pass this as an argument to the L2 contract deployer, or via the `ETHREX_DEPLOYER_RISC0_CONTRACT_VERIFIER_ADDRESS=
` env. variable. if you get an error like `risc0-ethereum/contracts/../lib/forge-std/src/Script.sol": No such file or directory (os error 2)`, try to update the git submodules (foundry dependencies) with `git submodule update --init --recursive`. ## Configuration diff --git a/docs/l2/architecture/tdx.md b/docs/l2/architecture/tdx.md index 5125cc12035..245cf64a231 100644 --- a/docs/l2/architecture/tdx.md +++ b/docs/l2/architecture/tdx.md @@ -58,7 +58,7 @@ Exports an image that uses [UKI](https://uapi-group.org/specifications/specs/uni ## Running -You can enable the prover by setting `ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER=true`. +You can enable the prover by setting `ETHREX_DEPLOYER_DEPLOY_TDX_VERIFIER=true`. For development purposes, you can use the flag `ETHREX_TDX_DEV_MODE=true` to disable quote verification. This allows you to run the quote generator even without having TDX-capable hardware. @@ -66,7 +66,7 @@ Ensure the proof coordinator is reachable at 172.17.0.1. You can bring up the ne ```sh // cd crates/l2 -make init ETHREX_DEPLOYER_TDX_DEPLOY_VERIFIER=true PROOF_COORDINATOR_ADDRESS=0.0.0.0 +make init ETHREX_DEPLOYER_DEPLOY_TDX_VERIFIER=true PROOF_COORDINATOR_ADDRESS=0.0.0.0 ``` And in another terminal, running the VM: diff --git a/tooling/load_test/src/main.rs b/tooling/load_test/src/main.rs index 7c0d55323c6..f3271ac54d3 100644 --- a/tooling/load_test/src/main.rs +++ b/tooling/load_test/src/main.rs @@ -93,7 +93,7 @@ async fn deploy_contract( contract: Vec, ) -> eyre::Result
{ let (_, contract_address) = - create_deploy(&client, deployer, contract.into(), Overrides::default()).await?; + create_deploy(&client, deployer, &contract, &[], Overrides::default()).await?; eyre::Ok(contract_address) }