From e95216fc0d6a1f8f2dcae9a9d9d88b5180a37cc1 Mon Sep 17 00:00:00 2001 From: eigmax Date: Tue, 23 Apr 2024 17:17:19 +0000 Subject: [PATCH 01/12] feat: impl settlement --- Cargo.lock | 104 +++++++++++++++++- Cargo.toml | 1 + src/settlement/ethereum/client.rs | 1 - .../ethereum/interfaces/eigen_bridge.rs | 44 ++++++++ .../interfaces/eigen_global_exit_root.rs | 1 + src/settlement/ethereum/interfaces/mod.rs | 2 + src/settlement/ethereum/mod.rs | 2 +- 7 files changed, 151 insertions(+), 4 deletions(-) delete mode 100644 src/settlement/ethereum/client.rs create mode 100644 src/settlement/ethereum/interfaces/eigen_bridge.rs create mode 100644 src/settlement/ethereum/interfaces/eigen_global_exit_root.rs create mode 100644 src/settlement/ethereum/interfaces/mod.rs diff --git a/Cargo.lock b/Cargo.lock index d6a36bf..15a2945 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addr2line" version = "0.21.0" @@ -1868,6 +1878,7 @@ dependencies = [ "async-trait", "c-kzg", "env_logger", + "ethers-contract", "ethers-core", "ethers-providers", "eyre", @@ -2108,6 +2119,63 @@ dependencies = [ "smallvec", ] +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease 0.2.19", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.60", + "toml", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.60", +] + [[package]] name = "ethers-core" version = "2.0.14" @@ -2116,6 +2184,7 @@ checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" dependencies = [ "arrayvec", "bytes", + "cargo_metadata", "chrono", "const-hex", "elliptic-curve", @@ -2123,12 +2192,14 @@ dependencies = [ "generic-array", "k256", "num_enum 0.7.2", + "once_cell", "open-fastrlp", "rand 0.8.5", "rlp", "serde", "serde_json", "strum", + "syn 2.0.60", "tempfile", "thiserror", "tiny-keccak", @@ -4323,6 +4394,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "prettyplease" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ac2cf0f2e4f42b49f5ffd07dae8d746508ef7526c13940e5f524012ae6c6550" +dependencies = [ + "proc-macro2", + "syn 2.0.60", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -4478,7 +4559,7 @@ dependencies = [ "log", "multimap", "petgraph", - "prettyplease", + "prettyplease 0.1.25", "prost", "prost-types", "regex", @@ -6252,6 +6333,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scale-info" version = "2.11.2" @@ -7245,7 +7335,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" dependencies = [ - "prettyplease", + "prettyplease 0.1.25", "proc-macro2", "prost-build", "quote", @@ -7741,6 +7831,16 @@ dependencies = [ "libc", ] +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + [[package]] name = "want" version = "0.3.1" diff --git a/Cargo.toml b/Cargo.toml index 43e06ae..f36c90f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ reth-libmdbx = { git = "https://github.com/0xEigenLabs/reth", package = "reth-li #reth-rpc-types = { path = "../reth/crates/rpc/rpc-types" } ethers-providers = { version = "2.0.14", features = ["ws"] } ethers-core = { version = "2.0.14", default-features = false } +ethers-contract = { version = "2.0.14", features = ["abigen"] } # lazy_static once_cell = "1.8.0" diff --git a/src/settlement/ethereum/client.rs b/src/settlement/ethereum/client.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/settlement/ethereum/client.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/settlement/ethereum/interfaces/eigen_bridge.rs b/src/settlement/ethereum/interfaces/eigen_bridge.rs new file mode 100644 index 0000000..c4f769d --- /dev/null +++ b/src/settlement/ethereum/interfaces/eigen_bridge.rs @@ -0,0 +1,44 @@ +//! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenBridge.sol +use ethers_contract::abigen; +use ethers_core::types::{Address, Bytes, U256}; +use ethers_providers::{Http, Provider}; +use std::sync::Arc; + +// example: https://github.com/gakonst/ethers-rs/blob/master/examples/contracts/examples/abigen.rs#L55 +abigen!( + EigenBridge, + r#"[ + function bridgeAsset(uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData) public payable virtual nonReentrant + function bridgeMessage(uint32 destinationNetwork, address destinationAddress, bool forceUpdateGlobalExitRoot, bytes calldata metadata) external payable + function claimAsset(bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata) external + ]"#, +); + +#[allow(dead_code)] +pub async fn bridge_asset( + address: Address, + client: Arc>, + destination_network: u32, + destination_address: Address, + amount: U256, + token: Address, + force_update_global_exit_root: bool, + calldata: Bytes, +) { + let contract = EigenBridge::new(address, client); + + if let Ok(result) = contract + .bridge_asset( + destination_network, + destination_address, + amount, + token, + force_update_global_exit_root, + calldata, + ) + .call() + .await + { + log::debug!("bridge asset {result:?}"); + } +} diff --git a/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs b/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs new file mode 100644 index 0000000..1da74ea --- /dev/null +++ b/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs @@ -0,0 +1 @@ +//! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenGlobalExitRoot.sol diff --git a/src/settlement/ethereum/interfaces/mod.rs b/src/settlement/ethereum/interfaces/mod.rs new file mode 100644 index 0000000..8d94bf8 --- /dev/null +++ b/src/settlement/ethereum/interfaces/mod.rs @@ -0,0 +1,2 @@ +pub(crate) mod eigen_bridge; +pub(crate) mod eigen_global_exit_root; diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index 1d33131..e7ab369 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -1 +1 @@ -pub(crate) mod client; +pub(crate) mod interfaces; From d6e0cf80a30a9bb43c21b194b55d2a5c6656b3cc Mon Sep 17 00:00:00 2001 From: eigmax Date: Wed, 24 Apr 2024 02:48:14 +0000 Subject: [PATCH 02/12] feat: impl settlement --- Cargo.lock | 1 + Cargo.toml | 1 + src/operator.rs | 21 ++++++++--- .../ethereum/interfaces/eigen_bridge.rs | 7 ++-- src/settlement/ethereum/mod.rs | 32 +++++++++++++++++ src/settlement/mod.rs | 35 +++++++++++++++++++ 6 files changed, 90 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 15a2945..1c46e75 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1875,6 +1875,7 @@ name = "eigen-zeth" version = "0.1.0" dependencies = [ "alloy-chains", + "anyhow", "async-trait", "c-kzg", "env_logger", diff --git a/Cargo.toml b/Cargo.toml index f36c90f..fa63e93 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,7 @@ tokio-stream = { version = "0.1" } # Misc eyre = "0.6.8" thiserror = "1.0.40" +anyhow = "1.0" c-kzg = "0.4.2" diff --git a/src/operator.rs b/src/operator.rs index 6957361..30a32a6 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -2,31 +2,41 @@ //! They will be launched in Run CMD. use crate::prover::ProverChannel; use ethers_providers::{Http, Provider}; - +use crate::settlement::{NetworkSpec, Settlement}; +use ethers_core::types::{Bytes, H160, U256}; use tokio::sync::mpsc::{self, Receiver}; use tokio::time::{interval, Duration}; +use std::sync::Arc; use crate::db::{lfs, Database}; +use crate::settlement::ethereum::EthereumSettlement; pub(crate) struct Operator { db: Box, prover: ProverChannel, - _settler: Provider, + provider: Arc>, rx_proof: Receiver>, + // TODO: use trait object + settler: EthereumSettlement, } + impl Operator { pub fn new(_db_path: &str, l1addr: &str, prover_addr: &str) -> Self { let (sx, rx) = mpsc::channel(10); let prover = ProverChannel::new(prover_addr, sx); let db = lfs::open_db(lfs::DBConfig::Memory).unwrap(); // TODO: abstract this in the settlement - let _settler = Provider::::try_from(l1addr).unwrap(); + let provider = Provider::::try_from(l1addr).unwrap(); + let provider = Arc::new(provider); + //let settler = init_settlement(NetworkSpec::Ethereum); + let settler = EthereumSettlement{}; Operator { prover, db, - _settler, + provider, + settler, rx_proof: rx, } } @@ -72,6 +82,9 @@ impl Operator { self.prover.execute(block_no).await.unwrap(); let block_no_next = block_no + 1; self.db.put(batch_key.clone(), block_no_next.to_be_bytes().to_vec()); + + // TODO + let _ = self.settler.bridge_asset(H160::zero(), self.provider.clone(), 0, H160::zero(), U256::zero(), H160::zero(), true, Bytes::default()).await; } else { log::debug!("Wait for the new task coming in"); } diff --git a/src/settlement/ethereum/interfaces/eigen_bridge.rs b/src/settlement/ethereum/interfaces/eigen_bridge.rs index c4f769d..492e570 100644 --- a/src/settlement/ethereum/interfaces/eigen_bridge.rs +++ b/src/settlement/ethereum/interfaces/eigen_bridge.rs @@ -3,6 +3,7 @@ use ethers_contract::abigen; use ethers_core::types::{Address, Bytes, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; +use anyhow::Result; // example: https://github.com/gakonst/ethers-rs/blob/master/examples/contracts/examples/abigen.rs#L55 abigen!( @@ -14,8 +15,7 @@ abigen!( ]"#, ); -#[allow(dead_code)] -pub async fn bridge_asset( +pub(crate) async fn bridge_asset( address: Address, client: Arc>, destination_network: u32, @@ -24,7 +24,7 @@ pub async fn bridge_asset( token: Address, force_update_global_exit_root: bool, calldata: Bytes, -) { +) -> Result<()> { let contract = EigenBridge::new(address, client); if let Ok(result) = contract @@ -41,4 +41,5 @@ pub async fn bridge_asset( { log::debug!("bridge asset {result:?}"); } + Ok(()) } diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index e7ab369..c09a533 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -1 +1,33 @@ +use crate::settlement::Settlement; pub(crate) mod interfaces; +use anyhow::Result; +use ethers_core::types::{Address, Bytes, U256}; +use ethers_providers::{Http, Provider}; +use std::sync::Arc; + +pub struct EthereumSettlement {} + +impl Settlement for EthereumSettlement { + async fn bridge_asset( + &self, + address: Address, + client: Arc>, + destination_network: u32, + destination_address: Address, + amount: U256, + token: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()> { + interfaces::eigen_bridge::bridge_asset( + address, + client, + destination_network, + destination_address, + amount, + token, + force_update_global_exit_root, + calldata, + ).await + } +} diff --git a/src/settlement/mod.rs b/src/settlement/mod.rs index 214637c..f41f950 100644 --- a/src/settlement/mod.rs +++ b/src/settlement/mod.rs @@ -3,4 +3,39 @@ //! 1. get_state: get the latest state of the settlement layer, including the state root and block number. //! 2. update_state: update the state of the settlement layer with the given proof and public input. +use ethers_core::types::{Address, Bytes, U256}; +use ethers_providers::{Http, Provider}; +use std::sync::Arc; +use anyhow::Result; + pub(crate) mod ethereum; + +pub trait Settlement { + async fn bridge_asset( + &self, + address: Address, + client: Arc>, + destination_network: u32, + destination_address: Address, + amount: U256, + token: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()>; + + // TODO: add more interfaces +} + +pub enum NetworkSpec { + Ethereum, + Optimism, +} + +//pub fn init_settlement(spec: NetworkSpec) -> Box { +// match spec { +// NetworkSpec::Ethereum => { +// Box::new(ethereum::EthereumSettlement{}) +// }, +// _ => todo!("Not supported network") +// } +//} \ No newline at end of file From 04bb58f5e6a142ea4fa080765ff6c2ec0cddd587 Mon Sep 17 00:00:00 2001 From: eigmax Date: Wed, 24 Apr 2024 06:26:47 +0000 Subject: [PATCH 03/12] feat: impl settlement --- src/operator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 30a32a6..6296f16 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -23,7 +23,7 @@ pub(crate) struct Operator { impl Operator { pub fn new(_db_path: &str, l1addr: &str, prover_addr: &str) -> Self { - let (sx, rx) = mpsc::channel(10); + let (sx, rx_proof) = mpsc::channel(10); let prover = ProverChannel::new(prover_addr, sx); let db = lfs::open_db(lfs::DBConfig::Memory).unwrap(); // TODO: abstract this in the settlement @@ -37,7 +37,7 @@ impl Operator { db, provider, settler, - rx_proof: rx, + rx_proof, } } From 306ffb8d554c3e53ba5fa8d484383b17ea87e2ae Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Thu, 25 Apr 2024 17:17:35 +0800 Subject: [PATCH 04/12] refactor: mvoe zeth_db_path to GLOBAL_ENV, fix ci --- src/env.rs | 9 ++++++--- src/main.rs | 4 ++-- src/operator.rs | 15 +++++++++------ .../ethereum/interfaces/eigen_bridge.rs | 4 +++- src/settlement/ethereum/mod.rs | 3 ++- src/settlement/mod.rs | 8 ++++++-- 6 files changed, 28 insertions(+), 15 deletions(-) diff --git a/src/env.rs b/src/env.rs index 17c3f1e..9cd4301 100644 --- a/src/env.rs +++ b/src/env.rs @@ -1,6 +1,7 @@ //! This module contains the environment variables for the EigenZeth service use once_cell::sync::Lazy; +use std::string::ToString; /// EigenZethEnv is a struct that holds the environment variables pub struct EigenZethEnv { @@ -9,6 +10,7 @@ pub struct EigenZethEnv { pub prover_addr: String, pub curve_type: String, pub host: String, + pub zeth_db_path: String, pub chain_id: u64, pub program_name: String, } @@ -16,11 +18,12 @@ pub struct EigenZethEnv { /// EIGEN_ZETH_ENV is a global variable that holds the environment variables, /// it is lazy loaded and thread safe pub static GLOBAL_ENV: Lazy = Lazy::new(|| EigenZethEnv { - db_path: std::env::var("ZETH_OPERATOR_DB").unwrap(), - l1addr: std::env::var("ZETH_L2_ADDR").unwrap(), + db_path: std::env::var("ZETH_OPERATOR_DB").unwrap_or("/tmp/operator".to_string()), + l1addr: std::env::var("ZETH_L2_ADDR").unwrap_or("http://localhost:8546".to_string()), prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), - host: std::env::var("HOST").unwrap_or(":8545".to_string()), + host: std::env::var("HOST").unwrap_or("0.0.0.0:8182".to_string()), + zeth_db_path: std::env::var("ZETH_DB_PATH").unwrap_or("/tmp/chain".to_string()), chain_id: std::env::var("CHAIN_ID") .unwrap_or("12345".to_string()) .parse::() diff --git a/src/main.rs b/src/main.rs index 7680fac..3894b23 100644 --- a/src/main.rs +++ b/src/main.rs @@ -394,8 +394,8 @@ async fn main() -> eyre::Result<()> { // .build(); let spec = Arc::new(ChainSpecBuilder::mainnet().build()); - let db_path = std::env::var("ZETH_DB_PATH")?; - let db_path = std::path::Path::new(&db_path); + // let db_path =; + let db_path = std::path::Path::new(&GLOBAL_ENV.zeth_db_path); let db = Arc::new(open_db_read_only( db_path.join("db").as_path(), Default::default(), diff --git a/src/operator.rs b/src/operator.rs index 6296f16..bf3e2a9 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,12 +1,16 @@ //! Initialize all components of the eigen-zeth full node. //! They will be launched in Run CMD. + +// TODO: Fixme +#![allow(unused_imports)] + use crate::prover::ProverChannel; -use ethers_providers::{Http, Provider}; use crate::settlement::{NetworkSpec, Settlement}; use ethers_core::types::{Bytes, H160, U256}; +use ethers_providers::{Http, Provider}; +use std::sync::Arc; use tokio::sync::mpsc::{self, Receiver}; use tokio::time::{interval, Duration}; -use std::sync::Arc; use crate::db::{lfs, Database}; use crate::settlement::ethereum::EthereumSettlement; @@ -17,10 +21,9 @@ pub(crate) struct Operator { provider: Arc>, rx_proof: Receiver>, // TODO: use trait object - settler: EthereumSettlement, + settler: EthereumSettlement, } - impl Operator { pub fn new(_db_path: &str, l1addr: &str, prover_addr: &str) -> Self { let (sx, rx_proof) = mpsc::channel(10); @@ -30,8 +33,8 @@ impl Operator { let provider = Provider::::try_from(l1addr).unwrap(); let provider = Arc::new(provider); - //let settler = init_settlement(NetworkSpec::Ethereum); - let settler = EthereumSettlement{}; + //let settler = init_settlement(NetworkSpec::Ethereum); + let settler = EthereumSettlement {}; Operator { prover, db, diff --git a/src/settlement/ethereum/interfaces/eigen_bridge.rs b/src/settlement/ethereum/interfaces/eigen_bridge.rs index 492e570..ed20c54 100644 --- a/src/settlement/ethereum/interfaces/eigen_bridge.rs +++ b/src/settlement/ethereum/interfaces/eigen_bridge.rs @@ -1,9 +1,9 @@ //! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenBridge.sol +use anyhow::Result; use ethers_contract::abigen; use ethers_core::types::{Address, Bytes, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; -use anyhow::Result; // example: https://github.com/gakonst/ethers-rs/blob/master/examples/contracts/examples/abigen.rs#L55 abigen!( @@ -15,6 +15,8 @@ abigen!( ]"#, ); +// TODO: Fixme +#[allow(clippy::too_many_arguments)] pub(crate) async fn bridge_asset( address: Address, client: Arc>, diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index c09a533..1429d8b 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -28,6 +28,7 @@ impl Settlement for EthereumSettlement { token, force_update_global_exit_root, calldata, - ).await + ) + .await } } diff --git a/src/settlement/mod.rs b/src/settlement/mod.rs index f41f950..69d93dc 100644 --- a/src/settlement/mod.rs +++ b/src/settlement/mod.rs @@ -2,14 +2,18 @@ //! including the following settlement api: //! 1. get_state: get the latest state of the settlement layer, including the state root and block number. //! 2. update_state: update the state of the settlement layer with the given proof and public input. +// TODO: Fix me +#![allow(dead_code)] +use anyhow::Result; use ethers_core::types::{Address, Bytes, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; -use anyhow::Result; pub(crate) mod ethereum; +// TODO: Fixme +#[allow(clippy::too_many_arguments)] pub trait Settlement { async fn bridge_asset( &self, @@ -38,4 +42,4 @@ pub enum NetworkSpec { // }, // _ => todo!("Not supported network") // } -//} \ No newline at end of file +//} From 20b5ea6554747641fc4f914f1b4aa80de71c005e Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Sat, 27 Apr 2024 12:05:38 +0800 Subject: [PATCH 05/12] feat: refactor settlement, impl eigen_bridge, impl eigen_global_exit_root, add settlement env --- Cargo.toml | 1 + src/env.rs | 49 +++++ src/operator.rs | 25 ++- src/prover/provider.rs | 31 ++-- .../ethereum/interfaces/eigen_bridge.rs | 169 +++++++++++++++--- .../interfaces/eigen_global_exit_root.rs | 44 +++++ .../ethereum/interfaces/eigen_zkvm.rs | 12 ++ src/settlement/ethereum/interfaces/mod.rs | 1 + src/settlement/ethereum/mod.rs | 165 +++++++++++++++-- src/settlement/mod.rs | 67 +++++-- 10 files changed, 483 insertions(+), 81 deletions(-) create mode 100644 src/settlement/ethereum/interfaces/eigen_zkvm.rs diff --git a/Cargo.toml b/Cargo.toml index fa63e93..dbf74ea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ reth-libmdbx = { git = "https://github.com/0xEigenLabs/reth", package = "reth-li ethers-providers = { version = "2.0.14", features = ["ws"] } ethers-core = { version = "2.0.14", default-features = false } ethers-contract = { version = "2.0.14", features = ["abigen"] } +ethers = "2.0.14" # lazy_static once_cell = "1.8.0" diff --git a/src/env.rs b/src/env.rs index 9cd4301..67516e6 100644 --- a/src/env.rs +++ b/src/env.rs @@ -13,6 +13,34 @@ pub struct EigenZethEnv { pub zeth_db_path: String, pub chain_id: u64, pub program_name: String, + pub settlement: SettlementEnv, +} + +#[derive(Clone)] +pub struct SettlementEnv { + pub eth_env: EthereumEnv, +} + +#[derive(Clone)] +pub struct EthereumEnv { + pub provider_url: String, + pub local_wallet: LocalWalletConfig, + pub l1_contracts_addr: EthContractsAddr, +} + +#[derive(Clone)] +pub struct LocalWalletConfig { + pub private_key: String, + pub chain_id: u64, +} + +// TODO: Fixme +#[allow(dead_code)] +#[derive(Clone)] +pub struct EthContractsAddr { + pub eigen_bridge: String, + pub eigen_global_exit: String, + pub eigen_zkvm: String, } /// EIGEN_ZETH_ENV is a global variable that holds the environment variables, @@ -31,4 +59,25 @@ pub static GLOBAL_ENV: Lazy = Lazy::new(|| EigenZethEnv { program_name: std::env::var("PROGRAM_NAME") .unwrap_or("EVM".to_string()) .to_lowercase(), + // TODO: too many env variables, I will move this to a config file,and use clap command to receive the path to the config file + settlement: SettlementEnv { + eth_env: EthereumEnv { + provider_url: std::env::var("ETH_PROVIDER_URL") + .unwrap_or("http://localhost:8546".to_string()), + local_wallet: LocalWalletConfig { + private_key: std::env::var("PRIVATE_KEY").unwrap_or("".to_string()), + chain_id: std::env::var("CHAIN_ID") + .unwrap_or("12345".to_string()) + .parse() + .unwrap(), + }, + l1_contracts_addr: EthContractsAddr { + eigen_bridge: std::env::var("EIGEN_BRIDGE_CONTRACT_ADDR") + .unwrap_or("0x".to_string()), + eigen_global_exit: std::env::var("EIGEN_GLOBAL_EXIT_CONTRACT_ADDR") + .unwrap_or("0x".to_string()), + eigen_zkvm: std::env::var("EIGEN_ZKVM_CONTRACT_ADDR").unwrap_or("0x".to_string()), + }, + }, + }, }); diff --git a/src/operator.rs b/src/operator.rs index bf3e2a9..9cd0ad0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -5,7 +5,7 @@ #![allow(unused_imports)] use crate::prover::ProverChannel; -use crate::settlement::{NetworkSpec, Settlement}; +use crate::settlement::{init_settlement, NetworkSpec, Settlement}; use ethers_core::types::{Bytes, H160, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; @@ -13,32 +13,29 @@ use tokio::sync::mpsc::{self, Receiver}; use tokio::time::{interval, Duration}; use crate::db::{lfs, Database}; -use crate::settlement::ethereum::EthereumSettlement; +use crate::env::GLOBAL_ENV; +use crate::settlement::ethereum::{EthereumSettlement, EthereumSettlementConfig}; pub(crate) struct Operator { db: Box, prover: ProverChannel, - provider: Arc>, rx_proof: Receiver>, - // TODO: use trait object - settler: EthereumSettlement, + settler: Box, } impl Operator { - pub fn new(_db_path: &str, l1addr: &str, prover_addr: &str) -> Self { + pub fn new(_db_path: &str, _l1addr: &str, prover_addr: &str) -> Self { let (sx, rx_proof) = mpsc::channel(10); let prover = ProverChannel::new(prover_addr, sx); let db = lfs::open_db(lfs::DBConfig::Memory).unwrap(); - // TODO: abstract this in the settlement - let provider = Provider::::try_from(l1addr).unwrap(); - let provider = Arc::new(provider); - //let settler = init_settlement(NetworkSpec::Ethereum); - let settler = EthereumSettlement {}; + let settler = init_settlement(NetworkSpec::Ethereum(EthereumSettlementConfig { + eth_settlement_env: GLOBAL_ENV.settlement.eth_env.clone(), + })); + // let settler = EthereumSettlement {}; Operator { prover, db, - provider, settler, rx_proof, } @@ -87,13 +84,13 @@ impl Operator { self.db.put(batch_key.clone(), block_no_next.to_be_bytes().to_vec()); // TODO - let _ = self.settler.bridge_asset(H160::zero(), self.provider.clone(), 0, H160::zero(), U256::zero(), H160::zero(), true, Bytes::default()).await; + let _ = self.settler.bridge_asset(0, H160::zero(), U256::zero(), H160::zero(), true, Bytes::default()).await; } else { log::debug!("Wait for the new task coming in"); } } _ = stop_channel.recv() => { - break; + self.prover.stop().await.unwrap(); } }; } diff --git a/src/prover/provider.rs b/src/prover/provider.rs index 6ab5cc4..a523d9b 100644 --- a/src/prover/provider.rs +++ b/src/prover/provider.rs @@ -42,6 +42,9 @@ pub struct ProverChannel { /// final proof final_proof_sender: Sender>, + + /// used to stop the endpoint + stop_endpoint_tx: Sender<()>, } type BlockNumber = u64; @@ -76,14 +79,21 @@ impl ProverChannel { pub fn new(addr: &str, sender: Sender>) -> Self { let (response_sender, response_receiver) = mpsc::channel(10); let (request_sender, request_receiver) = mpsc::channel(10); + let (stop_tx, stop_rx) = mpsc::channel(1); ProverChannel { step: ProveStep::Start, current_batch: None, parent_batch: None, - endpoint: Some(ProverEndpoint::new(addr, response_sender, request_receiver)), + endpoint: Some(ProverEndpoint::new( + addr, + response_sender, + request_receiver, + stop_rx, + )), request_sender, response_receiver, final_proof_sender: sender, + stop_endpoint_tx: stop_tx, } } @@ -111,6 +121,8 @@ impl ProverChannel { pub async fn stop(&mut self) -> Result<(), Box> { // stop the endpoint + self.stop_endpoint_tx.send(()).await?; + Ok(()) } @@ -278,8 +290,8 @@ pub struct ProverEndpoint { // request_sender: Sender, /// used to receive request, and send to ProverServer request_receiver: Option>, - /// used to stop the endpoint - stop_endpoint_tx: Sender<()>, + // /// used to stop the endpoint + // stop_endpoint_tx: Sender<()>, /// listen to the stop signal, and stop the endpoint loop stop_endpoint_rx: Receiver<()>, @@ -292,12 +304,11 @@ impl ProverEndpoint { addr: &str, response_sender: Sender, request_receiver: Receiver, + stop_rx: Receiver<()>, ) -> Self { - let (stop_tx, stop_rx) = mpsc::channel(1); ProverEndpoint { addr: addr.to_string(), request_receiver: Some(request_receiver), - stop_endpoint_tx: stop_tx, stop_endpoint_rx: stop_rx, response_sender, } @@ -359,9 +370,9 @@ impl ProverEndpoint { } } - /// stop the endpoint - pub async fn stop(&mut self) -> Result<(), Box> { - self.stop_endpoint_tx.send(()).await?; - Ok(()) - } + // stop the endpoint + // pub async fn stop(&mut self) -> Result<(), Box> { + // self.stop_endpoint_tx.send(()).await?; + // Ok(()) + // } } diff --git a/src/settlement/ethereum/interfaces/eigen_bridge.rs b/src/settlement/ethereum/interfaces/eigen_bridge.rs index ed20c54..6945741 100644 --- a/src/settlement/ethereum/interfaces/eigen_bridge.rs +++ b/src/settlement/ethereum/interfaces/eigen_bridge.rs @@ -1,5 +1,7 @@ //! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenBridge.sol use anyhow::Result; +use ethers::middleware::SignerMiddleware; +use ethers::prelude::LocalWallet; use ethers_contract::abigen; use ethers_core::types::{Address, Bytes, U256}; use ethers_providers::{Http, Provider}; @@ -12,36 +14,147 @@ abigen!( function bridgeAsset(uint32 destinationNetwork, address destinationAddress, uint256 amount, address token, bool forceUpdateGlobalExitRoot, bytes calldata permitData) public payable virtual nonReentrant function bridgeMessage(uint32 destinationNetwork, address destinationAddress, bool forceUpdateGlobalExitRoot, bytes calldata metadata) external payable function claimAsset(bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originTokenAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata) external + function claimMessage(bytes32[32] calldata smtProof, uint32 index, bytes32 mainnetExitRoot, bytes32 rollupExitRoot, uint32 originNetwork, address originAddress, uint32 destinationNetwork, address destinationAddress, uint256 amount, bytes calldata metadata) external ]"#, ); -// TODO: Fixme -#[allow(clippy::too_many_arguments)] -pub(crate) async fn bridge_asset( - address: Address, - client: Arc>, - destination_network: u32, - destination_address: Address, - amount: U256, - token: Address, - force_update_global_exit_root: bool, - calldata: Bytes, -) -> Result<()> { - let contract = EigenBridge::new(address, client); - - if let Ok(result) = contract - .bridge_asset( - destination_network, - destination_address, - amount, - token, - force_update_global_exit_root, - calldata, - ) - .call() - .await - { - log::debug!("bridge asset {result:?}"); +pub struct EigenBridgeContractClient { + contract: EigenBridge, LocalWallet>>, +} + +impl EigenBridgeContractClient { + pub fn new(contract_address: Address, provider: Provider, wallet: LocalWallet) -> Self { + let client = SignerMiddleware::new(provider, wallet); + let contract = EigenBridge::new(contract_address, Arc::new(client)); + EigenBridgeContractClient { contract } + } + + // TODO: Fixme + #[allow(clippy::too_many_arguments)] + pub(crate) async fn bridge_asset( + &self, + destination_network: u32, + destination_address: Address, + amount: U256, + token: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()> { + if let Ok(result) = self + .contract + .bridge_asset( + destination_network, + destination_address, + amount, + token, + force_update_global_exit_root, + calldata, + ) + .send() + .await + { + log::debug!("bridge asset {result:?}"); + } + Ok(()) + } + + pub(crate) async fn bridge_message( + &self, + destination_network: u32, + destination_address: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()> { + if let Ok(result) = self + .contract + .bridge_message( + destination_network, + destination_address, + force_update_global_exit_root, + calldata, + ) + .send() + .await + { + log::debug!("bridge message {result:?}"); + } + Ok(()) + } + + // TODO: Fixme + #[allow(clippy::too_many_arguments)] + pub(crate) async fn claim_asset( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_token_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()> { + if let Ok(result) = self + .contract + .claim_asset( + smt_proof, + index, + mainnet_exit_root, + rollup_exit_root, + origin_network, + origin_token_address, + destination_network, + destination_address, + amount, + metadata, + ) + .send() + .await + { + log::debug!("claim asset {result:?}"); + } + Ok(()) + } + + // TODO: Fixme + #[allow(clippy::too_many_arguments)] + pub(crate) async fn claim_message( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()> { + if let Ok(result) = self + .contract + .claim_message( + smt_proof, + index, + mainnet_exit_root, + rollup_exit_root, + origin_network, + origin_address, + destination_network, + destination_address, + amount, + metadata, + ) + .send() + .await + { + log::debug!("claim message {result:?}"); + } + Ok(()) } - Ok(()) } + +#[cfg(test)] +mod tests {} diff --git a/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs b/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs index 1da74ea..bbd5fa9 100644 --- a/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs +++ b/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs @@ -1 +1,45 @@ //! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenGlobalExitRoot.sol +use anyhow::Result; +use ethers::middleware::SignerMiddleware; +use ethers::prelude::LocalWallet; +use ethers_contract::abigen; +use ethers_core::types::Address; +use ethers_providers::{Http, Provider}; +use std::sync::Arc; + +abigen!( + EigenGlobalExitRoot, + r#"[ + function updateExitRoot(bytes32 newRollupExitRoot) external + function getLastGlobalExitRoot() public view returns (bytes32) + ]"#, +); + +pub struct EigenGlobalExitRootContractClient { + contract: EigenGlobalExitRoot, LocalWallet>>, +} + +impl EigenGlobalExitRootContractClient { + pub fn new(contract_address: Address, provider: Provider, wallet: LocalWallet) -> Self { + let client = SignerMiddleware::new(provider, wallet); + let contract = EigenGlobalExitRoot::new(contract_address, Arc::new(client)); + EigenGlobalExitRootContractClient { contract } + } + + pub async fn update_exit_root(&self, new_rollup_exit_root: [u8; 32]) -> Result<()> { + if let Ok(result) = self + .contract + .update_exit_root(new_rollup_exit_root) + .send() + .await + { + log::debug!("update exit root {result:?}"); + } + Ok(()) + } + + pub async fn get_last_global_exit_root(&self) -> Result<[u8; 32]> { + let last_global_exit_root = self.contract.get_last_global_exit_root().call().await?; + Ok(last_global_exit_root) + } +} diff --git a/src/settlement/ethereum/interfaces/eigen_zkvm.rs b/src/settlement/ethereum/interfaces/eigen_zkvm.rs new file mode 100644 index 0000000..0c12577 --- /dev/null +++ b/src/settlement/ethereum/interfaces/eigen_zkvm.rs @@ -0,0 +1,12 @@ +//! Rust contract client for https://github.com/0xEigenLabs/eigen-bridge-contracts/blob/feature/bridge_contract/src/EigenZkVM.sol + +// need abi.json +// abigen!( +// EigenZkVM, +// r#"[ +// function sequenceBatches(BatchData[] calldata batches,address l2Coinbase) external onlyAdmin +// ]"#, +// ); +// +// function verifyBatches(uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, Proof calldata proof, uint[1] calldata input) external +// function verifyBatchesTrustedAggregator(uint64 pendingStateNum, uint64 initNumBatch, uint64 finalNewBatch, bytes32 newLocalExitRoot, bytes32 newStateRoot, Proof calldata proof, uint[1] calldata input) external onlyAdmin diff --git a/src/settlement/ethereum/interfaces/mod.rs b/src/settlement/ethereum/interfaces/mod.rs index 8d94bf8..3a6dcc7 100644 --- a/src/settlement/ethereum/interfaces/mod.rs +++ b/src/settlement/ethereum/interfaces/mod.rs @@ -1,2 +1,3 @@ pub(crate) mod eigen_bridge; pub(crate) mod eigen_global_exit_root; +mod eigen_zkvm; diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index 1429d8b..8cd81a1 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -1,17 +1,66 @@ use crate::settlement::Settlement; pub(crate) mod interfaces; +use crate::env::EthereumEnv; +use crate::settlement::ethereum::interfaces::eigen_bridge::EigenBridgeContractClient; +use crate::settlement::ethereum::interfaces::eigen_global_exit_root::EigenGlobalExitRootContractClient; use anyhow::Result; +use async_trait::async_trait; +use ethers::signers::{LocalWallet, Signer}; +use ethers_core::k256::elliptic_curve::SecretKey; use ethers_core::types::{Address, Bytes, U256}; +use ethers_core::utils::hex; use ethers_providers::{Http, Provider}; -use std::sync::Arc; -pub struct EthereumSettlement {} +pub struct EthereumSettlement { + pub eigen_bridge_client: EigenBridgeContractClient, + pub eigen_global_exit_root_client: EigenGlobalExitRootContractClient, +} + +pub struct EthereumSettlementConfig { + pub eth_settlement_env: EthereumEnv, +} + +impl EthereumSettlement { + pub fn new(config: EthereumSettlementConfig) -> Self { + let provider = Provider::::try_from(&config.eth_settlement_env.provider_url).unwrap(); + let kye_bytes = hex::decode(&config.eth_settlement_env.local_wallet.private_key).unwrap(); + let secret_key = SecretKey::from_slice(&kye_bytes).unwrap(); + let local_wallet: LocalWallet = LocalWallet::from(secret_key) + .with_chain_id(config.eth_settlement_env.local_wallet.chain_id); + + let eigen_bridge_address: Address = config + .eth_settlement_env + .l1_contracts_addr + .eigen_bridge + .parse() + .unwrap(); + + let eigen_global_exit_root_address: Address = config + .eth_settlement_env + .l1_contracts_addr + .eigen_global_exit + .parse() + .unwrap(); + + EthereumSettlement { + eigen_bridge_client: EigenBridgeContractClient::new( + eigen_bridge_address, + provider.clone(), + local_wallet.clone(), + ), + eigen_global_exit_root_client: EigenGlobalExitRootContractClient::new( + eigen_global_exit_root_address, + provider, + local_wallet.clone(), + ), + } + } +} +#[async_trait] impl Settlement for EthereumSettlement { async fn bridge_asset( &self, - address: Address, - client: Arc>, destination_network: u32, destination_address: Address, amount: U256, @@ -19,16 +68,102 @@ impl Settlement for EthereumSettlement { force_update_global_exit_root: bool, calldata: Bytes, ) -> Result<()> { - interfaces::eigen_bridge::bridge_asset( - address, - client, - destination_network, - destination_address, - amount, - token, - force_update_global_exit_root, - calldata, - ) - .await + self.eigen_bridge_client + .bridge_asset( + destination_network, + destination_address, + amount, + token, + force_update_global_exit_root, + calldata, + ) + .await + } + + async fn bridge_message( + &self, + destination_network: u32, + destination_address: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()> { + self.eigen_bridge_client + .bridge_message( + destination_network, + destination_address, + force_update_global_exit_root, + calldata, + ) + .await + } + + async fn claim_asset( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_token_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()> { + self.eigen_bridge_client + .claim_asset( + smt_proof, + index, + mainnet_exit_root, + rollup_exit_root, + origin_network, + origin_token_address, + destination_network, + destination_address, + amount, + metadata, + ) + .await + } + + async fn claim_message( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()> { + self.eigen_bridge_client + .claim_message( + smt_proof, + index, + mainnet_exit_root, + rollup_exit_root, + origin_network, + origin_address, + destination_network, + destination_address, + amount, + metadata, + ) + .await + } + + async fn update_global_exit_root(&self, new_root: [u8; 32]) -> Result<()> { + self.eigen_global_exit_root_client + .update_exit_root(new_root) + .await + } + + async fn get_global_exit_root(&self) -> Result<[u8; 32]> { + self.eigen_global_exit_root_client + .get_last_global_exit_root() + .await } } diff --git a/src/settlement/mod.rs b/src/settlement/mod.rs index 69d93dc..d93337a 100644 --- a/src/settlement/mod.rs +++ b/src/settlement/mod.rs @@ -4,21 +4,20 @@ //! 2. update_state: update the state of the settlement layer with the given proof and public input. // TODO: Fix me #![allow(dead_code)] - use anyhow::Result; +use async_trait::async_trait; use ethers_core::types::{Address, Bytes, U256}; -use ethers_providers::{Http, Provider}; -use std::sync::Arc; pub(crate) mod ethereum; // TODO: Fixme #[allow(clippy::too_many_arguments)] +#[async_trait] pub trait Settlement { + // eigen_bridge + async fn bridge_asset( &self, - address: Address, - client: Arc>, destination_network: u32, destination_address: Address, amount: U256, @@ -27,19 +26,59 @@ pub trait Settlement { calldata: Bytes, ) -> Result<()>; + async fn bridge_message( + &self, + destination_network: u32, + destination_address: Address, + force_update_global_exit_root: bool, + calldata: Bytes, + ) -> Result<()>; + + async fn claim_asset( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_token_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()>; + + async fn claim_message( + &self, + smt_proof: [[u8; 32]; 32], + index: u32, + mainnet_exit_root: [u8; 32], + rollup_exit_root: [u8; 32], + origin_network: u32, + origin_address: Address, + destination_network: u32, + destination_address: Address, + amount: U256, + metadata: Bytes, + ) -> Result<()>; + + // eigen_global_exit_root + + async fn update_global_exit_root(&self, new_root: [u8; 32]) -> Result<()>; + + async fn get_global_exit_root(&self) -> Result<[u8; 32]>; + // TODO: add more interfaces } pub enum NetworkSpec { - Ethereum, + Ethereum(ethereum::EthereumSettlementConfig), Optimism, } -//pub fn init_settlement(spec: NetworkSpec) -> Box { -// match spec { -// NetworkSpec::Ethereum => { -// Box::new(ethereum::EthereumSettlement{}) -// }, -// _ => todo!("Not supported network") -// } -//} +pub fn init_settlement(spec: NetworkSpec) -> Box { + match spec { + NetworkSpec::Ethereum(config) => Box::new(ethereum::EthereumSettlement::new(config)), + _ => todo!("Not supported network"), + } +} From 880c904b253951de3ba83d069f2a9a6853c8ce84 Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Sat, 27 Apr 2024 18:36:46 +0800 Subject: [PATCH 06/12] refactor: remove prefix "eigen" --- src/db/lfs/libmdbx.rs | 4 +-- src/env.rs | 19 +++++----- .../interfaces/{eigen_bridge.rs => bridge.rs} | 8 +++-- ...lobal_exit_root.rs => global_exit_root.rs} | 6 ++-- src/settlement/ethereum/interfaces/mod.rs | 6 ++-- .../interfaces/{eigen_zkvm.rs => zkvm.rs} | 0 src/settlement/ethereum/mod.rs | 36 +++++++++---------- src/settlement/mod.rs | 4 +-- 8 files changed, 42 insertions(+), 41 deletions(-) rename src/settlement/ethereum/interfaces/{eigen_bridge.rs => bridge.rs} (96%) rename src/settlement/ethereum/interfaces/{eigen_global_exit_root.rs => global_exit_root.rs} (90%) rename src/settlement/ethereum/interfaces/{eigen_zkvm.rs => zkvm.rs} (100%) diff --git a/src/db/lfs/libmdbx.rs b/src/db/lfs/libmdbx.rs index fb0b2a8..911528f 100644 --- a/src/db/lfs/libmdbx.rs +++ b/src/db/lfs/libmdbx.rs @@ -93,8 +93,8 @@ mod tests { } #[test] - fn test_eigen_mdbx() { - let path = "tmp/test_eigen_mdbx_dn"; + fn test_mdbx() { + let path = "tmp/test_mdbx_db"; let max_dbs = 20; let mut db = open_mdbx_db(path, max_dbs).unwrap(); diff --git a/src/env.rs b/src/env.rs index 67516e6..f11850e 100644 --- a/src/env.rs +++ b/src/env.rs @@ -4,7 +4,7 @@ use once_cell::sync::Lazy; use std::string::ToString; /// EigenZethEnv is a struct that holds the environment variables -pub struct EigenZethEnv { +pub struct GlobalEnv { pub db_path: String, pub l1addr: String, pub prover_addr: String, @@ -38,14 +38,14 @@ pub struct LocalWalletConfig { #[allow(dead_code)] #[derive(Clone)] pub struct EthContractsAddr { - pub eigen_bridge: String, - pub eigen_global_exit: String, - pub eigen_zkvm: String, + pub bridge: String, + pub global_exit: String, + pub zkvm: String, } -/// EIGEN_ZETH_ENV is a global variable that holds the environment variables, +/// GLOBAL_ENV is a global variable that holds the environment variables, /// it is lazy loaded and thread safe -pub static GLOBAL_ENV: Lazy = Lazy::new(|| EigenZethEnv { +pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { db_path: std::env::var("ZETH_OPERATOR_DB").unwrap_or("/tmp/operator".to_string()), l1addr: std::env::var("ZETH_L2_ADDR").unwrap_or("http://localhost:8546".to_string()), prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), @@ -72,11 +72,10 @@ pub static GLOBAL_ENV: Lazy = Lazy::new(|| EigenZethEnv { .unwrap(), }, l1_contracts_addr: EthContractsAddr { - eigen_bridge: std::env::var("EIGEN_BRIDGE_CONTRACT_ADDR") + bridge: std::env::var("ZETH_BRIDGE_CONTRACT_ADDR").unwrap_or("0x".to_string()), + global_exit: std::env::var("ZETH_GLOBAL_EXIT_CONTRACT_ADDR") .unwrap_or("0x".to_string()), - eigen_global_exit: std::env::var("EIGEN_GLOBAL_EXIT_CONTRACT_ADDR") - .unwrap_or("0x".to_string()), - eigen_zkvm: std::env::var("EIGEN_ZKVM_CONTRACT_ADDR").unwrap_or("0x".to_string()), + zkvm: std::env::var("ZETH_ZKVM_CONTRACT_ADDR").unwrap_or("0x".to_string()), }, }, }, diff --git a/src/settlement/ethereum/interfaces/eigen_bridge.rs b/src/settlement/ethereum/interfaces/bridge.rs similarity index 96% rename from src/settlement/ethereum/interfaces/eigen_bridge.rs rename to src/settlement/ethereum/interfaces/bridge.rs index 6945741..7c29e49 100644 --- a/src/settlement/ethereum/interfaces/eigen_bridge.rs +++ b/src/settlement/ethereum/interfaces/bridge.rs @@ -18,15 +18,15 @@ abigen!( ]"#, ); -pub struct EigenBridgeContractClient { +pub struct BridgeContractClient { contract: EigenBridge, LocalWallet>>, } -impl EigenBridgeContractClient { +impl BridgeContractClient { pub fn new(contract_address: Address, provider: Provider, wallet: LocalWallet) -> Self { let client = SignerMiddleware::new(provider, wallet); let contract = EigenBridge::new(contract_address, Arc::new(client)); - EigenBridgeContractClient { contract } + BridgeContractClient { contract } } // TODO: Fixme @@ -51,6 +51,8 @@ impl EigenBridgeContractClient { calldata, ) .send() + .await? + .inspect(|s| log::info!("pending bridge asset transaction: {:?}", **s)) .await { log::debug!("bridge asset {result:?}"); diff --git a/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs b/src/settlement/ethereum/interfaces/global_exit_root.rs similarity index 90% rename from src/settlement/ethereum/interfaces/eigen_global_exit_root.rs rename to src/settlement/ethereum/interfaces/global_exit_root.rs index bbd5fa9..fa35774 100644 --- a/src/settlement/ethereum/interfaces/eigen_global_exit_root.rs +++ b/src/settlement/ethereum/interfaces/global_exit_root.rs @@ -15,15 +15,15 @@ abigen!( ]"#, ); -pub struct EigenGlobalExitRootContractClient { +pub struct GlobalExitRootContractClient { contract: EigenGlobalExitRoot, LocalWallet>>, } -impl EigenGlobalExitRootContractClient { +impl GlobalExitRootContractClient { pub fn new(contract_address: Address, provider: Provider, wallet: LocalWallet) -> Self { let client = SignerMiddleware::new(provider, wallet); let contract = EigenGlobalExitRoot::new(contract_address, Arc::new(client)); - EigenGlobalExitRootContractClient { contract } + GlobalExitRootContractClient { contract } } pub async fn update_exit_root(&self, new_rollup_exit_root: [u8; 32]) -> Result<()> { diff --git a/src/settlement/ethereum/interfaces/mod.rs b/src/settlement/ethereum/interfaces/mod.rs index 3a6dcc7..e2e101b 100644 --- a/src/settlement/ethereum/interfaces/mod.rs +++ b/src/settlement/ethereum/interfaces/mod.rs @@ -1,3 +1,3 @@ -pub(crate) mod eigen_bridge; -pub(crate) mod eigen_global_exit_root; -mod eigen_zkvm; +pub(crate) mod bridge; +pub(crate) mod global_exit_root; +mod zkvm; diff --git a/src/settlement/ethereum/interfaces/eigen_zkvm.rs b/src/settlement/ethereum/interfaces/zkvm.rs similarity index 100% rename from src/settlement/ethereum/interfaces/eigen_zkvm.rs rename to src/settlement/ethereum/interfaces/zkvm.rs diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index 8cd81a1..595bdf7 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -1,8 +1,8 @@ use crate::settlement::Settlement; pub(crate) mod interfaces; use crate::env::EthereumEnv; -use crate::settlement::ethereum::interfaces::eigen_bridge::EigenBridgeContractClient; -use crate::settlement::ethereum::interfaces::eigen_global_exit_root::EigenGlobalExitRootContractClient; +use crate::settlement::ethereum::interfaces::bridge::BridgeContractClient; +use crate::settlement::ethereum::interfaces::global_exit_root::GlobalExitRootContractClient; use anyhow::Result; use async_trait::async_trait; use ethers::signers::{LocalWallet, Signer}; @@ -12,8 +12,8 @@ use ethers_core::utils::hex; use ethers_providers::{Http, Provider}; pub struct EthereumSettlement { - pub eigen_bridge_client: EigenBridgeContractClient, - pub eigen_global_exit_root_client: EigenGlobalExitRootContractClient, + pub bridge_client: BridgeContractClient, + pub global_exit_root_client: GlobalExitRootContractClient, } pub struct EthereumSettlementConfig { @@ -28,28 +28,28 @@ impl EthereumSettlement { let local_wallet: LocalWallet = LocalWallet::from(secret_key) .with_chain_id(config.eth_settlement_env.local_wallet.chain_id); - let eigen_bridge_address: Address = config + let bridge_address: Address = config .eth_settlement_env .l1_contracts_addr - .eigen_bridge + .bridge .parse() .unwrap(); - let eigen_global_exit_root_address: Address = config + let global_exit_root_address: Address = config .eth_settlement_env .l1_contracts_addr - .eigen_global_exit + .global_exit .parse() .unwrap(); EthereumSettlement { - eigen_bridge_client: EigenBridgeContractClient::new( - eigen_bridge_address, + bridge_client: BridgeContractClient::new( + bridge_address, provider.clone(), local_wallet.clone(), ), - eigen_global_exit_root_client: EigenGlobalExitRootContractClient::new( - eigen_global_exit_root_address, + global_exit_root_client: GlobalExitRootContractClient::new( + global_exit_root_address, provider, local_wallet.clone(), ), @@ -68,7 +68,7 @@ impl Settlement for EthereumSettlement { force_update_global_exit_root: bool, calldata: Bytes, ) -> Result<()> { - self.eigen_bridge_client + self.bridge_client .bridge_asset( destination_network, destination_address, @@ -87,7 +87,7 @@ impl Settlement for EthereumSettlement { force_update_global_exit_root: bool, calldata: Bytes, ) -> Result<()> { - self.eigen_bridge_client + self.bridge_client .bridge_message( destination_network, destination_address, @@ -110,7 +110,7 @@ impl Settlement for EthereumSettlement { amount: U256, metadata: Bytes, ) -> Result<()> { - self.eigen_bridge_client + self.bridge_client .claim_asset( smt_proof, index, @@ -139,7 +139,7 @@ impl Settlement for EthereumSettlement { amount: U256, metadata: Bytes, ) -> Result<()> { - self.eigen_bridge_client + self.bridge_client .claim_message( smt_proof, index, @@ -156,13 +156,13 @@ impl Settlement for EthereumSettlement { } async fn update_global_exit_root(&self, new_root: [u8; 32]) -> Result<()> { - self.eigen_global_exit_root_client + self.global_exit_root_client .update_exit_root(new_root) .await } async fn get_global_exit_root(&self) -> Result<[u8; 32]> { - self.eigen_global_exit_root_client + self.global_exit_root_client .get_last_global_exit_root() .await } diff --git a/src/settlement/mod.rs b/src/settlement/mod.rs index d93337a..90ffa9e 100644 --- a/src/settlement/mod.rs +++ b/src/settlement/mod.rs @@ -14,7 +14,7 @@ pub(crate) mod ethereum; #[allow(clippy::too_many_arguments)] #[async_trait] pub trait Settlement { - // eigen_bridge + // bridge async fn bridge_asset( &self, @@ -62,7 +62,7 @@ pub trait Settlement { metadata: Bytes, ) -> Result<()>; - // eigen_global_exit_root + // global_exit_root async fn update_global_exit_root(&self, new_root: [u8; 32]) -> Result<()>; From 1fbb8ef2a0c6d80aee43bd6d47eacf4e5c0401d0 Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Sun, 28 Apr 2024 17:57:58 +0800 Subject: [PATCH 07/12] refactor: start with CLI, move settlement layer env to config file --- Cargo.lock | 725 ++++++++++++++++++- Cargo.toml | 6 + configs/settlement.toml | 11 + src/{batchproposer => batch_proposer}/mod.rs | 0 src/cli.rs | 28 + src/commands/chain_info.rs | 10 + src/commands/config.rs | 11 + src/commands/mod.rs | 3 + src/commands/run.rs | 144 ++++ src/config/env.rs | 35 + src/config/mod.rs | 1 + src/custom_reth/mod.rs | 396 ++++++++++ src/da/ethereum/mod.rs | 1 - src/da/mod.rs | 5 - src/env.rs | 82 --- src/main.rs | 446 +----------- src/operator.rs | 29 +- src/prover/provider.rs | 29 +- src/settlement/ethereum/mod.rs | 104 ++- src/settlement/mod.rs | 4 +- 20 files changed, 1460 insertions(+), 610 deletions(-) create mode 100644 configs/settlement.toml rename src/{batchproposer => batch_proposer}/mod.rs (100%) create mode 100644 src/commands/chain_info.rs create mode 100644 src/commands/config.rs create mode 100644 src/commands/mod.rs create mode 100644 src/commands/run.rs create mode 100644 src/config/env.rs create mode 100644 src/config/mod.rs create mode 100644 src/custom_reth/mod.rs delete mode 100644 src/da/ethereum/mod.rs delete mode 100644 src/da/mod.rs delete mode 100644 src/env.rs diff --git a/Cargo.lock b/Cargo.lock index 1c46e75..f2c5e90 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -329,7 +329,7 @@ dependencies = [ "arbitrary", "derive_arbitrary", "derive_more", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "nybbles", "proptest", "proptest-derive", @@ -560,6 +560,15 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "ascii-canvas" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +dependencies = [ + "term", +] + [[package]] name = "async-compression" version = "0.4.9" @@ -572,8 +581,8 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "zstd", - "zstd-safe", + "zstd 0.13.1", + "zstd-safe 7.1.0", ] [[package]] @@ -747,9 +756,9 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" @@ -757,6 +766,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "beef" version = "0.5.2" @@ -980,7 +995,7 @@ checksum = "f3e5afa991908cfbe79bd3109b824e473a1dc5f74f31fab91bb44c9e245daa77" dependencies = [ "boa_gc", "boa_macros", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "indexmap 2.2.6", "once_cell", "phf", @@ -1052,6 +1067,16 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2", + "tinyvec", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -1085,6 +1110,27 @@ dependencies = [ "serde", ] +[[package]] +name = "bzip2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" +dependencies = [ + "bzip2-sys", + "libc", +] + +[[package]] +name = "bzip2-sys" +version = "0.1.11+1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +dependencies = [ + "cc", + "libc", + "pkg-config", +] + [[package]] name = "c-kzg" version = "0.4.2" @@ -1247,12 +1293,84 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15" +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac", + "k256", + "serde", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2", + "sha3", + "thiserror", +] + [[package]] name = "colorchoice" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "config" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7328b20597b53c2454f0b1919720c25c7339051c02b72b7e05409e00b14132be" +dependencies = [ + "async-trait", + "convert_case 0.6.0", + "json5", + "lazy_static", + "nom", + "pathdiff", + "ron", + "rust-ini", + "serde", + "serde_json", + "toml", + "yaml-rust", +] + [[package]] name = "confy" version = "0.6.1" @@ -1284,12 +1402,38 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const-random" +version = "0.1.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87e00182fe74b066627d63b85fd550ac2998d4b0bd86bfed477a0ae4c7c71359" +dependencies = [ + "const-random-macro", +] + +[[package]] +name = "const-random-macro" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" +dependencies = [ + "getrandom 0.2.14", + "once_cell", + "tiny-keccak", +] + [[package]] name = "const-str" version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3618cccc083bb987a415d85c02ca6c9994ea5b44731ec28b9ecf09658655fba9" +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "convert_case" version = "0.4.0" @@ -1568,7 +1712,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "lock_api", "once_cell", "parking_lot_core 0.9.10", @@ -1789,6 +1933,15 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "dlv-list" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "442039f5147480ba31067cb00ada1adae6892028e40e45fc5de7b7df6dcc1b5f" +dependencies = [ + "const-random", +] + [[package]] name = "dns-lookup" version = "1.0.8" @@ -1878,7 +2031,10 @@ dependencies = [ "anyhow", "async-trait", "c-kzg", + "clap", + "config", "env_logger", + "ethers", "ethers-contract", "ethers-core", "ethers-providers", @@ -1915,7 +2071,7 @@ dependencies = [ "tokio-stream", "tonic", "tonic-build", - "uuid", + "uuid 1.8.0", ] [[package]] @@ -1949,6 +2105,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" +[[package]] +name = "ena" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1" +dependencies = [ + "log", +] + [[package]] name = "encoding_rs" version = "0.8.34" @@ -2061,6 +2226,28 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes 0.8.4", + "ctr 0.9.2", + "digest 0.10.7", + "hex", + "hmac", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2", + "sha3", + "thiserror", + "uuid 0.8.2", +] + [[package]] name = "ethabi" version = "18.0.0" @@ -2120,6 +2307,34 @@ dependencies = [ "smallvec", ] +[[package]] +name = "ethers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-middleware", + "ethers-providers", + "ethers-signers", + "ethers-solc", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + [[package]] name = "ethers-contract" version = "2.0.14" @@ -2149,11 +2364,13 @@ dependencies = [ "const-hex", "dunce", "ethers-core", + "ethers-etherscan", "eyre", "prettyplease 0.2.19", "proc-macro2", "quote", "regex", + "reqwest", "serde", "serde_json", "syn 2.0.60", @@ -2207,6 +2424,49 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ethers-etherscan" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" +dependencies = [ + "chrono", + "ethers-core", + "reqwest", + "semver 1.0.22", + "serde", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-etherscan", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + [[package]] name = "ethers-providers" version = "2.0.14" @@ -2245,6 +2505,57 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "ethers-signers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-solc" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" +dependencies = [ + "cfg-if", + "const-hex", + "dirs", + "dunce", + "ethers-core", + "glob", + "home", + "md-5", + "num_cpus", + "once_cell", + "path-slash", + "rayon", + "regex", + "semver 1.0.22", + "serde", + "serde_json", + "solang-parser", + "svm-rs", + "thiserror", + "tiny-keccak", + "tokio", + "tracing", + "walkdir", + "yansi", +] + [[package]] name = "event-listener" version = "2.5.3" @@ -2331,9 +2642,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80" [[package]] name = "flate2" -version = "1.0.29" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4556222738635b7a3417ae6130d8f52201e45a0c4d1a907f0826383adb5f85e7" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", @@ -2354,6 +2665,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "fs2" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "funty" version = "2.0.0" @@ -2408,6 +2729,16 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.30" @@ -2633,9 +2964,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", @@ -2657,7 +2988,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8094feaf31ff591f651a2664fb9cfd92bba7a60ce3197265e9482ebe753c8f7" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -2814,7 +3145,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2 0.5.6", + "socket2 0.5.7", "tokio", "tower-service", "tracing", @@ -3139,7 +3470,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "serde", ] @@ -3168,7 +3499,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" dependencies = [ - "socket2 0.5.6", + "socket2 0.5.7", "widestring", "windows-sys 0.48.0", "winreg", @@ -3252,6 +3583,17 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "json5" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96b0db21af676c1ce64250b5f40f3ce2cf27e4e47cb91ed91eb6fe9350b430c1" +dependencies = [ + "pest", + "pest_derive", + "serde", +] + [[package]] name = "jsonrpsee" version = "0.20.3" @@ -3460,6 +3802,36 @@ dependencies = [ "sha3-asm", ] +[[package]] +name = "lalrpop" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" +dependencies = [ + "ascii-canvas", + "bit-set", + "ena", + "itertools 0.11.0", + "lalrpop-util", + "petgraph", + "regex", + "regex-syntax 0.8.3", + "string_cache", + "term", + "tiny-keccak", + "unicode-xid", + "walkdir", +] + +[[package]] +name = "lalrpop-util" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" +dependencies = [ + "regex-automata 0.4.6", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -3477,9 +3849,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.153" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] name = "libffi" @@ -3586,7 +3958,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc" dependencies = [ - "hashbrown 0.14.3", + "hashbrown 0.14.5", ] [[package]] @@ -3640,6 +4012,16 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" +[[package]] +name = "md-5" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +dependencies = [ + "cfg-if", + "digest 0.10.7", +] + [[package]] name = "memchr" version = "2.7.2" @@ -3804,6 +4186,12 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" +[[package]] +name = "new_debug_unreachable" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" + [[package]] name = "nibble_vec" version = "0.1.0" @@ -4062,6 +4450,16 @@ dependencies = [ "num-traits", ] +[[package]] +name = "ordered-multimap" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ed8acf08e98e744e5384c8bc63ceb0364e68a6854187221c18df61c4797690e" +dependencies = [ + "dlv-list", + "hashbrown 0.13.2", +] + [[package]] name = "overload" version = "0.1.1" @@ -4167,12 +4565,57 @@ dependencies = [ "windows-targets 0.52.5", ] +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "path-slash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac", + "password-hash", + "sha2", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac", +] + [[package]] name = "pem" version = "1.1.1" @@ -4199,6 +4642,40 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pest_derive" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.60", +] + +[[package]] +name = "pest_meta" +version = "2.7.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + [[package]] name = "petgraph" version = "0.6.4" @@ -4239,7 +4716,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", - "phf_shared", + "phf_shared 0.11.2", ] [[package]] @@ -4248,7 +4725,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ - "phf_shared", + "phf_shared 0.11.2", "rand 0.8.5", ] @@ -4259,12 +4736,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", - "phf_shared", + "phf_shared 0.11.2", "proc-macro2", "quote", "syn 2.0.60", ] +[[package]] +name = "phf_shared" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096" +dependencies = [ + "siphasher", +] + [[package]] name = "phf_shared" version = "0.11.2" @@ -4375,6 +4861,12 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" + [[package]] name = "pretty_assertions" version = "1.4.0" @@ -5440,7 +5932,7 @@ dependencies = [ "sucds", "thiserror", "tracing", - "zstd", + "zstd 0.13.1", ] [[package]] @@ -5646,7 +6138,7 @@ dependencies = [ "strum", "tempfile", "thiserror", - "zstd", + "zstd 0.13.1", ] [[package]] @@ -6070,7 +6562,7 @@ dependencies = [ "derive_more", "dyn-clone", "enumn", - "hashbrown 0.14.3", + "hashbrown 0.14.5", "hex", "once_cell", "serde", @@ -6158,9 +6650,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1c77081a55300e016cb86f2864415b7518741879db925b8d488a0ee0d2da6bf" +checksum = "b26f4c25a604fcb3a1bcd96dd6ba37c93840de95de8198d94c0d571a74a804d1" dependencies = [ "bytemuck", "byteorder", @@ -6175,6 +6667,18 @@ dependencies = [ "chrono", ] +[[package]] +name = "ron" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" +dependencies = [ + "base64 0.21.7", + "bitflags 2.5.0", + "serde", + "serde_derive", +] + [[package]] name = "route-recognizer" version = "0.3.1" @@ -6212,6 +6716,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" +[[package]] +name = "rust-ini" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e2a3bcec1f113553ef1c88aae6c020a369d03d55b58de9869a0908930385091" +dependencies = [ + "cfg-if", + "ordered-multimap", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -6334,6 +6848,15 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6518fc26bced4d53678a22d6e423e9d8716377def84545fe328236e3af070e7f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", +] + [[package]] name = "same-file" version = "1.0.6" @@ -6393,6 +6916,18 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac", + "pbkdf2 0.11.0", + "salsa20", + "sha2", +] + [[package]] name = "sct" version = "0.7.1" @@ -6581,11 +7116,11 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c85f8e96d1d6857f13768fcbd895fcb06225510022a2774ed8b5150581847b0" +checksum = "0ad483d2ab0149d5a5ebcd9972a3852711e0153d863bf5a5d0391d28883c4a20" dependencies = [ - "base64 0.22.0", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", @@ -6599,9 +7134,9 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.8.0" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8b3a576c4eb2924262d5951a3b737ccaf16c931e39a2810c36f9a7e25575557" +checksum = "65569b702f41443e8bc8bbb1c5779bd0450bbe723b56198980e80ec45780bce2" dependencies = [ "darling 0.20.8", "proc-macro2", @@ -6793,9 +7328,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", "windows-sys 0.52.0", @@ -6817,6 +7352,20 @@ dependencies = [ "sha-1", ] +[[package]] +name = "solang-parser" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" +dependencies = [ + "itertools 0.11.0", + "lalrpop", + "lalrpop-util", + "phf", + "thiserror", + "unicode-xid", +] + [[package]] name = "spin" version = "0.5.2" @@ -6857,6 +7406,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "string_cache" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b" +dependencies = [ + "new_debug_unreachable", + "once_cell", + "parking_lot 0.12.2", + "phf_shared 0.10.0", + "precomputed-hash", +] + [[package]] name = "strsim" version = "0.9.3" @@ -6926,6 +7488,26 @@ dependencies = [ "num-traits", ] +[[package]] +name = "svm-rs" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" +dependencies = [ + "dirs", + "fs2", + "hex", + "once_cell", + "reqwest", + "semver 1.0.22", + "serde", + "serde_json", + "sha2", + "thiserror", + "url", + "zip", +] + [[package]] name = "syn" version = "1.0.109" @@ -7016,6 +7598,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "term" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" +dependencies = [ + "dirs-next", + "rustversion", + "winapi", +] + [[package]] name = "termcolor" version = "1.4.1" @@ -7152,7 +7745,7 @@ dependencies = [ "parking_lot 0.12.2", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.6", + "socket2 0.5.7", "tokio-macros", "windows-sys 0.48.0", ] @@ -7391,7 +7984,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", - "uuid", + "uuid 1.8.0", ] [[package]] @@ -7775,6 +8368,16 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom 0.2.14", + "serde", +] + [[package]] name = "uuid" version = "1.8.0" @@ -8244,6 +8847,15 @@ dependencies = [ "xml-rs", ] +[[package]] +name = "yaml-rust" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +dependencies = [ + "linked-hash-map", +] + [[package]] name = "yansi" version = "0.5.1" @@ -8358,13 +8970,52 @@ dependencies = [ "syn 2.0.60", ] +[[package]] +name = "zip" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" +dependencies = [ + "aes 0.8.4", + "byteorder", + "bzip2", + "constant_time_eq", + "crc32fast", + "crossbeam-utils", + "flate2", + "hmac", + "pbkdf2 0.11.0", + "sha1", + "time", + "zstd 0.11.2+zstd.1.5.2", +] + +[[package]] +name = "zstd" +version = "0.11.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +dependencies = [ + "zstd-safe 5.0.2+zstd.1.5.2", +] + [[package]] name = "zstd" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d789b1514203a1120ad2429eae43a7bd32b90976a7bb8a05f7ec02fa88cc23a" dependencies = [ - "zstd-safe", + "zstd-safe 7.1.0", +] + +[[package]] +name = "zstd-safe" +version = "5.0.2+zstd.1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +dependencies = [ + "libc", + "zstd-sys", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index dbf74ea..2320493 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,12 @@ ethers = "2.0.14" # lazy_static once_cell = "1.8.0" +# command +clap = "4.4.8" + +# config +config = "0.14.0" + # Async futures = "0.3.26" tokio = { version = "1.28.2", features = ["full"] } diff --git a/configs/settlement.toml b/configs/settlement.toml new file mode 100644 index 0000000..8569b61 --- /dev/null +++ b/configs/settlement.toml @@ -0,0 +1,11 @@ +[ethereum_settlement_config] +provider_url = "http://localhost:8546" + +[ethereum_settlement_config.local_wallet] +private_key = "0x76af8cc59ecfabf983d423e2054b07c11212cabc532062da0bd8067c59cf4a40" +chain_id = 12345 + +[ethereum_settlement_config.l1_contracts_addr] +bridge = "0x732200433EE79cCBf5842F9b5aD8fda6BF569F01" +global_exit = "0xAC97e12d0Ae20B2E0BF94e8Bd5752494577fC799" +zkvm = "0x12bfb8B59144b96bE5E74ECbC9896667261c004A" \ No newline at end of file diff --git a/src/batchproposer/mod.rs b/src/batch_proposer/mod.rs similarity index 100% rename from src/batchproposer/mod.rs rename to src/batch_proposer/mod.rs diff --git a/src/cli.rs b/src/cli.rs index 8b13789..0f44f57 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1 +1,29 @@ +use crate::commands::{chain_info::ChainInfoCmd, config::ConfigCmd, run::RunCmd}; +use anyhow::{bail, Result}; +#[derive(clap::Parser, Debug, Clone)] +#[command(version, author, about)] +pub struct Cli { + #[command(subcommand)] + pub subcommand: Option, +} + +#[derive(clap::Subcommand, Debug, Clone)] +pub enum SubCommand { + Run(RunCmd), + ChainInfo(ChainInfoCmd), + Config(ConfigCmd), +} + +impl Cli { + pub async fn run(&self) -> Result<()> { + match &self.subcommand { + Some(SubCommand::Run(cmd)) => cmd.run().await, + Some(SubCommand::ChainInfo(cmd)) => cmd.run().await, + Some(SubCommand::Config(cmd)) => cmd.run().await, + None => { + bail!("No subcommand provided") + } + } + } +} diff --git a/src/commands/chain_info.rs b/src/commands/chain_info.rs new file mode 100644 index 0000000..83823bb --- /dev/null +++ b/src/commands/chain_info.rs @@ -0,0 +1,10 @@ +use anyhow::Result; + +#[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] +pub struct ChainInfoCmd {} + +impl ChainInfoCmd { + pub async fn run(&self) -> Result<()> { + unimplemented!("TODO: implement ChainInfoCmd::run()") + } +} diff --git a/src/commands/config.rs b/src/commands/config.rs new file mode 100644 index 0000000..258c6b7 --- /dev/null +++ b/src/commands/config.rs @@ -0,0 +1,11 @@ +use anyhow::Result; + +/// ConfigCmd used to write configuration to the stdout. +#[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] +pub struct ConfigCmd {} + +impl ConfigCmd { + pub async fn run(&self) -> Result<()> { + unimplemented!("TODO: implement ConfigCmd::run()") + } +} diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..6bd3f58 --- /dev/null +++ b/src/commands/mod.rs @@ -0,0 +1,3 @@ +pub(crate) mod chain_info; +pub(crate) mod config; +pub(crate) mod run; diff --git a/src/commands/run.rs b/src/commands/run.rs new file mode 100644 index 0000000..53726c2 --- /dev/null +++ b/src/commands/run.rs @@ -0,0 +1,144 @@ +use crate::config::env::GLOBAL_ENV; +use crate::custom_reth; +use crate::operator; +use crate::settlement::ethereum::EthereumSettlementConfig; +use crate::settlement::NetworkSpec; +use anyhow::Result; +use std::fmt; +use std::str::FromStr; +use tokio::select; +use tokio::signal::unix::{signal, SignalKind}; +use tokio::sync::mpsc; + +/// The `RunCmd` struct is a command that runs the eigen-zeth. +#[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] +pub struct RunCmd { + /// The log level of the node. Default is `debug`. Possible values are `Trace`, `debug`, `info`, `warn`, `error`. + #[arg( + long, + value_name = "LOG_LEVEL", + verbatim_doc_comment, + default_value_t = LogLevel::Debug, + value_parser = LogLevel::from_str + )] + pub log_level: LogLevel, + + #[arg( + long, + default_value_t = SettlementLayer::Ethereum, + verbatim_doc_comment + )] + pub settlement: SettlementLayer, + + #[arg( + long, + value_hint = clap::ValueHint::FilePath, + requires = "settlement", + default_value = "configs/settlement.toml" + )] + pub settlement_conf: Option, +} + +#[derive(Debug, Clone, Eq, PartialEq, clap::ValueEnum)] +pub enum LogLevel { + Trace, + Debug, + Info, + Warn, + Error, +} + +impl FromStr for LogLevel { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + match s.to_lowercase().as_str() { + "debug" => Ok(LogLevel::Debug), + "info" => Ok(LogLevel::Info), + "warn" => Ok(LogLevel::Warn), + "error" => Ok(LogLevel::Error), + "trace" => Ok(LogLevel::Trace), + _ => Err(anyhow::Error::msg("invalid log level")), + } + } +} + +impl fmt::Display for LogLevel { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + LogLevel::Debug => write!(f, "debug"), + LogLevel::Info => write!(f, "info"), + LogLevel::Warn => write!(f, "warn"), + LogLevel::Error => write!(f, "error"), + LogLevel::Trace => write!(f, "trace"), + } + } +} + +impl fmt::Display for SettlementLayer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SettlementLayer::Ethereum => write!(f, "ethereum"), + } + } +} + +#[derive(Debug, Clone, Eq, PartialEq, clap::ValueEnum)] +#[non_exhaustive] +pub enum SettlementLayer { + Ethereum, +} + +impl RunCmd { + pub async fn run(&self) -> Result<()> { + let settlement_spec = match self.settlement { + SettlementLayer::Ethereum => match &self.settlement_conf { + None => { + return Err(anyhow::anyhow!( + "Settlement configuration is required for Ethereum settlement layer" + )); + } + Some(settlement_conf_path) => NetworkSpec::Ethereum( + EthereumSettlementConfig::from_conf_path(&settlement_conf_path)?, + ), + }, + }; + + let mut op = operator::Operator::new( + &GLOBAL_ENV.db_path, + &GLOBAL_ENV.l1addr, + &GLOBAL_ENV.prover_addr, + settlement_spec, + ) + .unwrap(); + + let mut sigterm = signal(SignalKind::terminate()).unwrap(); + let mut sigint = signal(SignalKind::interrupt()).unwrap(); + + let (stop_tx, stop_rx) = mpsc::channel::<()>(1); + + tokio::spawn(async move { + #[allow(clippy::let_underscore_future)] + #[allow(clippy::never_loop)] + loop { + select! { + _ = sigterm.recv() => { + println!("Recieve SIGTERM"); + break; + } + _ = sigint.recv() => { + println!("Recieve SIGTERM"); + break; + } + }; + } + stop_tx.send(()).await.unwrap(); + }); + + // Launch the custom reth service + custom_reth::launch_custom_node().await?; + + // Run the operator + op.run(stop_rx).await + } +} diff --git a/src/config/env.rs b/src/config/env.rs new file mode 100644 index 0000000..c89e976 --- /dev/null +++ b/src/config/env.rs @@ -0,0 +1,35 @@ +//! This module contains the environment variables for the EigenZeth service + +use once_cell::sync::Lazy; +use std::string::ToString; + +/// EigenZethEnv is a struct that holds the environment variables +pub struct GlobalEnv { + pub db_path: String, + pub l1addr: String, + pub prover_addr: String, + pub curve_type: String, + pub host: String, + pub zeth_db_path: String, + pub chain_id: u64, + pub program_name: String, +} + +/// GLOBAL_ENV is a global variable that holds the environment variables, +/// it is lazy loaded and thread safe +pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { + db_path: std::env::var("ZETH_OPERATOR_DB").unwrap_or("/tmp/operator".to_string()), + l1addr: std::env::var("ZETH_L2_ADDR").unwrap_or("http://localhost:8546".to_string()), + prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), + curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), + host: std::env::var("HOST").unwrap_or("0.0.0.0:8182".to_string()), + zeth_db_path: std::env::var("ZETH_DB_PATH") + .unwrap_or("/home/terry/project/0xeigen/local-reth-data/tmp/chain".to_string()), + chain_id: std::env::var("CHAIN_ID") + .unwrap_or("12345".to_string()) + .parse::() + .unwrap(), + program_name: std::env::var("PROGRAM_NAME") + .unwrap_or("EVM".to_string()) + .to_lowercase(), +}); diff --git a/src/config/mod.rs b/src/config/mod.rs new file mode 100644 index 0000000..996fb53 --- /dev/null +++ b/src/config/mod.rs @@ -0,0 +1 @@ +pub(crate) mod env; diff --git a/src/custom_reth/mod.rs b/src/custom_reth/mod.rs new file mode 100644 index 0000000..3e30675 --- /dev/null +++ b/src/custom_reth/mod.rs @@ -0,0 +1,396 @@ +use reth_node_builder::{ + components::{ComponentsBuilder, PayloadServiceBuilder}, + node::NodeTypes, + BuilderContext, FullNodeTypes, Node, PayloadBuilderConfig, +}; +use reth_primitives::revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}; +use reth_primitives::ChainSpecBuilder; +use reth_primitives::{Address, ChainSpec, Header, Withdrawals, B256}; +use std::sync::Arc; + +use reth_basic_payload_builder::{ + BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, BuildArguments, BuildOutcome, + PayloadBuilder, PayloadConfig, +}; +use reth_blockchain_tree::noop::NoopBlockchainTree; +use reth_db::open_db_read_only; +use reth_node_api::{ + validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion, + EngineTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, +}; +use reth_node_core::rpc::builder::{ + RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, +}; +use reth_provider::test_utils::TestCanonStateSubscriptions; +use reth_provider::{ + providers::{BlockchainProvider, ProviderFactory}, + CanonStateSubscriptions, StateProviderFactory, +}; +use reth_tasks::{TaskManager, TokioTaskExecutor}; +use reth_transaction_pool::TransactionPool; + +use reth_node_ethereum::{ + node::{EthereumNetworkBuilder, EthereumPoolBuilder}, + EthEvmConfig, +}; +use reth_payload_builder::{ + error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, + PayloadBuilderService, +}; +use reth_rpc_types::{ + engine::{ + ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, + PayloadAttributes as EthPayloadAttributes, PayloadId, + }, + withdrawal::Withdrawal, + ExecutionPayloadV1, +}; +use reth_tracing::{RethTracer, Tracer}; +use serde::{Deserialize, Serialize}; +use std::convert::Infallible; +use thiserror::Error; + +use crate::config::env::GLOBAL_ENV; +use crate::rpc; +use anyhow::{anyhow, Result}; + +use crate::rpc::eigen::EigenRpcExtApiServer; + +/// A custom payload attributes type. +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] +pub struct CustomPayloadAttributes { + /// An inner payload type + #[serde(flatten)] + pub inner: EthPayloadAttributes, + /// A custom field + pub custom: u64, +} + +/// Custom error type used in payload attributes validation +#[derive(Debug, Error)] +pub enum CustomError { + #[error("Custom field is not zero")] + CustomFieldIsNotZero, +} + +impl PayloadAttributes for CustomPayloadAttributes { + fn timestamp(&self) -> u64 { + self.inner.timestamp() + } + + fn withdrawals(&self) -> Option<&Vec> { + self.inner.withdrawals() + } + + fn parent_beacon_block_root(&self) -> Option { + self.inner.parent_beacon_block_root() + } + + fn ensure_well_formed_attributes( + &self, + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + ) -> Result<(), AttributesValidationError> { + validate_version_specific_fields(chain_spec, version, self.into())?; + + // custom validation logic - ensure that the custom field is not zero + if self.custom == 0 { + return Err(AttributesValidationError::invalid_params( + CustomError::CustomFieldIsNotZero, + )); + } + + Ok(()) + } +} + +/// New type around the payload builder attributes type +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct CustomPayloadBuilderAttributes(EthPayloadBuilderAttributes); + +impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes { + type RpcPayloadAttributes = CustomPayloadAttributes; + type Error = Infallible; + + fn try_new(parent: B256, attributes: CustomPayloadAttributes) -> Result { + Ok(Self(EthPayloadBuilderAttributes::new( + parent, + attributes.inner, + ))) + } + + fn payload_id(&self) -> PayloadId { + self.0.id + } + + fn parent(&self) -> B256 { + self.0.parent + } + + fn timestamp(&self) -> u64 { + self.0.timestamp + } + + fn parent_beacon_block_root(&self) -> Option { + self.0.parent_beacon_block_root + } + + fn suggested_fee_recipient(&self) -> Address { + self.0.suggested_fee_recipient + } + + fn prev_randao(&self) -> B256 { + self.0.prev_randao + } + + fn withdrawals(&self) -> &Withdrawals { + &self.0.withdrawals + } + + fn cfg_and_block_env( + &self, + chain_spec: &ChainSpec, + parent: &Header, + ) -> (CfgEnvWithHandlerCfg, BlockEnv) { + self.0.cfg_and_block_env(chain_spec, parent) + } +} + +/// Custom engine types - uses a custom payload attributes RPC type, but uses the default +/// payload builder attributes type. +#[derive(Clone, Debug, Default, Deserialize, Serialize)] +#[non_exhaustive] +pub struct CustomEngineTypes; + +impl EngineTypes for CustomEngineTypes { + type PayloadAttributes = CustomPayloadAttributes; + type PayloadBuilderAttributes = CustomPayloadBuilderAttributes; + type BuiltPayload = EthBuiltPayload; + type ExecutionPayloadV1 = ExecutionPayloadV1; + type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; + type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3; + + fn validate_version_specific_fields( + chain_spec: &ChainSpec, + version: EngineApiMessageVersion, + payload_or_attrs: PayloadOrAttributes<'_, CustomPayloadAttributes>, + ) -> Result<(), AttributesValidationError> { + validate_version_specific_fields(chain_spec, version, payload_or_attrs) + } +} + +#[derive(Debug, Clone, Default)] +#[non_exhaustive] +struct MyCustomNode; + +/// Configure the node types +impl NodeTypes for MyCustomNode { + type Primitives = (); + // use the custom engine types + type Engine = CustomEngineTypes; + // use the default ethereum EVM config + type Evm = EthEvmConfig; + + fn evm_config(&self) -> Self::Evm { + Self::Evm::default() + } +} + +/// Implement the Node trait for the custom node +/// +/// This provides a preset configuration for the node +impl Node for MyCustomNode +where + N: FullNodeTypes, +{ + type PoolBuilder = EthereumPoolBuilder; + type NetworkBuilder = EthereumNetworkBuilder; + type PayloadBuilder = CustomPayloadServiceBuilder; + + fn components( + self, + ) -> ComponentsBuilder { + ComponentsBuilder::default() + .node_types::() + .pool(EthereumPoolBuilder::default()) + .payload(CustomPayloadServiceBuilder::default()) + .network(EthereumNetworkBuilder::default()) + } +} + +/// A custom payload service builder that supports the custom engine types +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct CustomPayloadServiceBuilder; + +impl PayloadServiceBuilder for CustomPayloadServiceBuilder +where + Node: FullNodeTypes, + Pool: TransactionPool + Unpin + 'static, +{ + async fn spawn_payload_service( + self, + ctx: &BuilderContext, + pool: Pool, + ) -> eyre::Result> { + let payload_builder = CustomPayloadBuilder::default(); + let conf = ctx.payload_builder_config(); + + let payload_job_config = BasicPayloadJobGeneratorConfig::default() + .interval(conf.interval()) + .deadline(conf.deadline()) + .max_payload_tasks(conf.max_payload_tasks()) + .extradata(conf.extradata_rlp_bytes()) + .max_gas_limit(conf.max_gas_limit()); + + let payload_generator = BasicPayloadJobGenerator::with_builder( + ctx.provider().clone(), + pool, + ctx.task_executor().clone(), + payload_job_config, + ctx.chain_spec(), + payload_builder, + ); + let (payload_service, payload_builder) = + PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); + + ctx.task_executor() + .spawn_critical("payload builder service", Box::pin(payload_service)); + + Ok(payload_builder) + } +} + +/// The type responsible for building custom payloads +#[derive(Debug, Default, Clone)] +#[non_exhaustive] +pub struct CustomPayloadBuilder; + +impl PayloadBuilder for CustomPayloadBuilder +where + Client: StateProviderFactory, + Pool: TransactionPool, +{ + type Attributes = CustomPayloadBuilderAttributes; + type BuiltPayload = EthBuiltPayload; + + fn try_build( + &self, + args: BuildArguments, + ) -> Result, PayloadBuilderError> { + let BuildArguments { + client, + pool, + cached_reads, + config, + cancel, + best_payload, + } = args; + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + extra_data, + attributes, + chain_spec, + } = config; + + // This reuses the default EthereumPayloadBuilder to build the payload + // but any custom logic can be implemented here + reth_ethereum_payload_builder::EthereumPayloadBuilder::default().try_build(BuildArguments { + client, + pool, + cached_reads, + config: PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + extra_data, + attributes: attributes.0, + chain_spec, + }, + cancel, + best_payload, + }) + } + + fn build_empty_payload( + client: &Client, + config: PayloadConfig, + ) -> Result { + let PayloadConfig { + initialized_block_env, + initialized_cfg, + parent_block, + extra_data, + attributes, + chain_spec, + } = config; + > ::build_empty_payload( + client, + PayloadConfig { initialized_block_env, initialized_cfg, parent_block, extra_data, attributes: attributes.0, chain_spec } + ) + } +} + +// TODO: Refactor this +pub async fn launch_custom_node() -> Result<()> { + let _guard = RethTracer::new().init().map_err(|e| anyhow!(e))?; + + let _tasks = TaskManager::current(); + + // create optimism genesis with canyon at block 2 + //let spec = ChainSpec::builder() + // .chain(Chain::mainnet()) + // .genesis(Genesis::default()) + // .london_activated() + // .paris_activated() + // .shanghai_activated() + // .build(); + let spec = Arc::new(ChainSpecBuilder::mainnet().build()); + + // let db_path =; + let db_path = std::path::Path::new(&GLOBAL_ENV.zeth_db_path); + let db = Arc::new( + open_db_read_only(db_path.join("db").as_path(), Default::default()) + .map_err(|e| anyhow!(e))?, + ); + let factory = ProviderFactory::new(db.clone(), spec.clone(), db_path.join("static_files"))?; + let provider = BlockchainProvider::new(factory, NoopBlockchainTree::default())?; + let rpc_builder = RpcModuleBuilder::default() + .with_provider(provider.clone()) + // Rest is just noops that do nothing + .with_noop_pool() + .with_noop_network() + .with_executor(TokioTaskExecutor::default()) + .with_evm_config(EthEvmConfig::default()) + .with_events(TestCanonStateSubscriptions::default()); + let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); + let mut server = rpc_builder.build(config); + let custom_rpc = rpc::eigen::EigenRpcExt { provider }; + server.merge_configured(custom_rpc.into_rpc())?; + + // Start the server & keep it alive + let server_args = + RpcServerConfig::http(Default::default()).with_http_address(GLOBAL_ENV.host.parse()?); + println!("Node started"); + let _handle = server_args.start(server).await?; + + // futures::future::pending::<()>().await; + + /* + // create node config + let node_config = NodeConfig::test() + .with_rpc(RpcServerArgs::default().with_http()) + .with_chain(spec); + + let handle = NodeBuilder::new(node_config) + .testing_node(tasks.executor()) + .launch_node(MyCustomNode::default()) + .await + .unwrap(); + handle.node_exit_future.await + */ + + Ok(()) +} diff --git a/src/da/ethereum/mod.rs b/src/da/ethereum/mod.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/da/ethereum/mod.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/da/mod.rs b/src/da/mod.rs deleted file mode 100644 index da0f00a..0000000 --- a/src/da/mod.rs +++ /dev/null @@ -1,5 +0,0 @@ -//! This is a module that contains the data availability logic for the Eigen network. -//! including the following data availability api: -//! 1. submit: submits the batch data to Data Availability layer. - -pub(crate) mod ethereum; diff --git a/src/env.rs b/src/env.rs deleted file mode 100644 index f11850e..0000000 --- a/src/env.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! This module contains the environment variables for the EigenZeth service - -use once_cell::sync::Lazy; -use std::string::ToString; - -/// EigenZethEnv is a struct that holds the environment variables -pub struct GlobalEnv { - pub db_path: String, - pub l1addr: String, - pub prover_addr: String, - pub curve_type: String, - pub host: String, - pub zeth_db_path: String, - pub chain_id: u64, - pub program_name: String, - pub settlement: SettlementEnv, -} - -#[derive(Clone)] -pub struct SettlementEnv { - pub eth_env: EthereumEnv, -} - -#[derive(Clone)] -pub struct EthereumEnv { - pub provider_url: String, - pub local_wallet: LocalWalletConfig, - pub l1_contracts_addr: EthContractsAddr, -} - -#[derive(Clone)] -pub struct LocalWalletConfig { - pub private_key: String, - pub chain_id: u64, -} - -// TODO: Fixme -#[allow(dead_code)] -#[derive(Clone)] -pub struct EthContractsAddr { - pub bridge: String, - pub global_exit: String, - pub zkvm: String, -} - -/// GLOBAL_ENV is a global variable that holds the environment variables, -/// it is lazy loaded and thread safe -pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { - db_path: std::env::var("ZETH_OPERATOR_DB").unwrap_or("/tmp/operator".to_string()), - l1addr: std::env::var("ZETH_L2_ADDR").unwrap_or("http://localhost:8546".to_string()), - prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), - curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), - host: std::env::var("HOST").unwrap_or("0.0.0.0:8182".to_string()), - zeth_db_path: std::env::var("ZETH_DB_PATH").unwrap_or("/tmp/chain".to_string()), - chain_id: std::env::var("CHAIN_ID") - .unwrap_or("12345".to_string()) - .parse::() - .unwrap(), - program_name: std::env::var("PROGRAM_NAME") - .unwrap_or("EVM".to_string()) - .to_lowercase(), - // TODO: too many env variables, I will move this to a config file,and use clap command to receive the path to the config file - settlement: SettlementEnv { - eth_env: EthereumEnv { - provider_url: std::env::var("ETH_PROVIDER_URL") - .unwrap_or("http://localhost:8546".to_string()), - local_wallet: LocalWalletConfig { - private_key: std::env::var("PRIVATE_KEY").unwrap_or("".to_string()), - chain_id: std::env::var("CHAIN_ID") - .unwrap_or("12345".to_string()) - .parse() - .unwrap(), - }, - l1_contracts_addr: EthContractsAddr { - bridge: std::env::var("ZETH_BRIDGE_CONTRACT_ADDR").unwrap_or("0x".to_string()), - global_exit: std::env::var("ZETH_GLOBAL_EXIT_CONTRACT_ADDR") - .unwrap_or("0x".to_string()), - zkvm: std::env::var("ZETH_ZKVM_CONTRACT_ADDR").unwrap_or("0x".to_string()), - }, - }, - }, -}); diff --git a/src/main.rs b/src/main.rs index 3894b23..a5b624b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,442 +1,20 @@ -use reth_node_builder::{ - components::{ComponentsBuilder, PayloadServiceBuilder}, - node::NodeTypes, - BuilderContext, FullNodeTypes, Node, PayloadBuilderConfig, -}; -use reth_primitives::revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg}; -use reth_primitives::ChainSpecBuilder; -use reth_primitives::{Address, ChainSpec, Header, Withdrawals, B256}; -use std::sync::Arc; - -use reth_basic_payload_builder::{ - BasicPayloadJobGenerator, BasicPayloadJobGeneratorConfig, BuildArguments, BuildOutcome, - PayloadBuilder, PayloadConfig, -}; -use reth_blockchain_tree::noop::NoopBlockchainTree; -use reth_db::open_db_read_only; -use reth_node_api::{ - validate_version_specific_fields, AttributesValidationError, EngineApiMessageVersion, - EngineTypes, PayloadAttributes, PayloadBuilderAttributes, PayloadOrAttributes, -}; -use reth_node_core::rpc::builder::{ - RethRpcModule, RpcModuleBuilder, RpcServerConfig, TransportRpcModuleConfig, -}; -use reth_provider::test_utils::TestCanonStateSubscriptions; -use reth_provider::{ - providers::{BlockchainProvider, ProviderFactory}, - CanonStateSubscriptions, StateProviderFactory, -}; -use reth_tasks::{TaskManager, TokioTaskExecutor}; -use reth_transaction_pool::TransactionPool; - -use reth_node_ethereum::{ - node::{EthereumNetworkBuilder, EthereumPoolBuilder}, - EthEvmConfig, -}; -use reth_payload_builder::{ - error::PayloadBuilderError, EthBuiltPayload, EthPayloadBuilderAttributes, PayloadBuilderHandle, - PayloadBuilderService, -}; -use reth_rpc_types::{ - engine::{ - ExecutionPayloadEnvelopeV2, ExecutionPayloadEnvelopeV3, - PayloadAttributes as EthPayloadAttributes, PayloadId, - }, - withdrawal::Withdrawal, - ExecutionPayloadV1, -}; -use reth_tracing::{RethTracer, Tracer}; -use serde::{Deserialize, Serialize}; -use std::convert::Infallible; -use thiserror::Error; - -mod prover; -mod rpc; -mod settlement; +use anyhow::Result; +use clap::Parser; +mod batch_proposer; mod cli; -mod da; +mod commands; +mod config; +mod custom_reth; mod db; mod operator; - -mod batchproposer; -mod env; - -use crate::rpc::eigen::EigenRpcExtApiServer; - -use crate::env::GLOBAL_ENV; -use tokio::select; -use tokio::signal::unix::signal; -use tokio::signal::unix::SignalKind; -use tokio::sync::mpsc; - -/// A custom payload attributes type. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct CustomPayloadAttributes { - /// An inner payload type - #[serde(flatten)] - pub inner: EthPayloadAttributes, - /// A custom field - pub custom: u64, -} - -/// Custom error type used in payload attributes validation -#[derive(Debug, Error)] -pub enum CustomError { - #[error("Custom field is not zero")] - CustomFieldIsNotZero, -} - -impl PayloadAttributes for CustomPayloadAttributes { - fn timestamp(&self) -> u64 { - self.inner.timestamp() - } - - fn withdrawals(&self) -> Option<&Vec> { - self.inner.withdrawals() - } - - fn parent_beacon_block_root(&self) -> Option { - self.inner.parent_beacon_block_root() - } - - fn ensure_well_formed_attributes( - &self, - chain_spec: &ChainSpec, - version: EngineApiMessageVersion, - ) -> Result<(), AttributesValidationError> { - validate_version_specific_fields(chain_spec, version, self.into())?; - - // custom validation logic - ensure that the custom field is not zero - if self.custom == 0 { - return Err(AttributesValidationError::invalid_params( - CustomError::CustomFieldIsNotZero, - )); - } - - Ok(()) - } -} - -/// New type around the payload builder attributes type -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct CustomPayloadBuilderAttributes(EthPayloadBuilderAttributes); - -impl PayloadBuilderAttributes for CustomPayloadBuilderAttributes { - type RpcPayloadAttributes = CustomPayloadAttributes; - type Error = Infallible; - - fn try_new(parent: B256, attributes: CustomPayloadAttributes) -> Result { - Ok(Self(EthPayloadBuilderAttributes::new( - parent, - attributes.inner, - ))) - } - - fn payload_id(&self) -> PayloadId { - self.0.id - } - - fn parent(&self) -> B256 { - self.0.parent - } - - fn timestamp(&self) -> u64 { - self.0.timestamp - } - - fn parent_beacon_block_root(&self) -> Option { - self.0.parent_beacon_block_root - } - - fn suggested_fee_recipient(&self) -> Address { - self.0.suggested_fee_recipient - } - - fn prev_randao(&self) -> B256 { - self.0.prev_randao - } - - fn withdrawals(&self) -> &Withdrawals { - &self.0.withdrawals - } - - fn cfg_and_block_env( - &self, - chain_spec: &ChainSpec, - parent: &Header, - ) -> (CfgEnvWithHandlerCfg, BlockEnv) { - self.0.cfg_and_block_env(chain_spec, parent) - } -} - -/// Custom engine types - uses a custom payload attributes RPC type, but uses the default -/// payload builder attributes type. -#[derive(Clone, Debug, Default, Deserialize, Serialize)] -#[non_exhaustive] -pub struct CustomEngineTypes; - -impl EngineTypes for CustomEngineTypes { - type PayloadAttributes = CustomPayloadAttributes; - type PayloadBuilderAttributes = CustomPayloadBuilderAttributes; - type BuiltPayload = EthBuiltPayload; - type ExecutionPayloadV1 = ExecutionPayloadV1; - type ExecutionPayloadV2 = ExecutionPayloadEnvelopeV2; - type ExecutionPayloadV3 = ExecutionPayloadEnvelopeV3; - - fn validate_version_specific_fields( - chain_spec: &ChainSpec, - version: EngineApiMessageVersion, - payload_or_attrs: PayloadOrAttributes<'_, CustomPayloadAttributes>, - ) -> Result<(), AttributesValidationError> { - validate_version_specific_fields(chain_spec, version, payload_or_attrs) - } -} - -#[derive(Debug, Clone, Default)] -#[non_exhaustive] -struct MyCustomNode; - -/// Configure the node types -impl NodeTypes for MyCustomNode { - type Primitives = (); - // use the custom engine types - type Engine = CustomEngineTypes; - // use the default ethereum EVM config - type Evm = EthEvmConfig; - - fn evm_config(&self) -> Self::Evm { - Self::Evm::default() - } -} - -/// Implement the Node trait for the custom node -/// -/// This provides a preset configuration for the node -impl Node for MyCustomNode -where - N: FullNodeTypes, -{ - type PoolBuilder = EthereumPoolBuilder; - type NetworkBuilder = EthereumNetworkBuilder; - type PayloadBuilder = CustomPayloadServiceBuilder; - - fn components( - self, - ) -> ComponentsBuilder { - ComponentsBuilder::default() - .node_types::() - .pool(EthereumPoolBuilder::default()) - .payload(CustomPayloadServiceBuilder::default()) - .network(EthereumNetworkBuilder::default()) - } -} - -/// A custom payload service builder that supports the custom engine types -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct CustomPayloadServiceBuilder; - -impl PayloadServiceBuilder for CustomPayloadServiceBuilder -where - Node: FullNodeTypes, - Pool: TransactionPool + Unpin + 'static, -{ - async fn spawn_payload_service( - self, - ctx: &BuilderContext, - pool: Pool, - ) -> eyre::Result> { - let payload_builder = CustomPayloadBuilder::default(); - let conf = ctx.payload_builder_config(); - - let payload_job_config = BasicPayloadJobGeneratorConfig::default() - .interval(conf.interval()) - .deadline(conf.deadline()) - .max_payload_tasks(conf.max_payload_tasks()) - .extradata(conf.extradata_rlp_bytes()) - .max_gas_limit(conf.max_gas_limit()); - - let payload_generator = BasicPayloadJobGenerator::with_builder( - ctx.provider().clone(), - pool, - ctx.task_executor().clone(), - payload_job_config, - ctx.chain_spec(), - payload_builder, - ); - let (payload_service, payload_builder) = - PayloadBuilderService::new(payload_generator, ctx.provider().canonical_state_stream()); - - ctx.task_executor() - .spawn_critical("payload builder service", Box::pin(payload_service)); - - Ok(payload_builder) - } -} - -/// The type responsible for building custom payloads -#[derive(Debug, Default, Clone)] -#[non_exhaustive] -pub struct CustomPayloadBuilder; - -impl PayloadBuilder for CustomPayloadBuilder -where - Client: StateProviderFactory, - Pool: TransactionPool, -{ - type Attributes = CustomPayloadBuilderAttributes; - type BuiltPayload = EthBuiltPayload; - - fn try_build( - &self, - args: BuildArguments, - ) -> Result, PayloadBuilderError> { - let BuildArguments { - client, - pool, - cached_reads, - config, - cancel, - best_payload, - } = args; - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes, - chain_spec, - } = config; - - // This reuses the default EthereumPayloadBuilder to build the payload - // but any custom logic can be implemented here - reth_ethereum_payload_builder::EthereumPayloadBuilder::default().try_build(BuildArguments { - client, - pool, - cached_reads, - config: PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes: attributes.0, - chain_spec, - }, - cancel, - best_payload, - }) - } - - fn build_empty_payload( - client: &Client, - config: PayloadConfig, - ) -> Result { - let PayloadConfig { - initialized_block_env, - initialized_cfg, - parent_block, - extra_data, - attributes, - chain_spec, - } = config; - > ::build_empty_payload( - client, - PayloadConfig { initialized_block_env, initialized_cfg, parent_block, extra_data, attributes: attributes.0, chain_spec } - ) - } -} +mod prover; +mod rpc; +mod settlement; #[tokio::main] -async fn main() -> eyre::Result<()> { +async fn main() -> Result<()> { + std::env::set_var("RUST_LOG", "debug"); env_logger::init(); - - let mut op = operator::Operator::new( - &GLOBAL_ENV.db_path, - &GLOBAL_ENV.l1addr, - &GLOBAL_ENV.prover_addr, - ); - - let mut sigterm = signal(SignalKind::terminate()).unwrap(); - let mut sigint = signal(SignalKind::interrupt()).unwrap(); - - let (stop_tx, stop_rx) = mpsc::channel::<()>(1); - - tokio::spawn(async move { - #[allow(clippy::let_underscore_future)] - #[allow(clippy::never_loop)] - loop { - select! { - _ = sigterm.recv() => { - println!("Recieve SIGTERM"); - break; - } - _ = sigint.recv() => { - println!("Recieve SIGTERM"); - break; - } - }; - } - stop_tx.send(()).await.unwrap(); - }); - - let _guard = RethTracer::new().init()?; - - let _tasks = TaskManager::current(); - - // create optimism genesis with canyon at block 2 - //let spec = ChainSpec::builder() - // .chain(Chain::mainnet()) - // .genesis(Genesis::default()) - // .london_activated() - // .paris_activated() - // .shanghai_activated() - // .build(); - let spec = Arc::new(ChainSpecBuilder::mainnet().build()); - - // let db_path =; - let db_path = std::path::Path::new(&GLOBAL_ENV.zeth_db_path); - let db = Arc::new(open_db_read_only( - db_path.join("db").as_path(), - Default::default(), - )?); - let factory = ProviderFactory::new(db.clone(), spec.clone(), db_path.join("static_files"))?; - let provider = BlockchainProvider::new(factory, NoopBlockchainTree::default())?; - let rpc_builder = RpcModuleBuilder::default() - .with_provider(provider.clone()) - // Rest is just noops that do nothing - .with_noop_pool() - .with_noop_network() - .with_executor(TokioTaskExecutor::default()) - .with_evm_config(EthEvmConfig::default()) - .with_events(TestCanonStateSubscriptions::default()); - let config = TransportRpcModuleConfig::default().with_http([RethRpcModule::Eth]); - let mut server = rpc_builder.build(config); - let custom_rpc = rpc::eigen::EigenRpcExt { provider }; - server.merge_configured(custom_rpc.into_rpc())?; - - // Start the server & keep it alive - let server_args = - RpcServerConfig::http(Default::default()).with_http_address(GLOBAL_ENV.host.parse()?); - println!("Node started"); - let _handle = server_args.start(server).await?; - - // futures::future::pending::<()>().await; - - op.run(stop_rx).await; - Ok(()) - - /* - // create node config - let node_config = NodeConfig::test() - .with_rpc(RpcServerArgs::default().with_http()) - .with_chain(spec); - - let handle = NodeBuilder::new(node_config) - .testing_node(tasks.executor()) - .launch_node(MyCustomNode::default()) - .await - .unwrap(); - handle.node_exit_future.await - */ + cli::Cli::parse().run().await } diff --git a/src/operator.rs b/src/operator.rs index 9cd0ad0..c5efe74 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -6,14 +6,15 @@ use crate::prover::ProverChannel; use crate::settlement::{init_settlement, NetworkSpec, Settlement}; +use anyhow::{anyhow, Result}; use ethers_core::types::{Bytes, H160, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; use tokio::sync::mpsc::{self, Receiver}; use tokio::time::{interval, Duration}; +use crate::config::env::GLOBAL_ENV; use crate::db::{lfs, Database}; -use crate::env::GLOBAL_ENV; use crate::settlement::ethereum::{EthereumSettlement, EthereumSettlementConfig}; pub(crate) struct Operator { @@ -24,24 +25,32 @@ pub(crate) struct Operator { } impl Operator { - pub fn new(_db_path: &str, _l1addr: &str, prover_addr: &str) -> Self { + pub fn new( + db_path: &str, + _l1addr: &str, + prover_addr: &str, + settlement_spec: NetworkSpec, + ) -> Result { let (sx, rx_proof) = mpsc::channel(10); let prover = ProverChannel::new(prover_addr, sx); - let db = lfs::open_db(lfs::DBConfig::Memory).unwrap(); + let db = lfs::open_db(lfs::DBConfig::Mdbx { + path: db_path.to_string(), + max_dbs: 10, + }) + .map_err(|e| anyhow!("Failed to open db: {:?}", e))?; - let settler = init_settlement(NetworkSpec::Ethereum(EthereumSettlementConfig { - eth_settlement_env: GLOBAL_ENV.settlement.eth_env.clone(), - })); - // let settler = EthereumSettlement {}; - Operator { + let settler = init_settlement(settlement_spec) + .map_err(|e| anyhow!("Failed to init settlement: {:?}", e))?; + + Ok(Operator { prover, db, settler, rx_proof, - } + }) } - pub async fn run(&mut self, mut stop_channel: Receiver<()>) { + pub async fn run(&mut self, mut stop_channel: Receiver<()>) -> Result<()> { let mut ticker = interval(Duration::from_millis(1000)); let batch_key = "next_batch".to_string().as_bytes().to_vec(); let proof_key = "batch_proof".to_string().as_bytes().to_vec(); diff --git a/src/prover/provider.rs b/src/prover/provider.rs index a523d9b..f07f1ef 100644 --- a/src/prover/provider.rs +++ b/src/prover/provider.rs @@ -7,7 +7,7 @@ // TODO: Fix me #![allow(dead_code)] -use crate::env::GLOBAL_ENV; +use crate::config::env::GLOBAL_ENV; use crate::prover::provider::prover_service::prover_request::RequestType; use crate::prover::provider::prover_service::prover_response::ResponseType; use crate::prover::provider::prover_service::prover_service_client::ProverServiceClient; @@ -15,6 +15,7 @@ use crate::prover::provider::prover_service::{ Batch, GenAggregatedProofRequest, GenBatchProofRequest, GenFinalProofRequest, ProofResultCode, ProverRequest, }; +use anyhow::{anyhow, Result}; use prost::Message; use std::fmt; use std::time::Duration; @@ -97,7 +98,7 @@ impl ProverChannel { } } - pub async fn start(&mut self) -> Result<(), Box> { + pub async fn start(&mut self) -> Result<()> { // start the endpoint // self.endpoint.launch().await; @@ -119,14 +120,16 @@ impl ProverChannel { Ok(()) } - pub async fn stop(&mut self) -> Result<(), Box> { + pub async fn stop(&mut self) -> Result<()> { // stop the endpoint - self.stop_endpoint_tx.send(()).await?; - - Ok(()) + Ok(self + .stop_endpoint_tx + .send(()) + .await + .map_err(|e| anyhow!("Failed to stop the endpoint: {:?}", e))?) } - pub async fn execute(&mut self, batch: BlockNumber) -> Result<(), Box> { + pub async fn execute(&mut self, batch: BlockNumber) -> Result<()> { log::debug!("execute batch {batch}"); self.set_current_batch(batch)?; @@ -138,7 +141,7 @@ impl ProverChannel { Ok(()) } - async fn entry_step(&mut self) -> Result<(), Box> { + async fn entry_step(&mut self) -> Result<()> { loop { self.step = match &self.step { ProveStep::Start => { @@ -263,14 +266,14 @@ impl ProverChannel { } } - fn set_current_batch(&mut self, batch: BlockNumber) -> Result<(), Box> { + fn set_current_batch(&mut self, batch: BlockNumber) -> Result<()> { self.step = ProveStep::Start; self.parent_batch.clone_from(&self.current_batch); self.current_batch = Some(batch); Ok(()) } - fn clean_current_batch(&mut self) -> Result<(), Box> { + fn clean_current_batch(&mut self) -> Result<()> { self.parent_batch.clone_from(&self.current_batch); self.current_batch = None; Ok(()) @@ -318,13 +321,13 @@ impl ProverEndpoint { // pub async fn send_request( // &mut self, // request: ProverRequest, - // ) -> Result<(), Box> { + // ) -> Result<()> { // self.request_sender.send(request).await?; // Ok(()) // } /// launch the endpoint - pub async fn launch(&mut self) -> Result<(), Box> { + pub async fn launch(&mut self) -> Result<()> { let mut client = ProverServiceClient::connect(self.addr.clone()).await?; log::info!("ProverEndpoint connected to {}", self.addr); @@ -371,7 +374,7 @@ impl ProverEndpoint { } // stop the endpoint - // pub async fn stop(&mut self) -> Result<(), Box> { + // pub async fn stop(&mut self) -> Result<()> { // self.stop_endpoint_tx.send(()).await?; // Ok(()) // } diff --git a/src/settlement/ethereum/mod.rs b/src/settlement/ethereum/mod.rs index 595bdf7..f5f10ad 100644 --- a/src/settlement/ethereum/mod.rs +++ b/src/settlement/ethereum/mod.rs @@ -1,48 +1,100 @@ use crate::settlement::Settlement; +use std::path::Path; pub(crate) mod interfaces; -use crate::env::EthereumEnv; use crate::settlement::ethereum::interfaces::bridge::BridgeContractClient; use crate::settlement::ethereum::interfaces::global_exit_root::GlobalExitRootContractClient; -use anyhow::Result; +use anyhow::{anyhow, Result}; use async_trait::async_trait; +use config::{Config, File}; use ethers::signers::{LocalWallet, Signer}; use ethers_core::k256::elliptic_curve::SecretKey; use ethers_core::types::{Address, Bytes, U256}; use ethers_core::utils::hex; use ethers_providers::{Http, Provider}; +use serde::Deserialize; pub struct EthereumSettlement { pub bridge_client: BridgeContractClient, pub global_exit_root_client: GlobalExitRootContractClient, } +#[derive(Debug, Deserialize)] pub struct EthereumSettlementConfig { - pub eth_settlement_env: EthereumEnv, + pub provider_url: String, + pub local_wallet: LocalWalletConfig, + pub l1_contracts_addr: EthContractsAddr, +} + +#[derive(Debug, Deserialize)] +pub struct LocalWalletConfig { + pub private_key: String, + pub chain_id: u64, +} + +#[derive(Debug, Deserialize)] +pub struct EthContractsAddr { + pub bridge: String, + pub global_exit: String, + pub zkvm: String, +} + +impl EthereumSettlementConfig { + pub fn from_conf_path(conf_path: &str) -> Result { + log::info!("Load the Ethereum settlement config from: {}", conf_path); + + let config = Config::builder() + .add_source(File::from(Path::new(conf_path))) + .build() + .map_err(|e| anyhow!("Failed to build config: {:?}", e))?; + + config + .get("ethereum_settlement_config") + .map_err(|e| anyhow!("Failed to parse EthereumSettlementConfig: {:?}", e)) + } } impl EthereumSettlement { - pub fn new(config: EthereumSettlementConfig) -> Self { - let provider = Provider::::try_from(&config.eth_settlement_env.provider_url).unwrap(); - let kye_bytes = hex::decode(&config.eth_settlement_env.local_wallet.private_key).unwrap(); - let secret_key = SecretKey::from_slice(&kye_bytes).unwrap(); - let local_wallet: LocalWallet = LocalWallet::from(secret_key) - .with_chain_id(config.eth_settlement_env.local_wallet.chain_id); - - let bridge_address: Address = config - .eth_settlement_env - .l1_contracts_addr - .bridge - .parse() - .unwrap(); - - let global_exit_root_address: Address = config - .eth_settlement_env - .l1_contracts_addr - .global_exit - .parse() - .unwrap(); - - EthereumSettlement { + pub fn new(config: EthereumSettlementConfig) -> Result { + let provider = Provider::::try_from(&config.provider_url).map_err(|e| { + anyhow!( + "Failed to create provider from URL {}: {:?}", + config.provider_url, + e + ) + })?; + + let kye_bytes = hex::decode(&config.local_wallet.private_key).map_err(|e| { + anyhow!( + "Failed to decode private key {}: {:?}", + config.local_wallet.private_key, + e + ) + })?; + + let secret_key = SecretKey::from_slice(&kye_bytes) + .map_err(|e| anyhow!("Failed to parse secret key: {:?}", e))?; + + let local_wallet: LocalWallet = + LocalWallet::from(secret_key).with_chain_id(config.local_wallet.chain_id); + + let bridge_address: Address = config.l1_contracts_addr.bridge.parse().map_err(|e| { + anyhow!( + "Failed to parse bridge address {}: {:?}", + config.l1_contracts_addr.bridge, + e + ) + })?; + + let global_exit_root_address: Address = + config.l1_contracts_addr.global_exit.parse().map_err(|e| { + anyhow!( + "Failed to parse global exit root address {}: {:?}", + config.l1_contracts_addr.global_exit, + e + ) + })?; + + Ok(EthereumSettlement { bridge_client: BridgeContractClient::new( bridge_address, provider.clone(), @@ -53,7 +105,7 @@ impl EthereumSettlement { provider, local_wallet.clone(), ), - } + }) } } diff --git a/src/settlement/mod.rs b/src/settlement/mod.rs index 90ffa9e..953d152 100644 --- a/src/settlement/mod.rs +++ b/src/settlement/mod.rs @@ -76,9 +76,9 @@ pub enum NetworkSpec { Optimism, } -pub fn init_settlement(spec: NetworkSpec) -> Box { +pub fn init_settlement(spec: NetworkSpec) -> Result> { match spec { - NetworkSpec::Ethereum(config) => Box::new(ethereum::EthereumSettlement::new(config)), + NetworkSpec::Ethereum(config) => Ok(Box::new(ethereum::EthereumSettlement::new(config)?)), _ => todo!("Not supported network"), } } From 8510291a1357ff8c9f5570adf35a88849a62c02e Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Wed, 1 May 2024 11:35:48 +0800 Subject: [PATCH 08/12] fix: fix lint --- src/commands/run.rs | 2 +- src/prover/provider.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/commands/run.rs b/src/commands/run.rs index 53726c2..d53130c 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -99,7 +99,7 @@ impl RunCmd { )); } Some(settlement_conf_path) => NetworkSpec::Ethereum( - EthereumSettlementConfig::from_conf_path(&settlement_conf_path)?, + EthereumSettlementConfig::from_conf_path(settlement_conf_path)?, ), }, }; diff --git a/src/prover/provider.rs b/src/prover/provider.rs index f07f1ef..780f19f 100644 --- a/src/prover/provider.rs +++ b/src/prover/provider.rs @@ -122,11 +122,10 @@ impl ProverChannel { pub async fn stop(&mut self) -> Result<()> { // stop the endpoint - Ok(self - .stop_endpoint_tx + self.stop_endpoint_tx .send(()) .await - .map_err(|e| anyhow!("Failed to stop the endpoint: {:?}", e))?) + .map_err(|e| anyhow!("Failed to stop the endpoint: {:?}", e)) } pub async fn execute(&mut self, batch: BlockNumber) -> Result<()> { From 30a0a541a46c6b046bf607a856a1387282329aee Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Thu, 2 May 2024 22:15:01 +0800 Subject: [PATCH 09/12] refactor: support selection of DB, fix operator, move specific env to config --- Cargo.lock | 24 +++--- configs/database.toml | 3 + src/cli.rs | 1 + src/commands/chain_info.rs | 1 + src/commands/run.rs | 137 ++++++++++++++++++++++++++------- src/config/env.rs | 2 - src/custom_reth/mod.rs | 2 +- src/db/lfs/libmdbx.rs | 46 ++++++++++-- src/db/lfs/mod.rs | 12 +-- src/main.rs | 2 - src/operator.rs | 71 +++++++++++------- src/prover/provider.rs | 150 +++++++++++++++++++++++-------------- 12 files changed, 308 insertions(+), 143 deletions(-) create mode 100644 configs/database.toml diff --git a/Cargo.lock b/Cargo.lock index f2c5e90..6088a38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4633,9 +4633,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "311fb059dee1a7b802f036316d790138c613a4e8b180c822e3925a662e9f0c95" +checksum = "560131c633294438da9f7c4b08189194b20946c8274c6b9e38881a7874dc8ee8" dependencies = [ "memchr", "thiserror", @@ -4644,9 +4644,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73541b156d32197eecda1a4014d7f868fd2bcb3c550d5386087cfba442bf69c" +checksum = "26293c9193fbca7b1a3bf9b79dc1e388e927e6cacaa78b4a3ab705a1d3d41459" dependencies = [ "pest", "pest_generator", @@ -4654,9 +4654,9 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35eeed0a3fab112f75165fdc026b3913f4183133f19b49be773ac9ea966e8bd" +checksum = "3ec22af7d3fb470a85dd2ca96b7c577a1eb4ef6f1683a9fe9a8c16e136c04687" dependencies = [ "pest", "pest_meta", @@ -4667,9 +4667,9 @@ dependencies = [ [[package]] name = "pest_meta" -version = "2.7.9" +version = "2.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2adbf29bb9776f28caece835398781ab24435585fe0d4dc1374a61db5accedca" +checksum = "d7a240022f37c361ec1878d646fc5b7d7c4d28d5946e1a80ad5a7a4f4ca0bdcd" dependencies = [ "once_cell", "pest", @@ -7054,9 +7054,9 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" [[package]] name = "serde" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a" +checksum = "ddc6f9cc94d67c0e21aaf7eda3a010fd3af78ebf6e096aa6e2e13c79749cce4f" dependencies = [ "serde_derive", ] @@ -7072,9 +7072,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.199" +version = "1.0.200" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc" +checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb" dependencies = [ "proc-macro2", "quote", diff --git a/configs/database.toml b/configs/database.toml new file mode 100644 index 0000000..9fc4a12 --- /dev/null +++ b/configs/database.toml @@ -0,0 +1,3 @@ +[mdbx_config] +path = "/tmp/operator" +max_dbs = 10 diff --git a/src/cli.rs b/src/cli.rs index 0f44f57..d7ef00a 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,6 +1,7 @@ use crate::commands::{chain_info::ChainInfoCmd, config::ConfigCmd, run::RunCmd}; use anyhow::{bail, Result}; +/// Cli is the root command for the CLI. #[derive(clap::Parser, Debug, Clone)] #[command(version, author, about)] pub struct Cli { diff --git a/src/commands/chain_info.rs b/src/commands/chain_info.rs index 83823bb..eb3cee2 100644 --- a/src/commands/chain_info.rs +++ b/src/commands/chain_info.rs @@ -1,5 +1,6 @@ use anyhow::Result; +/// ChainInfoCmd used to print the Eigen-Zeth information. #[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] pub struct ChainInfoCmd {} diff --git a/src/commands/run.rs b/src/commands/run.rs index d53130c..b5e3b21 100644 --- a/src/commands/run.rs +++ b/src/commands/run.rs @@ -1,28 +1,32 @@ +use std::fmt; + +use anyhow::Result; +use tokio::select; +use tokio::signal::unix::{signal, SignalKind}; +use tokio::sync::mpsc; + use crate::config::env::GLOBAL_ENV; use crate::custom_reth; +use crate::db::lfs; use crate::operator; use crate::settlement::ethereum::EthereumSettlementConfig; use crate::settlement::NetworkSpec; -use anyhow::Result; -use std::fmt; -use std::str::FromStr; -use tokio::select; -use tokio::signal::unix::{signal, SignalKind}; -use tokio::sync::mpsc; /// The `RunCmd` struct is a command that runs the eigen-zeth. -#[derive(clap::Parser, Debug, Clone, PartialEq, Eq)] +#[derive(clap::Args, Debug, Clone, PartialEq, Eq)] +#[command(version, author, about, long_about)] pub struct RunCmd { - /// The log level of the node. Default is `debug`. Possible values are `Trace`, `debug`, `info`, `warn`, `error`. + /// The log level of the node. #[arg( long, value_name = "LOG_LEVEL", verbatim_doc_comment, default_value_t = LogLevel::Debug, - value_parser = LogLevel::from_str + ignore_case = true, )] pub log_level: LogLevel, + /// The settlement layer to use. #[arg( long, default_value_t = SettlementLayer::Ethereum, @@ -30,13 +34,71 @@ pub struct RunCmd { )] pub settlement: SettlementLayer, + /// Path to a file containing the settlement configuration. #[arg( long, + value_name = "FILE", value_hint = clap::ValueHint::FilePath, requires = "settlement", default_value = "configs/settlement.toml" )] pub settlement_conf: Option, + + #[clap(flatten)] + pub base_params: BaseParams, +} + +#[derive(clap::Args, Debug, Clone, PartialEq, Eq)] +pub struct BaseParams { + #[clap(flatten)] + pub databases: DatabaseParams, + + /// Aggregator's EOA address, used to prove batch by the aggregator. + #[arg( + long, + value_name = "EOA_ADDR", + verbatim_doc_comment, + default_value = "479881985774944702531460751064278034642760119942" + )] + pub aggregator_addr: String, +} + +#[derive(clap::Args, Debug, Clone, PartialEq, Eq)] +pub struct DatabaseParams { + /// Choose a supported database. + #[arg( + long, + value_name = "DB", + verbatim_doc_comment, + default_value_t = Database::Mdbx, + ignore_case = true, + )] + pub database: Database, + + /// Path to a file containing the database configuration. + #[arg( + long, + value_name = "FILE", + value_hint = clap::ValueHint::FilePath, + requires = "database", + default_value = "configs/database.toml" + )] + pub database_conf: String, +} + +#[derive(Debug, Clone, Eq, PartialEq, clap::ValueEnum)] +pub enum Database { + Memory, + Mdbx, +} + +impl fmt::Display for Database { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Database::Memory => write!(f, "memory"), + Database::Mdbx => write!(f, "mdbx"), + } + } } #[derive(Debug, Clone, Eq, PartialEq, clap::ValueEnum)] @@ -48,21 +110,6 @@ pub enum LogLevel { Error, } -impl FromStr for LogLevel { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - match s.to_lowercase().as_str() { - "debug" => Ok(LogLevel::Debug), - "info" => Ok(LogLevel::Info), - "warn" => Ok(LogLevel::Warn), - "error" => Ok(LogLevel::Error), - "trace" => Ok(LogLevel::Trace), - _ => Err(anyhow::Error::msg("invalid log level")), - } - } -} - impl fmt::Display for LogLevel { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { @@ -91,32 +138,66 @@ pub enum SettlementLayer { impl RunCmd { pub async fn run(&self) -> Result<()> { + // initialize the logger + std::env::set_var("RUST_LOG", self.log_level.to_string()); + env_logger::init(); + log::info!("Initialized logger with level: {}", self.log_level); + + // Load the settlement configuration let settlement_spec = match self.settlement { SettlementLayer::Ethereum => match &self.settlement_conf { None => { + log::info!("Using Ethereum SettlementLayer"); return Err(anyhow::anyhow!( "Settlement configuration is required for Ethereum settlement layer" )); } - Some(settlement_conf_path) => NetworkSpec::Ethereum( - EthereumSettlementConfig::from_conf_path(settlement_conf_path)?, - ), + Some(settlement_conf_path) => { + log::info!("Using Ethereum SettlementLayer"); + NetworkSpec::Ethereum(EthereumSettlementConfig::from_conf_path( + settlement_conf_path, + )?) + } }, }; + // Load the database configuration + let db_config = match self.base_params.databases.database { + Database::Memory => { + log::info!("Using in-memory database"); + lfs::DBConfig::Memory + } + Database::Mdbx => { + log::info!("Using mdbx database"); + lfs::DBConfig::Mdbx(lfs::libmdbx::Config::from_conf_path( + &self.base_params.databases.database_conf, + )?) + } + }; + + let aggregator_addr = &self.base_params.aggregator_addr; + log::info!( + "Load Aggregator address: {}", + self.base_params.aggregator_addr + ); + + // Initialize the operator let mut op = operator::Operator::new( - &GLOBAL_ENV.db_path, &GLOBAL_ENV.l1addr, &GLOBAL_ENV.prover_addr, settlement_spec, + db_config, + aggregator_addr, ) .unwrap(); let mut sigterm = signal(SignalKind::terminate()).unwrap(); let mut sigint = signal(SignalKind::interrupt()).unwrap(); + // initialize the signal channel let (stop_tx, stop_rx) = mpsc::channel::<()>(1); + // Handle the SIGTERM and SIGINT signals tokio::spawn(async move { #[allow(clippy::let_underscore_future)] #[allow(clippy::never_loop)] diff --git a/src/config/env.rs b/src/config/env.rs index c89e976..a889195 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -5,7 +5,6 @@ use std::string::ToString; /// EigenZethEnv is a struct that holds the environment variables pub struct GlobalEnv { - pub db_path: String, pub l1addr: String, pub prover_addr: String, pub curve_type: String, @@ -18,7 +17,6 @@ pub struct GlobalEnv { /// GLOBAL_ENV is a global variable that holds the environment variables, /// it is lazy loaded and thread safe pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { - db_path: std::env::var("ZETH_OPERATOR_DB").unwrap_or("/tmp/operator".to_string()), l1addr: std::env::var("ZETH_L2_ADDR").unwrap_or("http://localhost:8546".to_string()), prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), diff --git a/src/custom_reth/mod.rs b/src/custom_reth/mod.rs index 3e30675..4d0e976 100644 --- a/src/custom_reth/mod.rs +++ b/src/custom_reth/mod.rs @@ -373,7 +373,7 @@ pub async fn launch_custom_node() -> Result<()> { // Start the server & keep it alive let server_args = RpcServerConfig::http(Default::default()).with_http_address(GLOBAL_ENV.host.parse()?); - println!("Node started"); + log::info!("Node started"); let _handle = server_args.start(server).await?; // futures::future::pending::<()>().await; diff --git a/src/db/lfs/libmdbx.rs b/src/db/lfs/libmdbx.rs index 911528f..85c880f 100644 --- a/src/db/lfs/libmdbx.rs +++ b/src/db/lfs/libmdbx.rs @@ -4,8 +4,12 @@ use crate::db::lfs::libmdbx; use crate::db::Database as EigenDB; +use anyhow::{anyhow, Result}; +use config::{Config as UtilConfig, File}; use reth_libmdbx::*; +use serde::Deserialize; use std::fs; +use std::path::Path; pub struct Db(MdbxDB); @@ -20,14 +24,35 @@ pub struct MdbxDB { default_db: Database, } -pub fn open_mdbx_db(path: &str, max_dbs: usize) -> std::result::Result, ()> { +#[derive(Debug, Clone, Deserialize)] +pub struct Config { + pub path: String, + pub max_dbs: usize, +} + +impl Config { + pub fn from_conf_path(conf_path: &str) -> Result { + log::info!("Load the Database config from: {}", conf_path); + + let config = config::Config::builder() + .add_source(File::from(Path::new(conf_path))) + .build() + .map_err(|e| anyhow!("Failed to build config: {:?}", e))?; + + config + .get("mdbx_config") + .map_err(|e| anyhow!("Failed to parse Mdbx Config: {:?}", e)) + } +} + +pub fn open_mdbx_db(config: Config) -> std::result::Result, ()> { // create the directory if it does not exist // TODO: catch errors - fs::create_dir_all(path).unwrap(); + fs::create_dir_all(&config.path).unwrap(); let env = match Environment::builder() - .set_max_dbs(max_dbs) - .open(std::path::Path::new(path)) + .set_max_dbs(config.max_dbs) + .open(std::path::Path::new(&config.path)) { Ok(env) => env, Err(e) => { @@ -88,7 +113,12 @@ mod tests { fn test_open_mdbx_db() { let path = "tmp/test_open_mdbx_db"; let max_dbs = 20; - let _ = open_mdbx_db(path, max_dbs).unwrap(); + let config = Config { + path: path.to_string(), + max_dbs, + }; + + let _ = open_mdbx_db(config).unwrap(); fs::remove_dir_all(path).unwrap(); } @@ -96,7 +126,11 @@ mod tests { fn test_mdbx() { let path = "tmp/test_mdbx_db"; let max_dbs = 20; - let mut db = open_mdbx_db(path, max_dbs).unwrap(); + let config = Config { + path: path.to_string(), + max_dbs, + }; + let mut db = open_mdbx_db(config).unwrap(); let key = b"key"; // let key = string::String::from("value").into_bytes(); diff --git a/src/db/lfs/mod.rs b/src/db/lfs/mod.rs index 14f3294..1a06261 100644 --- a/src/db/lfs/mod.rs +++ b/src/db/lfs/mod.rs @@ -1,7 +1,7 @@ // TODO: Fix me #![allow(dead_code)] -mod libmdbx; +pub(crate) mod libmdbx; mod mem; use crate::db::Database as EigenDB; @@ -10,18 +10,12 @@ pub(crate) enum DBConfig { /// memory kv-database Memory, /// libmdbx database - Mdbx { - /// Path to the mdbx database - // path: PathBuf, - path: String, - /// Maximum number of databases - max_dbs: usize, - }, + Mdbx(libmdbx::Config), } pub(crate) fn open_db(config: DBConfig) -> Result, ()> { match config { DBConfig::Memory => mem::open_memory_db(), - DBConfig::Mdbx { path, max_dbs } => libmdbx::open_mdbx_db(&path, max_dbs), + DBConfig::Mdbx(config) => libmdbx::open_mdbx_db(config), } } diff --git a/src/main.rs b/src/main.rs index a5b624b..b571bbf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -14,7 +14,5 @@ mod settlement; #[tokio::main] async fn main() -> Result<()> { - std::env::set_var("RUST_LOG", "debug"); - env_logger::init(); cli::Cli::parse().run().await } diff --git a/src/operator.rs b/src/operator.rs index c5efe74..52049d6 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -10,7 +10,7 @@ use anyhow::{anyhow, Result}; use ethers_core::types::{Bytes, H160, U256}; use ethers_providers::{Http, Provider}; use std::sync::Arc; -use tokio::sync::mpsc::{self, Receiver}; +use tokio::sync::mpsc::{self, Receiver, Sender}; use tokio::time::{interval, Duration}; use crate::config::env::GLOBAL_ENV; @@ -20,25 +20,28 @@ use crate::settlement::ethereum::{EthereumSettlement, EthereumSettlementConfig}; pub(crate) struct Operator { db: Box, prover: ProverChannel, - rx_proof: Receiver>, settler: Box, + proof_sender: Sender>, + proof_receiver: Receiver>, } impl Operator { pub fn new( - db_path: &str, _l1addr: &str, prover_addr: &str, settlement_spec: NetworkSpec, + db_config: lfs::DBConfig, + aggregator_addr: &str, ) -> Result { - let (sx, rx_proof) = mpsc::channel(10); - let prover = ProverChannel::new(prover_addr, sx); - let db = lfs::open_db(lfs::DBConfig::Mdbx { - path: db_path.to_string(), - max_dbs: 10, - }) - .map_err(|e| anyhow!("Failed to open db: {:?}", e))?; + let (proof_sender, proof_receiver) = mpsc::channel(10); + + // initialize the prover + let prover = ProverChannel::new(prover_addr, aggregator_addr); + + // initialize the database + let db = lfs::open_db(db_config).map_err(|e| anyhow!("Failed to open db: {:?}", e))?; + // initialize the settlement layer let settler = init_settlement(settlement_spec) .map_err(|e| anyhow!("Failed to init settlement: {:?}", e))?; @@ -46,7 +49,8 @@ impl Operator { prover, db, settler, - rx_proof, + proof_sender, + proof_receiver, }) } @@ -72,7 +76,32 @@ impl Operator { }, (Some(no), None) => { let block_no = u64::from_be_bytes(no.try_into().unwrap()); - self.prover.execute(block_no).await.unwrap(); + let prover_task = self.prover.execute(block_no); + tokio::select! { + result = prover_task => { + match result { + Ok(execute_result) => { + log::info!("execute batch {} success: {:?}", block_no, execute_result); + // TODO: send proof and public inputs to the settlement layer + self.proof_sender.send(Vec::from(execute_result.proof)).await.unwrap(); + } + Err(e) => { + log::error!("execute batch {} failed: {:?}", block_no, e); + // TODO: retry or skip? + } + } + + // trigger the next task + let block_no_next = block_no + 1; + self.db.put(batch_key.clone(), block_no_next.to_be_bytes().to_vec()); + } + + _ = stop_channel.recv() => { + self.prover.stop().await.unwrap(); + log::info!("Operator stopped"); + return Ok(()); + } + } }, (None, Some(no)) => todo!("Invalid branch, block: {no}"), (Some(next), Some(cur)) => { @@ -81,27 +110,17 @@ impl Operator { }, }; } - proof_data = self.rx_proof.recv() => { + proof_data = self.proof_receiver.recv() => { log::debug!("fetch proof: {:?}", proof_data); self.db.put(proof_key.clone(), proof_data.unwrap()); - // trigger the next task - if let Some(current_batch) = self.db.get(&batch_key) { - let block_no = u64::from_be_bytes(current_batch.try_into().unwrap()); - self.prover.execute(block_no).await.unwrap(); - let block_no_next = block_no + 1; - self.db.put(batch_key.clone(), block_no_next.to_be_bytes().to_vec()); - - // TODO - let _ = self.settler.bridge_asset(0, H160::zero(), U256::zero(), H160::zero(), true, Bytes::default()).await; - } else { - log::debug!("Wait for the new task coming in"); - } + // TODO: verify the proof + let _ = self.settler.bridge_asset(0, H160::zero(), U256::zero(), H160::zero(), true, Bytes::default()).await; } _ = stop_channel.recv() => { self.prover.stop().await.unwrap(); } - }; + } } } } diff --git a/src/prover/provider.rs b/src/prover/provider.rs index 780f19f..ee04d0d 100644 --- a/src/prover/provider.rs +++ b/src/prover/provider.rs @@ -15,8 +15,7 @@ use crate::prover::provider::prover_service::{ Batch, GenAggregatedProofRequest, GenBatchProofRequest, GenFinalProofRequest, ProofResultCode, ProverRequest, }; -use anyhow::{anyhow, Result}; -use prost::Message; +use anyhow::{anyhow, bail, Result}; use std::fmt; use std::time::Duration; use tokio::sync::mpsc; @@ -42,10 +41,12 @@ pub struct ProverChannel { response_receiver: Receiver, /// final proof - final_proof_sender: Sender>, + // final_proof_sender: Sender>, /// used to stop the endpoint stop_endpoint_tx: Sender<()>, + /// the address of the aggregator + aggregator_addr: String, } type BlockNumber = u64; @@ -53,6 +54,20 @@ type StartChunk = String; type EndChunk = String; type RecursiveProof = String; +type ErrMsg = String; + +#[derive(Debug, Clone)] +pub enum ExecuteResult { + Success(ProofResult), + Failed(ErrMsg), +} + +#[derive(Debug, Clone)] +pub struct ProofResult { + pub proof: String, + pub public_inputs: String, +} + /// ProveStep ... #[derive(Debug)] enum ProveStep { @@ -61,7 +76,7 @@ enum ProveStep { Batch(BlockNumber), Aggregate(StartChunk, EndChunk), Final(RecursiveProof), - End, + End(ExecuteResult), } impl fmt::Display for ProveStep { @@ -71,13 +86,13 @@ impl fmt::Display for ProveStep { ProveStep::Batch(no) => write!(f, "♦ Batch: {}", no), ProveStep::Aggregate(s, e) => write!(f, "♠ Agg: {} -> {}", s, e), ProveStep::Final(r) => write!(f, "♣ Final: {:?}", r), - ProveStep::End => write!(f, "🌹"), + ProveStep::End(result) => write!(f, "🌹 End: {:?}", result), } } } impl ProverChannel { - pub fn new(addr: &str, sender: Sender>) -> Self { + pub fn new(addr: &str, aggregator_addr: &str) -> Self { let (response_sender, response_receiver) = mpsc::channel(10); let (request_sender, request_receiver) = mpsc::channel(10); let (stop_tx, stop_rx) = mpsc::channel(1); @@ -93,8 +108,8 @@ impl ProverChannel { )), request_sender, response_receiver, - final_proof_sender: sender, stop_endpoint_tx: stop_tx, + aggregator_addr: aggregator_addr.to_string(), } } @@ -106,13 +121,36 @@ impl ProverChannel { // the self.endpoint will be None after this // TODO: handle the error, and relaunch the endpoint let mut endpoint = self.endpoint.take().unwrap(); + // loop { + // tokio::select! { + // r = endpoint.launch() => { + // match r { + // Ok(_) => { + // // stop with the signal + // return Ok(()) + // } + // Err(e) => { + // // stop with the error + // // TODO: relaunch the endpoint + // log::error!("ProverEndpoint error: {:?}", e); + // } + // } + // } + // } + // } + tokio::spawn(async move { - match endpoint.launch().await { - Ok(_) => { - log::info!("ProverEndpoint stopped"); - } - Err(e) => { - log::error!("ProverEndpoint error: {:?}", e); + loop { + match endpoint.launch().await { + Ok(_) => { + // stop with the signal + return; + } + Err(e) => { + // stop with the error + // TODO: relaunch the endpoint + log::error!("ProverEndpoint error: {:?}", e); + } } } }); @@ -126,21 +164,20 @@ impl ProverChannel { .send(()) .await .map_err(|e| anyhow!("Failed to stop the endpoint: {:?}", e)) + .map(|_| log::info!("ProverChannel stopped")) } - pub async fn execute(&mut self, batch: BlockNumber) -> Result<()> { + pub async fn execute(&mut self, batch: BlockNumber) -> Result { log::debug!("execute batch {batch}"); self.set_current_batch(batch)?; // return proof for the batch - self.entry_step().await?; - + let result = self.entry_step().await; self.clean_current_batch()?; - - Ok(()) + result.map_err(|e| anyhow!("execute batch:{} failed: {:?}", batch, e)) } - async fn entry_step(&mut self) -> Result<()> { + async fn entry_step(&mut self) -> Result { loop { self.step = match &self.step { ProveStep::Start => { @@ -174,14 +211,19 @@ impl ProverChannel { .batch_proof_result .unwrap() .chunk_proofs; - let start_chunk = chunks.first().unwrap().clone().proof_key; - let end_chunk = chunks.last().unwrap().clone().proof_key; + let start_chunk = chunks.first().unwrap().clone().proof; + let end_chunk = chunks.last().unwrap().clone().proof; ProveStep::Aggregate(start_chunk, end_chunk) } else { - ProveStep::End + ProveStep::End(ExecuteResult::Failed(format!( + "gen batch proof failed, err: {}", + gen_batch_proof_response.error_message + ))) } } else { - ProveStep::End + ProveStep::End(ExecuteResult::Failed( + "gen batch proof failed, err: invalid response".to_string(), + )) } } @@ -208,10 +250,15 @@ impl ProverChannel { let recursive_proof = gen_aggregated_proof_response.result_string; ProveStep::Final(recursive_proof) } else { - ProveStep::End + ProveStep::End(ExecuteResult::Failed(format!( + "gen aggregated proof failed, err: {}", + gen_aggregated_proof_response.error_message + ))) } } else { - ProveStep::End + ProveStep::End(ExecuteResult::Failed( + "gen aggregated proof failed, err: invalid response".to_string(), + )) } } @@ -221,7 +268,7 @@ impl ProverChannel { request_type: Some(RequestType::GenFinalProof(GenFinalProofRequest { recursive_proof: recursive_proof.clone(), curve_name: GLOBAL_ENV.curve_type.clone(), - aggregator_addr: GLOBAL_ENV.host.clone(), + aggregator_addr: self.aggregator_addr.clone(), })), }; self.request_sender.send(request).await?; @@ -233,31 +280,34 @@ impl ProverChannel { if gen_final_proof_response.result_code == ProofResultCode::CompletedOk as i32 { - let mut final_proof = vec![]; - gen_final_proof_response - .final_proof - .unwrap() - .encode(&mut final_proof)?; - self.final_proof_sender.send(final_proof).await?; - ProveStep::End + // TODO: ensure the proof and public_inputs's structure + ProveStep::End(ExecuteResult::Success(ProofResult { + proof: gen_final_proof_response.final_proof.unwrap().proof, + // TODO: public_inputs + public_inputs: "TODO".to_string(), + })) } else { - // TODO: return error - log::error!( - "gen final proof failed, error: {:?}", + ProveStep::End(ExecuteResult::Failed(format!( + "gen final proof failed: {}", gen_final_proof_response.error_message - ); - ProveStep::End + ))) } } else { - log::error!("gen final proof failed, no response"); - ProveStep::End + ProveStep::End(ExecuteResult::Failed( + "gen final proof failed, err: invalid response".to_string(), + )) } } - ProveStep::End => { + ProveStep::End(execute_result) => { + let result = (*execute_result).clone(); // reset smt state self.step = ProveStep::Start; - return Ok(()); + + return match result { + ExecuteResult::Success(r) => Ok(r), + ExecuteResult::Failed(err) => bail!("{}", err), + }; } }; log::debug!("Status: {:?}, {}", self.current_batch, self.step); @@ -316,15 +366,6 @@ impl ProverEndpoint { } } - /// send request to the gRPC Stream - // pub async fn send_request( - // &mut self, - // request: ProverRequest, - // ) -> Result<()> { - // self.request_sender.send(request).await?; - // Ok(()) - // } - /// launch the endpoint pub async fn launch(&mut self) -> Result<()> { let mut client = ProverServiceClient::connect(self.addr.clone()).await?; @@ -342,6 +383,7 @@ impl ProverEndpoint { loop { tokio::select! { _ = self.stop_endpoint_rx.recv() => { + log::info!("ProverEndpoint stopped"); return Ok(()); } recv_msg_result = resp_stream.message() => { @@ -371,10 +413,4 @@ impl ProverEndpoint { } } } - - // stop the endpoint - // pub async fn stop(&mut self) -> Result<()> { - // self.stop_endpoint_tx.send(()).await?; - // Ok(()) - // } } From fc385dec729136543fea219acb17c8db0e3027d7 Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Thu, 2 May 2024 22:31:01 +0800 Subject: [PATCH 10/12] docs: update readme --- README.md | 2 +- src/config/env.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fe35514..29800a7 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ rm -rf /tmp/chain reth init --datadir /tmp/chain --chain testdata/chain.json RUST_LOG="debug,evm=trace,consensus::auto=trace,consensus::engine=trace,rpc::eth=trace" reth node -d --chain testdata/chain.json --datadir /tmp/chain --auto-mine --http --http.port 8546 --http.api debug,eth,net,trace,web3,rpc -RUST_LOG="rpc::eth=trace" ZETH_DB_PATH=/tmp/chain ZETH_OPERATOR_DB=/tmp/operator PROVER_ADDR=localhost:50061 ZETH_L2_ADDR=http://localhost:8546 HOST=0.0.0.0:8182 cargo run -r +RUST_LOG="rpc::eth=trace" ZETH_DB_PATH=/tmp/chain PROVER_ADDR=http://localhost:50061 ZETH_L2_ADDR=http://localhost:8546 HOST=0.0.0.0:8182 cargo run -r -- run --database mdbx ``` diff --git a/src/config/env.rs b/src/config/env.rs index a889195..005ce77 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -22,7 +22,7 @@ pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), host: std::env::var("HOST").unwrap_or("0.0.0.0:8182".to_string()), zeth_db_path: std::env::var("ZETH_DB_PATH") - .unwrap_or("/home/terry/project/0xeigen/local-reth-data/tmp/chain".to_string()), + .unwrap_or("/tmp/chain".to_string()), chain_id: std::env::var("CHAIN_ID") .unwrap_or("12345".to_string()) .parse::() From 0a241828c6ca515ec5a9a525c7bbd7ec2bd26e9c Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Thu, 2 May 2024 22:32:24 +0800 Subject: [PATCH 11/12] style: update fmt --- src/config/env.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/config/env.rs b/src/config/env.rs index 005ce77..b08fd46 100644 --- a/src/config/env.rs +++ b/src/config/env.rs @@ -21,8 +21,7 @@ pub static GLOBAL_ENV: Lazy = Lazy::new(|| GlobalEnv { prover_addr: std::env::var("PROVER_ADDR").unwrap_or("http://127.0.0.1:50061".to_string()), curve_type: std::env::var("CURVE_TYPE").unwrap_or("BN128".to_string()), host: std::env::var("HOST").unwrap_or("0.0.0.0:8182".to_string()), - zeth_db_path: std::env::var("ZETH_DB_PATH") - .unwrap_or("/tmp/chain".to_string()), + zeth_db_path: std::env::var("ZETH_DB_PATH").unwrap_or("/tmp/chain".to_string()), chain_id: std::env::var("CHAIN_ID") .unwrap_or("12345".to_string()) .parse::() From 2338c07b08bcdf0d3d5e69566e27eb67eb3dd26b Mon Sep 17 00:00:00 2001 From: Terry <644052732@qq.com> Date: Fri, 3 May 2024 00:50:12 +0800 Subject: [PATCH 12/12] refactor: update the L1 provider_url --- configs/settlement.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/settlement.toml b/configs/settlement.toml index 8569b61..fc0b6c4 100644 --- a/configs/settlement.toml +++ b/configs/settlement.toml @@ -1,5 +1,5 @@ [ethereum_settlement_config] -provider_url = "http://localhost:8546" +provider_url = "http://localhost:8545" [ethereum_settlement_config.local_wallet] private_key = "0x76af8cc59ecfabf983d423e2054b07c11212cabc532062da0bd8067c59cf4a40"