From 142141c34eceb68df775721933c6a26b5f5cecc1 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Tue, 30 Jul 2024 17:59:43 -0300 Subject: [PATCH 01/36] add skeleton --- Cargo.lock | 121 +++++++++++++++++++++++++++++++++++++ Cargo.toml | 3 +- crates/egnaddrs/Cargo.toml | 14 +++++ crates/egnaddrs/cli_eth.rs | 25 ++++++++ 4 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 crates/egnaddrs/Cargo.toml create mode 100644 crates/egnaddrs/cli_eth.rs diff --git a/Cargo.lock b/Cargo.lock index 786969fa..7d870342 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -499,6 +499,55 @@ dependencies = [ "ws_stream_wasm", ] +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys 0.52.0", +] + [[package]] name = "anyhow" version = "1.0.86" @@ -1021,6 +1070,46 @@ dependencies = [ "inout", ] +[[package]] +name = "clap" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn 2.0.67", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + [[package]] name = "coins-bip32" version = "0.8.7" @@ -1073,6 +1162,12 @@ dependencies = [ "thiserror", ] +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + [[package]] name = "const-hex" version = "1.12.0" @@ -1465,6 +1560,14 @@ dependencies = [ "serde_json", ] +[[package]] +name = "eigen-egnaddrs" +version = "0.0.1-alpha" +dependencies = [ + "alloy-primitives", + "clap", +] + [[package]] name = "eigen-logging" version = "0.0.1-alpha" @@ -2744,6 +2847,12 @@ version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + [[package]] name = "itertools" version = "0.10.5" @@ -4499,6 +4608,12 @@ dependencies = [ "precomputed-hash", ] +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.26.2" @@ -5163,6 +5278,12 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "uuid" version = "0.8.2" diff --git a/Cargo.toml b/Cargo.toml index 1ceb2fd6..1fe6ed9c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,6 +10,7 @@ members = [ "crates/utils/", "crates/crypto/bls/", "crates/crypto/keystore/", + "crates/egnaddrs/", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", "crates/services/avsregistry/", @@ -25,7 +26,7 @@ members = [ "testing/testing-utils/", "examples/avsregistry-read", "examples/avsregistry-write", - "examples/anvil-utils" + "examples/anvil-utils", ] resolver = "2" diff --git a/crates/egnaddrs/Cargo.toml b/crates/egnaddrs/Cargo.toml new file mode 100644 index 00000000..dcefd454 --- /dev/null +++ b/crates/egnaddrs/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "eigen-egnaddrs" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +repository.workspace = true + +[dependencies] +clap = { version = "4.5.11", features = ["derive"] } +alloy-primitives.workspace = true + +[[bin]] +name = "cli_eth" +path = "cli_eth.rs" diff --git a/crates/egnaddrs/cli_eth.rs b/crates/egnaddrs/cli_eth.rs new file mode 100644 index 00000000..7d1fa682 --- /dev/null +++ b/crates/egnaddrs/cli_eth.rs @@ -0,0 +1,25 @@ +use alloy_primitives::Address; +use clap::Parser; + +/// Simple program to greet a person +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[arg(long)] + service_manager: Option
, + + #[arg(long)] + registry_coordinator: Option
, + + #[arg(long)] + rpc_url: String, +} + +fn main() { + let args = Args::parse(); + print_addrs(args.rpc_url); +} + +fn print_addrs(param: String) { + println!("print_addrs: {}", param); +} From 03b9dad6478cc5ef188312f4f3569104d339dbb0 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 31 Jul 2024 02:28:32 -0300 Subject: [PATCH 02/36] add commands info and load provider --- Cargo.lock | 3 +++ crates/egnaddrs/Cargo.toml | 3 +++ crates/egnaddrs/cli_eth.rs | 32 +++++++++++++++++++++++--------- 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7d870342..5d71fa29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1566,6 +1566,9 @@ version = "0.0.1-alpha" dependencies = [ "alloy-primitives", "clap", + "eigen-utils", + "ethers", + "tokio", ] [[package]] diff --git a/crates/egnaddrs/Cargo.toml b/crates/egnaddrs/Cargo.toml index dcefd454..50a5d641 100644 --- a/crates/egnaddrs/Cargo.toml +++ b/crates/egnaddrs/Cargo.toml @@ -8,6 +8,9 @@ repository.workspace = true [dependencies] clap = { version = "4.5.11", features = ["derive"] } alloy-primitives.workspace = true +ethers.workspace = true +tokio.workspace = true +eigen-utils.workspace = true [[bin]] name = "cli_eth" diff --git a/crates/egnaddrs/cli_eth.rs b/crates/egnaddrs/cli_eth.rs index 7d1fa682..e08944f6 100644 --- a/crates/egnaddrs/cli_eth.rs +++ b/crates/egnaddrs/cli_eth.rs @@ -1,25 +1,39 @@ use alloy_primitives::Address; use clap::Parser; +use eigen_utils::{binding::RegistryCoordinator, get_provider}; +use ethers::providers::{Http, Middleware, Provider}; +use tokio; -/// Simple program to greet a person #[derive(Parser, Debug)] -#[command(version, about, long_about = None)] +#[command( + version, + about = "Used to help debug and test deployments and contract setups.", + long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." +)] struct Args { - #[arg(long)] + #[arg(long, help = "ServiceManager contract address")] service_manager: Option
, - #[arg(long)] + #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] registry_coordinator: Option
, - #[arg(long)] + #[arg(long, help = "rpc url", default_value = "http://localhost:8545")] rpc_url: String, } -fn main() { +#[tokio::main] +async fn main() { let args = Args::parse(); - print_addrs(args.rpc_url); + print_addrs(args).await; } -fn print_addrs(param: String) { - println!("print_addrs: {}", param); +async fn print_addrs(args: Args) { + // The default RPC URL is the local anvil address + let client = Provider::::try_from(args.rpc_url).expect("Invalid RPC URL"); // check get_provide utl + let chain_id = client.get_chainid().await.expect("Invalid RPC URL"); + println!("{}", chain_id); + + // TODO: get service_manager_addr and registry_coordinator_addr + // use service_manager to get eigen layer contracts addresses (slasher, delegation-manager, strategy-manager) + // use registry_coordinator to get avs contracts addresses (bls-apk-registry, index-registry, stake-registry) } From 28f684ed19c62eba1e047c29d5519564765f1d56 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 31 Jul 2024 16:32:00 -0300 Subject: [PATCH 03/36] add contract addresses --- Cargo.lock | 16 +- Cargo.toml | 3 +- crates/contracts/bindings/Cargo.toml | 3 +- .../bindings/src/generate_bindings.rs | 5 + crates/egnaddrs/cli_eth.rs | 39 --- crates/{egnaddrs => eigen-cli}/Cargo.toml | 12 +- crates/eigen-cli/egnaddrs.rs | 226 ++++++++++++++++++ crates/utils/src/binding.rs | 7 + 8 files changed, 263 insertions(+), 48 deletions(-) delete mode 100644 crates/egnaddrs/cli_eth.rs rename crates/{egnaddrs => eigen-cli}/Cargo.toml (54%) create mode 100644 crates/eigen-cli/egnaddrs.rs diff --git a/Cargo.lock b/Cargo.lock index 5d71fa29..ddcba175 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1510,6 +1510,9 @@ dependencies = [ [[package]] name = "eigen-contract-bindings" version = "0.0.1-alpha" +dependencies = [ + "ethers", +] [[package]] name = "eigen-crypto-bls" @@ -1561,13 +1564,19 @@ dependencies = [ ] [[package]] -name = "eigen-egnaddrs" +name = "eigen-eigen-cli" version = "0.0.1-alpha" dependencies = [ + "alloy-contract", "alloy-primitives", + "alloy-provider", "clap", + "eigen-contract-bindings", + "eigen-testing-utils", "eigen-utils", "ethers", + "serde", + "serde_json", "tokio", ] @@ -4407,11 +4416,12 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.120" +version = "1.0.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] diff --git a/Cargo.toml b/Cargo.toml index 1fe6ed9c..1e181e29 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ members = [ "crates/utils/", "crates/crypto/bls/", "crates/crypto/keystore/", - "crates/egnaddrs/", + "crates/eigen-cli/", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", "crates/services/avsregistry/", @@ -93,6 +93,7 @@ hyper = "0.14.25" eth-keystore = "0.5.0" hex-literal = "0.4.1" k256 = "0.13.3" +serde_json = "1.0.121" #misc parking_lot = "0.12" diff --git a/crates/contracts/bindings/Cargo.toml b/crates/contracts/bindings/Cargo.toml index 8c30ff78..dd153e93 100644 --- a/crates/contracts/bindings/Cargo.toml +++ b/crates/contracts/bindings/Cargo.toml @@ -9,5 +9,4 @@ repository.workspace = true license-file.workspace = true [dependencies] - - +ethers.workspace = true diff --git a/crates/contracts/bindings/src/generate_bindings.rs b/crates/contracts/bindings/src/generate_bindings.rs index 8978d8ab..cb299d9c 100644 --- a/crates/contracts/bindings/src/generate_bindings.rs +++ b/crates/contracts/bindings/src/generate_bindings.rs @@ -45,5 +45,10 @@ mod tests { generate_bindings("ISlasher", "ISlasher.json", "../bindings"); generate_bindings("IStrategy", "IStrategy.json", "../bindings"); generate_bindings("IERC20", "IERC20.json", "../bindings"); + generate_bindings( + "IBLSSignatureChecker", + "IBLSSignatureChecker.json", + "../bindings", + ); } } diff --git a/crates/egnaddrs/cli_eth.rs b/crates/egnaddrs/cli_eth.rs deleted file mode 100644 index e08944f6..00000000 --- a/crates/egnaddrs/cli_eth.rs +++ /dev/null @@ -1,39 +0,0 @@ -use alloy_primitives::Address; -use clap::Parser; -use eigen_utils::{binding::RegistryCoordinator, get_provider}; -use ethers::providers::{Http, Middleware, Provider}; -use tokio; - -#[derive(Parser, Debug)] -#[command( - version, - about = "Used to help debug and test deployments and contract setups.", - long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." -)] -struct Args { - #[arg(long, help = "ServiceManager contract address")] - service_manager: Option
, - - #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] - registry_coordinator: Option
, - - #[arg(long, help = "rpc url", default_value = "http://localhost:8545")] - rpc_url: String, -} - -#[tokio::main] -async fn main() { - let args = Args::parse(); - print_addrs(args).await; -} - -async fn print_addrs(args: Args) { - // The default RPC URL is the local anvil address - let client = Provider::::try_from(args.rpc_url).expect("Invalid RPC URL"); // check get_provide utl - let chain_id = client.get_chainid().await.expect("Invalid RPC URL"); - println!("{}", chain_id); - - // TODO: get service_manager_addr and registry_coordinator_addr - // use service_manager to get eigen layer contracts addresses (slasher, delegation-manager, strategy-manager) - // use registry_coordinator to get avs contracts addresses (bls-apk-registry, index-registry, stake-registry) -} diff --git a/crates/egnaddrs/Cargo.toml b/crates/eigen-cli/Cargo.toml similarity index 54% rename from crates/egnaddrs/Cargo.toml rename to crates/eigen-cli/Cargo.toml index 50a5d641..d8cde6eb 100644 --- a/crates/egnaddrs/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "eigen-egnaddrs" +name = "eigen-eigen-cli" version.workspace = true edition.workspace = true rust-version.workspace = true @@ -11,7 +11,13 @@ alloy-primitives.workspace = true ethers.workspace = true tokio.workspace = true eigen-utils.workspace = true +eigen-contract-bindings.workspace = true +eigen-testing-utils.workspace = true +alloy-provider.workspace = true +alloy-contract.workspace = true +serde.workspace = true +serde_json.workspace = true [[bin]] -name = "cli_eth" -path = "cli_eth.rs" +name = "egnaddrs" +path = "egnaddrs.rs" diff --git a/crates/eigen-cli/egnaddrs.rs b/crates/eigen-cli/egnaddrs.rs new file mode 100644 index 00000000..8521f402 --- /dev/null +++ b/crates/eigen-cli/egnaddrs.rs @@ -0,0 +1,226 @@ +use alloy_contract; +use alloy_primitives::Address; +use alloy_provider::Provider; +use clap::Parser; +use eigen_utils::{ + binding::{ContractsRegistry, DelegationManager, IBLSSignatureChecker}, + get_provider, +}; +use serde::Serialize; +use serde_json; +use tokio; + +#[derive(Parser, Debug)] +#[command( + version, + about = "Used to help debug and test deployments and contract setups.", + long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." +)] +struct Args { + #[arg(long, help = "ServiceManager contract address")] + service_manager: Option
, + + #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] + registry_coordinator: Option
, + + #[arg(long, help = "rpc url", default_value = "http://localhost:8545")] + rpc_url: String, +} + +#[derive(Serialize)] +pub struct EigenAddressesResponse { + network: NetworkInfo, + eigenlayer: EigenAddresses, + avs: AvsAddresses, +} + +#[derive(Serialize)] +pub struct NetworkInfo { + rpc_url: String, + chain_id: u64, +} + +#[derive(Serialize)] +pub struct EigenAddresses { + slasher: Address, + delegation_manager: Address, + strategy_manager: Address, +} + +#[derive(Serialize)] +pub struct AvsAddresses { + service_manager: Address, + registry_coordinator: Address, + bls_apk_registry: Address, + index_registry: Address, + stake_registry: Address, +} + +#[tokio::main] +async fn main() { + let args = Args::parse(); + let addresses = get_addresses(args).await; + + println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); +} + +async fn get_registry_coord_and_service_manager_addr( + args: Args, + client: P, +) -> (Address, Address) +where + T: alloy_contract::private::Transport + ::core::clone::Clone, + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, +{ + if let Some(registry_coord_addr) = args.registry_coordinator { + let contracts_registry = ContractsRegistry::new(registry_coord_addr, client); + + let service_manager_addr = contracts_registry + .contracts("mockAvsServiceManager".to_string()) + .call() + .await + .unwrap() + ._0; + + (registry_coord_addr, service_manager_addr) + } else if let Some(service_manager_addr) = args.service_manager { + let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); + let registry_coord_addr = service_manager + .registryCoordinator() + .call() + .await + .unwrap() + ._0; + + (registry_coord_addr, service_manager_addr) + } else { + // raise error + panic!() + } +} + +async fn get_eigenlayer_contract_addresses( + service_manager_addr: Address, + client: P, +) -> EigenAddresses +where + P: alloy_contract::private::Provider, + T: alloy_contract::private::Transport + ::core::clone::Clone, + N: alloy_contract::private::Network, +{ + let service_manager = IBLSSignatureChecker::new(service_manager_addr, &client); + let delegation_manager_addr = service_manager.delegation().call().await.unwrap()._0; + let delegation_manager_client = DelegationManager::new(delegation_manager_addr, &client); + let slasher_addr = delegation_manager_client.slasher().call().await.unwrap()._0; + let strategy_manager_addr = delegation_manager_client + .strategyManager() + .call() + .await + .unwrap() + ._0; + + EigenAddresses { + slasher: slasher_addr, + delegation_manager: delegation_manager_addr, + strategy_manager: strategy_manager_addr, + } +} + +async fn get_avs_contract_addresses( + registry_coord_addr: Address, + client: P, +) -> AvsAddresses +where + P: alloy_contract::private::Provider, + T: alloy_contract::private::Transport + ::core::clone::Clone, + N: alloy_contract::private::Network, +{ + let contracts_registry = ContractsRegistry::new(registry_coord_addr, &client); + let service_manager_addr = contracts_registry + .contracts("ServiceManagerBase".to_string()) + .call() + .await + .unwrap() + ._0; + let bls_pubkey_apk_addr = contracts_registry + .contracts("blsApkRegistry".to_string()) + .call() + .await + .unwrap() + ._0; + let index_registry_addr = contracts_registry + .contracts("indexRegistry".to_string()) + .call() + .await + .unwrap() + ._0; + let stake_registry_addr = contracts_registry + .contracts("stakeRegistry".to_string()) + .call() + .await + .unwrap() + ._0; + + AvsAddresses { + service_manager: service_manager_addr, + registry_coordinator: registry_coord_addr, + bls_apk_registry: bls_pubkey_apk_addr, + index_registry: index_registry_addr, + stake_registry: stake_registry_addr, + } +} + +async fn get_addresses(args: Args) -> EigenAddressesResponse { + let rpc_url = args.rpc_url.clone(); + let client = get_provider(&rpc_url); + let chain_id = client.get_chain_id().await.unwrap(); + let (registry_coord_addr, service_manager_addr) = + get_registry_coord_and_service_manager_addr(args, client.clone()).await; + let avs = get_avs_contract_addresses(registry_coord_addr, client.clone()).await; + + let eigenlayer = get_eigenlayer_contract_addresses(service_manager_addr, client).await; + + let network = NetworkInfo { rpc_url, chain_id }; + EigenAddressesResponse { + network, + eigenlayer, + avs, + } +} + +#[cfg(test)] +mod test { + use crate::get_addresses; + + use super::Args; + use eigen_testing_utils::anvil_constants::{ + get_registry_coordinator_address, get_service_manager_address, + }; + use tokio; + #[tokio::test] + async fn egnaddrs_with_service_manager_flag() { + let service_manager_address = get_service_manager_address().await; + let args = Args { + registry_coordinator: None, + service_manager: Some(service_manager_address), + rpc_url: "http://localhost:8545".into(), + }; + let addresses = get_addresses(args).await; + // TODO: add corresponding assert + assert!(true); + } + + #[tokio::test] + async fn egnaddrs_with_registry_coordinator_flag() { + let registry_coordinator_address = get_registry_coordinator_address().await; + let args = Args { + registry_coordinator: Some(registry_coordinator_address), + service_manager: None, + rpc_url: "http://localhost:8545".into(), + }; + let addresses = get_addresses(args).await; + // TODO: add corresponding assert + assert!(true); + } +} diff --git a/crates/utils/src/binding.rs b/crates/utils/src/binding.rs index 7e5c418a..c183fbb4 100644 --- a/crates/utils/src/binding.rs +++ b/crates/utils/src/binding.rs @@ -107,6 +107,13 @@ sol!( "../../crates/contracts/bindings/utils/json/ECDSAStakeRegistry.json" ); +sol!( + #[allow(missing_docs)] + #[sol(rpc)] + IBLSSignatureChecker, + "../../crates/contracts/bindings/utils/json/IBLSSignatureChecker.json" +); + // Anvil utilities sol!( From 29fe3bbdaba1e38101eeb0a8f0c50969eec02a72 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 31 Jul 2024 16:52:07 -0300 Subject: [PATCH 04/36] remove unused crates --- Cargo.lock | 2 -- crates/eigen-cli/Cargo.toml | 2 -- crates/eigen-cli/egnaddrs.rs | 4 +--- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ddcba175..00f7df7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1571,10 +1571,8 @@ dependencies = [ "alloy-primitives", "alloy-provider", "clap", - "eigen-contract-bindings", "eigen-testing-utils", "eigen-utils", - "ethers", "serde", "serde_json", "tokio", diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index d8cde6eb..f5bbf2a5 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -8,10 +8,8 @@ repository.workspace = true [dependencies] clap = { version = "4.5.11", features = ["derive"] } alloy-primitives.workspace = true -ethers.workspace = true tokio.workspace = true eigen-utils.workspace = true -eigen-contract-bindings.workspace = true eigen-testing-utils.workspace = true alloy-provider.workspace = true alloy-contract.workspace = true diff --git a/crates/eigen-cli/egnaddrs.rs b/crates/eigen-cli/egnaddrs.rs index 8521f402..916d8637 100644 --- a/crates/eigen-cli/egnaddrs.rs +++ b/crates/eigen-cli/egnaddrs.rs @@ -1,4 +1,3 @@ -use alloy_contract; use alloy_primitives::Address; use alloy_provider::Provider; use clap::Parser; @@ -7,8 +6,6 @@ use eigen_utils::{ get_provider, }; use serde::Serialize; -use serde_json; -use tokio; #[derive(Parser, Debug)] #[command( @@ -198,6 +195,7 @@ mod test { get_registry_coordinator_address, get_service_manager_address, }; use tokio; + #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; From 80e15df8109c11d9a93dc0cc068742f90100f49e Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Wed, 31 Jul 2024 19:04:29 -0300 Subject: [PATCH 05/36] add testing against sdk-go output --- crates/eigen-cli/egnaddrs.rs | 116 +++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 34 deletions(-) diff --git a/crates/eigen-cli/egnaddrs.rs b/crates/eigen-cli/egnaddrs.rs index 916d8637..de0b17b6 100644 --- a/crates/eigen-cli/egnaddrs.rs +++ b/crates/eigen-cli/egnaddrs.rs @@ -2,10 +2,10 @@ use alloy_primitives::Address; use alloy_provider::Provider; use clap::Parser; use eigen_utils::{ - binding::{ContractsRegistry, DelegationManager, IBLSSignatureChecker}, + binding::{DelegationManager, IBLSSignatureChecker, RegistryCoordinator}, get_provider, }; -use serde::Serialize; +use serde::{Deserialize, Serialize}; #[derive(Parser, Debug)] #[command( @@ -24,32 +24,38 @@ struct Args { rpc_url: String, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct EigenAddressesResponse { - network: NetworkInfo, - eigenlayer: EigenAddresses, avs: AvsAddresses, + eigenlayer: EigenAddresses, + network: NetworkInfo, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] pub struct NetworkInfo { + chain_id: String, rpc_url: String, - chain_id: u64, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] pub struct EigenAddresses { - slasher: Address, delegation_manager: Address, + slasher: Address, strategy_manager: Address, } -#[derive(Serialize)] +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] pub struct AvsAddresses { - service_manager: Address, - registry_coordinator: Address, bls_apk_registry: Address, index_registry: Address, + registry_coordinator: Address, + service_manager: Address, stake_registry: Address, } @@ -71,10 +77,9 @@ where N: alloy_contract::private::Network, { if let Some(registry_coord_addr) = args.registry_coordinator { - let contracts_registry = ContractsRegistry::new(registry_coord_addr, client); - - let service_manager_addr = contracts_registry - .contracts("mockAvsServiceManager".to_string()) + let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); + let service_manager_addr = registry_coordinator + .serviceManager() .call() .await .unwrap() @@ -133,27 +138,27 @@ where T: alloy_contract::private::Transport + ::core::clone::Clone, N: alloy_contract::private::Network, { - let contracts_registry = ContractsRegistry::new(registry_coord_addr, &client); - let service_manager_addr = contracts_registry - .contracts("ServiceManagerBase".to_string()) + let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); + let service_manager_addr = registry_coordinator + .serviceManager() .call() .await .unwrap() ._0; - let bls_pubkey_apk_addr = contracts_registry - .contracts("blsApkRegistry".to_string()) + let bls_pubkey_apk_addr = registry_coordinator + .blsApkRegistry() .call() .await .unwrap() ._0; - let index_registry_addr = contracts_registry - .contracts("indexRegistry".to_string()) + let index_registry_addr = registry_coordinator + .indexRegistry() .call() .await .unwrap() ._0; - let stake_registry_addr = contracts_registry - .contracts("stakeRegistry".to_string()) + let stake_registry_addr = registry_coordinator + .stakeRegistry() .call() .await .unwrap() @@ -171,11 +176,10 @@ where async fn get_addresses(args: Args) -> EigenAddressesResponse { let rpc_url = args.rpc_url.clone(); let client = get_provider(&rpc_url); - let chain_id = client.get_chain_id().await.unwrap(); + let chain_id = client.get_chain_id().await.unwrap().to_string(); let (registry_coord_addr, service_manager_addr) = get_registry_coord_and_service_manager_addr(args, client.clone()).await; let avs = get_avs_contract_addresses(registry_coord_addr, client.clone()).await; - let eigenlayer = get_eigenlayer_contract_addresses(service_manager_addr, client).await; let network = NetworkInfo { rpc_url, chain_id }; @@ -188,9 +192,7 @@ async fn get_addresses(args: Args) -> EigenAddressesResponse { #[cfg(test)] mod test { - use crate::get_addresses; - - use super::Args; + use super::{get_addresses, Args, EigenAddressesResponse}; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, }; @@ -199,26 +201,72 @@ mod test { #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; + let args = Args { registry_coordinator: None, service_manager: Some(service_manager_address), rpc_url: "http://localhost:8545".into(), }; + let expected_addresses: EigenAddressesResponse = serde_json::from_str( + r#"{ + "avs": { + "bls-apk-registry": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", + "index-registry": "0x851356ae760d987E095750cCeb3bC6014560891C", + "registry-coordinator": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", + "service-manager": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", + "stake-registry": "0xf5059a5D33d5853360D16C683c16e67980206f36" + }, + "eigenlayer": { + "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + }, + "network": { + "chain-id": "31337", + "rpc-url": "http://localhost:8545" + } + }"#, + ) + .unwrap(); + let addresses = get_addresses(args).await; - // TODO: add corresponding assert - assert!(true); + + assert_eq!(expected_addresses, addresses); } #[tokio::test] async fn egnaddrs_with_registry_coordinator_flag() { let registry_coordinator_address = get_registry_coordinator_address().await; + let args = Args { registry_coordinator: Some(registry_coordinator_address), service_manager: None, rpc_url: "http://localhost:8545".into(), }; + let expected_addresses: EigenAddressesResponse = serde_json::from_str( + r#"{ + "avs": { + "bls-apk-registry": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", + "index-registry": "0x851356ae760d987E095750cCeb3bC6014560891C", + "registry-coordinator": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", + "service-manager": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", + "stake-registry": "0xf5059a5D33d5853360D16C683c16e67980206f36" + }, + "eigenlayer": { + "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + }, + "network": { + "chain-id": "31337", + "rpc-url": "http://localhost:8545" + } + }"#, + ) + .unwrap(); + let addresses = get_addresses(args).await; - // TODO: add corresponding assert - assert!(true); + + assert_eq!(expected_addresses, addresses); } } From 2a81e79d542b236cd76835e644d96de11fdf769d Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 1 Aug 2024 14:44:42 -0300 Subject: [PATCH 06/36] add error handling and reorganize eigen-cli crate --- Cargo.lock | 30 ++-- Cargo.toml | 1 + crates/eigen-cli/Cargo.toml | 12 +- crates/eigen-cli/src/args.rs | 21 +++ crates/eigen-cli/src/bin/egnaddrs.rs | 10 ++ crates/eigen-cli/{egnaddrs.rs => src/lib.rs} | 162 +++++++------------ 6 files changed, 115 insertions(+), 121 deletions(-) create mode 100644 crates/eigen-cli/src/args.rs create mode 100644 crates/eigen-cli/src/bin/egnaddrs.rs rename crates/eigen-cli/{egnaddrs.rs => src/lib.rs} (59%) diff --git a/Cargo.lock b/Cargo.lock index 00f7df7a..084e09b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1451,6 +1451,21 @@ dependencies = [ "eigen-utils", ] +[[package]] +name = "eigen-cli" +version = "0.0.1-alpha" +dependencies = [ + "alloy-contract", + "alloy-primitives", + "alloy-provider", + "clap", + "eigen-testing-utils", + "eigen-utils", + "serde", + "serde_json", + "tokio", +] + [[package]] name = "eigen-client-avsregistry" version = "0.0.1-alpha" @@ -1563,21 +1578,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "eigen-eigen-cli" -version = "0.0.1-alpha" -dependencies = [ - "alloy-contract", - "alloy-primitives", - "alloy-provider", - "clap", - "eigen-testing-utils", - "eigen-utils", - "serde", - "serde_json", - "tokio", -] - [[package]] name = "eigen-logging" version = "0.0.1-alpha" diff --git a/Cargo.toml b/Cargo.toml index 1e181e29..c6923be2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -94,6 +94,7 @@ eth-keystore = "0.5.0" hex-literal = "0.4.1" k256 = "0.13.3" serde_json = "1.0.121" +clap = { version = "4.5.11", features = ["derive"] } #misc parking_lot = "0.12" diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index f5bbf2a5..384b7cdc 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -1,21 +1,21 @@ [package] -name = "eigen-eigen-cli" +name = "eigen-cli" version.workspace = true edition.workspace = true rust-version.workspace = true repository.workspace = true [dependencies] -clap = { version = "4.5.11", features = ["derive"] } alloy-primitives.workspace = true -tokio.workspace = true -eigen-utils.workspace = true -eigen-testing-utils.workspace = true alloy-provider.workspace = true alloy-contract.workspace = true +clap.workspace = true +eigen-testing-utils.workspace = true +eigen-utils.workspace = true serde.workspace = true serde_json.workspace = true +tokio.workspace = true [[bin]] name = "egnaddrs" -path = "egnaddrs.rs" +path = "src/bin/egnaddrs.rs" diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs new file mode 100644 index 00000000..7a5fdbbb --- /dev/null +++ b/crates/eigen-cli/src/args.rs @@ -0,0 +1,21 @@ +use crate::ANVIL_RPC_URL; +use alloy_primitives::Address; +use clap::Parser; + +#[derive(Parser, Debug)] +#[command( + version, + about = "Used to help debug and test deployments and contract setups.", + long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." +)] + +pub struct Args { + #[arg(long, help = "ServiceManager contract address")] + pub service_manager: Option
, + + #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] + pub registry_coordinator: Option
, + + #[arg(long, help = "rpc url", default_value = ANVIL_RPC_URL)] + pub rpc_url: String, +} diff --git a/crates/eigen-cli/src/bin/egnaddrs.rs b/crates/eigen-cli/src/bin/egnaddrs.rs new file mode 100644 index 00000000..dbadfa78 --- /dev/null +++ b/crates/eigen-cli/src/bin/egnaddrs.rs @@ -0,0 +1,10 @@ +use clap::Parser; +use eigen_cli::{args::Args, get_addresses}; + +#[tokio::main] +async fn main() { + let args = Args::parse(); + let addresses = get_addresses(args).await.unwrap(); + + println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); +} diff --git a/crates/eigen-cli/egnaddrs.rs b/crates/eigen-cli/src/lib.rs similarity index 59% rename from crates/eigen-cli/egnaddrs.rs rename to crates/eigen-cli/src/lib.rs index de0b17b6..a162870c 100644 --- a/crates/eigen-cli/egnaddrs.rs +++ b/crates/eigen-cli/src/lib.rs @@ -1,28 +1,15 @@ +use crate::args::Args; +use alloy_contract::Error as ContractError; use alloy_primitives::Address; use alloy_provider::Provider; -use clap::Parser; use eigen_utils::{ binding::{DelegationManager, IBLSSignatureChecker, RegistryCoordinator}, get_provider, }; use serde::{Deserialize, Serialize}; +pub mod args; -#[derive(Parser, Debug)] -#[command( - version, - about = "Used to help debug and test deployments and contract setups.", - long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." -)] -struct Args { - #[arg(long, help = "ServiceManager contract address")] - service_manager: Option
, - - #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] - registry_coordinator: Option
, - - #[arg(long, help = "rpc url", default_value = "http://localhost:8545")] - rpc_url: String, -} +pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct EigenAddressesResponse { @@ -59,145 +46,121 @@ pub struct AvsAddresses { stake_registry: Address, } -#[tokio::main] -async fn main() { - let args = Args::parse(); - let addresses = get_addresses(args).await; - - println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); -} - async fn get_registry_coord_and_service_manager_addr( args: Args, client: P, -) -> (Address, Address) +) -> Result<(Address, Address), ContractError> where T: alloy_contract::private::Transport + ::core::clone::Clone, P: alloy_contract::private::Provider, N: alloy_contract::private::Network, { - if let Some(registry_coord_addr) = args.registry_coordinator { - let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); - let service_manager_addr = registry_coordinator - .serviceManager() - .call() - .await - .unwrap() - ._0; - - (registry_coord_addr, service_manager_addr) - } else if let Some(service_manager_addr) = args.service_manager { - let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); - let registry_coord_addr = service_manager - .registryCoordinator() - .call() - .await - .unwrap() - ._0; - - (registry_coord_addr, service_manager_addr) - } else { - // raise error - panic!() + match (args.registry_coordinator, args.service_manager) { + (Some(registry_coord_addr), _) => { + let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); + let service_manager_addr = registry_coordinator.serviceManager().call().await?._0; + Ok((registry_coord_addr, service_manager_addr)) + } + (_, Some(service_manager_addr)) => { + let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); + let registry_coord_addr = service_manager.registryCoordinator().call().await?._0; + Ok((registry_coord_addr, service_manager_addr)) + } + _ => { + // TODO: fix this adding a new Error type + panic!("must provide either --registry-coordinator or --service-manager flag") + } } } async fn get_eigenlayer_contract_addresses( service_manager_addr: Address, client: P, -) -> EigenAddresses +) -> Result where P: alloy_contract::private::Provider, T: alloy_contract::private::Transport + ::core::clone::Clone, N: alloy_contract::private::Network, { let service_manager = IBLSSignatureChecker::new(service_manager_addr, &client); - let delegation_manager_addr = service_manager.delegation().call().await.unwrap()._0; - let delegation_manager_client = DelegationManager::new(delegation_manager_addr, &client); - let slasher_addr = delegation_manager_client.slasher().call().await.unwrap()._0; - let strategy_manager_addr = delegation_manager_client - .strategyManager() - .call() - .await - .unwrap() - ._0; - - EigenAddresses { - slasher: slasher_addr, - delegation_manager: delegation_manager_addr, - strategy_manager: strategy_manager_addr, - } + let delegation_manager = service_manager.delegation().call().await?._0; + let delegation_manager_client = DelegationManager::new(delegation_manager, &client); + let slasher = delegation_manager_client.slasher().call().await?._0; + let strategy_manager = delegation_manager_client.strategyManager().call().await?._0; + + Ok(EigenAddresses { + slasher, + delegation_manager, + strategy_manager, + }) } async fn get_avs_contract_addresses( - registry_coord_addr: Address, + registry_coordinator: Address, client: P, -) -> AvsAddresses +) -> Result where P: alloy_contract::private::Provider, T: alloy_contract::private::Transport + ::core::clone::Clone, N: alloy_contract::private::Network, { - let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); - let service_manager_addr = registry_coordinator + let registry_coordinator_instance = RegistryCoordinator::new(registry_coordinator, &client); + let service_manager = registry_coordinator_instance .serviceManager() .call() - .await - .unwrap() + .await? ._0; - let bls_pubkey_apk_addr = registry_coordinator + let bls_apk_registry = registry_coordinator_instance .blsApkRegistry() .call() - .await - .unwrap() + .await? ._0; - let index_registry_addr = registry_coordinator + let index_registry = registry_coordinator_instance .indexRegistry() .call() - .await - .unwrap() + .await? ._0; - let stake_registry_addr = registry_coordinator + let stake_registry = registry_coordinator_instance .stakeRegistry() .call() - .await - .unwrap() + .await? ._0; - AvsAddresses { - service_manager: service_manager_addr, - registry_coordinator: registry_coord_addr, - bls_apk_registry: bls_pubkey_apk_addr, - index_registry: index_registry_addr, - stake_registry: stake_registry_addr, - } + Ok(AvsAddresses { + service_manager, + registry_coordinator, + bls_apk_registry, + index_registry, + stake_registry, + }) } -async fn get_addresses(args: Args) -> EigenAddressesResponse { +pub async fn get_addresses(args: Args) -> Result { let rpc_url = args.rpc_url.clone(); let client = get_provider(&rpc_url); - let chain_id = client.get_chain_id().await.unwrap().to_string(); + let chain_id = client.get_chain_id().await?.to_string(); let (registry_coord_addr, service_manager_addr) = - get_registry_coord_and_service_manager_addr(args, client.clone()).await; - let avs = get_avs_contract_addresses(registry_coord_addr, client.clone()).await; - let eigenlayer = get_eigenlayer_contract_addresses(service_manager_addr, client).await; + get_registry_coord_and_service_manager_addr(args, client.clone()).await?; + let avs = get_avs_contract_addresses(registry_coord_addr, client.clone()).await?; + let eigenlayer = get_eigenlayer_contract_addresses(service_manager_addr, client).await?; let network = NetworkInfo { rpc_url, chain_id }; - EigenAddressesResponse { + Ok(EigenAddressesResponse { network, eigenlayer, avs, - } + }) } #[cfg(test)] mod test { - use super::{get_addresses, Args, EigenAddressesResponse}; + use super::{get_addresses, Args, EigenAddressesResponse, ANVIL_RPC_URL}; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, }; use tokio; + // TODO: start anvil with the right deployed state #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; @@ -205,7 +168,7 @@ mod test { let args = Args { registry_coordinator: None, service_manager: Some(service_manager_address), - rpc_url: "http://localhost:8545".into(), + rpc_url: ANVIL_RPC_URL.into(), }; let expected_addresses: EigenAddressesResponse = serde_json::from_str( r#"{ @@ -228,8 +191,7 @@ mod test { }"#, ) .unwrap(); - - let addresses = get_addresses(args).await; + let addresses = get_addresses(args).await.unwrap(); assert_eq!(expected_addresses, addresses); } @@ -241,7 +203,7 @@ mod test { let args = Args { registry_coordinator: Some(registry_coordinator_address), service_manager: None, - rpc_url: "http://localhost:8545".into(), + rpc_url: ANVIL_RPC_URL.into(), }; let expected_addresses: EigenAddressesResponse = serde_json::from_str( r#"{ @@ -265,7 +227,7 @@ mod test { ) .unwrap(); - let addresses = get_addresses(args).await; + let addresses = get_addresses(args).await.unwrap(); assert_eq!(expected_addresses, addresses); } From 7d1fadddfe5684038f452d8faf5b400fbb5d5b42 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 1 Aug 2024 15:33:24 -0300 Subject: [PATCH 07/36] add EigenAddressCliError type and reorganize egnaddrs crate (remove egnaddr bin) --- Cargo.lock | 3 + crates/eigen-cli/Cargo.toml | 9 +- crates/eigen-cli/src/eigen_address.rs | 173 ++++++++++++++++++ crates/eigen-cli/src/lib.rs | 168 ++--------------- .../src/{bin/egnaddrs.rs => main.rs} | 4 +- 5 files changed, 200 insertions(+), 157 deletions(-) create mode 100644 crates/eigen-cli/src/eigen_address.rs rename crates/eigen-cli/src/{bin/egnaddrs.rs => main.rs} (54%) diff --git a/Cargo.lock b/Cargo.lock index 084e09b6..69434297 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1456,13 +1456,16 @@ name = "eigen-cli" version = "0.0.1-alpha" dependencies = [ "alloy-contract", + "alloy-json-rpc", "alloy-primitives", "alloy-provider", + "alloy-transport", "clap", "eigen-testing-utils", "eigen-utils", "serde", "serde_json", + "thiserror", "tokio", ] diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index 384b7cdc..6bc3a992 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -6,16 +6,15 @@ rust-version.workspace = true repository.workspace = true [dependencies] +alloy-contract.workspace = true +alloy-json-rpc.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true -alloy-contract.workspace = true +alloy-transport.workspace = true clap.workspace = true eigen-testing-utils.workspace = true eigen-utils.workspace = true serde.workspace = true serde_json.workspace = true +thiserror.workspace = true tokio.workspace = true - -[[bin]] -name = "egnaddrs" -path = "src/bin/egnaddrs.rs" diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/src/eigen_address.rs new file mode 100644 index 00000000..df120e13 --- /dev/null +++ b/crates/eigen-cli/src/eigen_address.rs @@ -0,0 +1,173 @@ +use crate::args::Args; +use crate::EigenAddressCliError; +use alloy_contract::Error as ContractError; +use alloy_primitives::Address; +use alloy_provider::Provider; +use eigen_utils::{ + binding::{DelegationManager, IBLSSignatureChecker, RegistryCoordinator}, + get_provider, +}; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] +pub struct EigenAddresses { + delegation_manager: Address, + slasher: Address, + strategy_manager: Address, +} +#[derive(Serialize, Deserialize, Debug, PartialEq)] +pub struct EigenAddressesResponse { + avs: AvsAddresses, + eigenlayer: EigenAddresses, + network: NetworkInfo, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] +pub struct NetworkInfo { + chain_id: String, + rpc_url: String, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq)] +#[serde(rename_all(serialize = "kebab-case"))] +#[serde(rename_all(deserialize = "kebab-case"))] +pub struct AvsAddresses { + bls_apk_registry: Address, + index_registry: Address, + registry_coordinator: Address, + service_manager: Address, + stake_registry: Address, +} + +impl EigenAddresses { + async fn get_registry_coord_and_service_manager_addr( + args: Args, + client: P, + ) -> Result<(Address, Address), EigenAddressCliError> + where + T: alloy_contract::private::Transport + ::core::clone::Clone, + P: alloy_contract::private::Provider, + N: alloy_contract::private::Network, + { + match (args.registry_coordinator, args.service_manager) { + (Some(registry_coord_addr), _) => { + let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); + let service_manager_addr = registry_coordinator + .serviceManager() + .call() + .await + .map_err(|e| EigenAddressCliError::ContractError(e))? + ._0; + Ok((registry_coord_addr, service_manager_addr)) + } + (_, Some(service_manager_addr)) => { + let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); + let registry_coord_addr = service_manager + .registryCoordinator() + .call() + .await + .map_err(|e| EigenAddressCliError::ContractError(e))? + ._0; + Ok((registry_coord_addr, service_manager_addr)) + } + _ => Err(EigenAddressCliError::MissingArgs( + "must provide either --registry-coordinator or --service-manager flag".into(), + )), + } + } + + async fn get_eigenlayer_contract_addresses( + service_manager_addr: Address, + client: P, + ) -> Result + where + P: alloy_contract::private::Provider, + T: alloy_contract::private::Transport + ::core::clone::Clone, + N: alloy_contract::private::Network, + { + let service_manager = IBLSSignatureChecker::new(service_manager_addr, &client); + let delegation_manager = service_manager.delegation().call().await?._0; + let delegation_manager_client = DelegationManager::new(delegation_manager, &client); + let slasher = delegation_manager_client.slasher().call().await?._0; + let strategy_manager = delegation_manager_client.strategyManager().call().await?._0; + + Ok(EigenAddresses { + slasher, + delegation_manager, + strategy_manager, + }) + } + + async fn get_avs_contract_addresses( + registry_coordinator: Address, + client: P, + ) -> Result + where + P: alloy_contract::private::Provider, + T: alloy_contract::private::Transport + ::core::clone::Clone, + N: alloy_contract::private::Network, + { + let registry_coordinator_instance = RegistryCoordinator::new(registry_coordinator, &client); + let service_manager = registry_coordinator_instance + .serviceManager() + .call() + .await? + ._0; + let bls_apk_registry = registry_coordinator_instance + .blsApkRegistry() + .call() + .await? + ._0; + let index_registry = registry_coordinator_instance + .indexRegistry() + .call() + .await? + ._0; + let stake_registry = registry_coordinator_instance + .stakeRegistry() + .call() + .await? + ._0; + + Ok(AvsAddresses { + service_manager, + registry_coordinator, + bls_apk_registry, + index_registry, + stake_registry, + }) + } + + pub async fn get_addresses(args: Args) -> Result { + let rpc_url = args.rpc_url.clone(); + let client = get_provider(&rpc_url); + let chain_id = client + .get_chain_id() + .await + .map_err(|e| EigenAddressCliError::RpcError(e))? + .to_string(); + let (registry_coord_addr, service_manager_addr) = + EigenAddresses::get_registry_coord_and_service_manager_addr(args, client.clone()) + .await?; + + let avs = EigenAddresses::get_avs_contract_addresses(registry_coord_addr, client.clone()) + .await + .map_err(|e| EigenAddressCliError::ContractError(e))?; + + let eigenlayer = + EigenAddresses::get_eigenlayer_contract_addresses(service_manager_addr, client) + .await + .map_err(|e| EigenAddressCliError::ContractError(e))?; + + let network = NetworkInfo { rpc_url, chain_id }; + Ok(EigenAddressesResponse { + network, + eigenlayer, + avs, + }) + } +} diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index a162870c..4fdaea62 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -1,160 +1,28 @@ -use crate::args::Args; use alloy_contract::Error as ContractError; -use alloy_primitives::Address; -use alloy_provider::Provider; -use eigen_utils::{ - binding::{DelegationManager, IBLSSignatureChecker, RegistryCoordinator}, - get_provider, -}; -use serde::{Deserialize, Serialize}; +use alloy_json_rpc::RpcError; +use alloy_transport::TransportErrorKind; +use thiserror::Error; pub mod args; +pub mod eigen_address; pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; -#[derive(Serialize, Deserialize, Debug, PartialEq)] -pub struct EigenAddressesResponse { - avs: AvsAddresses, - eigenlayer: EigenAddresses, - network: NetworkInfo, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct NetworkInfo { - chain_id: String, - rpc_url: String, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct EigenAddresses { - delegation_manager: Address, - slasher: Address, - strategy_manager: Address, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct AvsAddresses { - bls_apk_registry: Address, - index_registry: Address, - registry_coordinator: Address, - service_manager: Address, - stake_registry: Address, -} - -async fn get_registry_coord_and_service_manager_addr( - args: Args, - client: P, -) -> Result<(Address, Address), ContractError> -where - T: alloy_contract::private::Transport + ::core::clone::Clone, - P: alloy_contract::private::Provider, - N: alloy_contract::private::Network, -{ - match (args.registry_coordinator, args.service_manager) { - (Some(registry_coord_addr), _) => { - let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); - let service_manager_addr = registry_coordinator.serviceManager().call().await?._0; - Ok((registry_coord_addr, service_manager_addr)) - } - (_, Some(service_manager_addr)) => { - let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); - let registry_coord_addr = service_manager.registryCoordinator().call().await?._0; - Ok((registry_coord_addr, service_manager_addr)) - } - _ => { - // TODO: fix this adding a new Error type - panic!("must provide either --registry-coordinator or --service-manager flag") - } - } -} - -async fn get_eigenlayer_contract_addresses( - service_manager_addr: Address, - client: P, -) -> Result -where - P: alloy_contract::private::Provider, - T: alloy_contract::private::Transport + ::core::clone::Clone, - N: alloy_contract::private::Network, -{ - let service_manager = IBLSSignatureChecker::new(service_manager_addr, &client); - let delegation_manager = service_manager.delegation().call().await?._0; - let delegation_manager_client = DelegationManager::new(delegation_manager, &client); - let slasher = delegation_manager_client.slasher().call().await?._0; - let strategy_manager = delegation_manager_client.strategyManager().call().await?._0; - - Ok(EigenAddresses { - slasher, - delegation_manager, - strategy_manager, - }) -} - -async fn get_avs_contract_addresses( - registry_coordinator: Address, - client: P, -) -> Result -where - P: alloy_contract::private::Provider, - T: alloy_contract::private::Transport + ::core::clone::Clone, - N: alloy_contract::private::Network, -{ - let registry_coordinator_instance = RegistryCoordinator::new(registry_coordinator, &client); - let service_manager = registry_coordinator_instance - .serviceManager() - .call() - .await? - ._0; - let bls_apk_registry = registry_coordinator_instance - .blsApkRegistry() - .call() - .await? - ._0; - let index_registry = registry_coordinator_instance - .indexRegistry() - .call() - .await? - ._0; - let stake_registry = registry_coordinator_instance - .stakeRegistry() - .call() - .await? - ._0; - - Ok(AvsAddresses { - service_manager, - registry_coordinator, - bls_apk_registry, - index_registry, - stake_registry, - }) -} - -pub async fn get_addresses(args: Args) -> Result { - let rpc_url = args.rpc_url.clone(); - let client = get_provider(&rpc_url); - let chain_id = client.get_chain_id().await?.to_string(); - let (registry_coord_addr, service_manager_addr) = - get_registry_coord_and_service_manager_addr(args, client.clone()).await?; - let avs = get_avs_contract_addresses(registry_coord_addr, client.clone()).await?; - let eigenlayer = get_eigenlayer_contract_addresses(service_manager_addr, client).await?; - - let network = NetworkInfo { rpc_url, chain_id }; - Ok(EigenAddressesResponse { - network, - eigenlayer, - avs, - }) +/// Possible errors raised while trying to get contract addresses +#[derive(Error, Debug)] +pub enum EigenAddressCliError { + #[error("missing arguments error")] + MissingArgs(String), + #[error("contract error")] + ContractError(ContractError), + #[error("RPC error")] + RpcError(RpcError), } #[cfg(test)] mod test { - use super::{get_addresses, Args, EigenAddressesResponse, ANVIL_RPC_URL}; + use super::ANVIL_RPC_URL; + use crate::args::Args; + use crate::eigen_address::{EigenAddresses, EigenAddressesResponse}; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, }; @@ -191,7 +59,7 @@ mod test { }"#, ) .unwrap(); - let addresses = get_addresses(args).await.unwrap(); + let addresses = EigenAddresses::get_addresses(args).await.unwrap(); assert_eq!(expected_addresses, addresses); } @@ -227,7 +95,7 @@ mod test { ) .unwrap(); - let addresses = get_addresses(args).await.unwrap(); + let addresses = EigenAddresses::get_addresses(args).await.unwrap(); assert_eq!(expected_addresses, addresses); } diff --git a/crates/eigen-cli/src/bin/egnaddrs.rs b/crates/eigen-cli/src/main.rs similarity index 54% rename from crates/eigen-cli/src/bin/egnaddrs.rs rename to crates/eigen-cli/src/main.rs index dbadfa78..cfd62f9f 100644 --- a/crates/eigen-cli/src/bin/egnaddrs.rs +++ b/crates/eigen-cli/src/main.rs @@ -1,10 +1,10 @@ use clap::Parser; -use eigen_cli::{args::Args, get_addresses}; +use eigen_cli::{args::Args, eigen_address::EigenAddresses}; #[tokio::main] async fn main() { let args = Args::parse(); - let addresses = get_addresses(args).await.unwrap(); + let addresses = EigenAddresses::get_addresses(args).await.unwrap(); println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); } From f70121daf5633bb7f6aea58cf2e246204ccbbb69 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 1 Aug 2024 17:28:55 -0300 Subject: [PATCH 08/36] add documentation to functions and fixing spaces --- crates/eigen-cli/src/args.rs | 1 - crates/eigen-cli/src/eigen_address.rs | 99 +++++++++++++++++++-------- 2 files changed, 70 insertions(+), 30 deletions(-) diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index 7a5fdbbb..82a39773 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -8,7 +8,6 @@ use clap::Parser; about = "Used to help debug and test deployments and contract setups.", long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." )] - pub struct Args { #[arg(long, help = "ServiceManager contract address")] pub service_manager: Option
, diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/src/eigen_address.rs index df120e13..7a450b41 100644 --- a/crates/eigen-cli/src/eigen_address.rs +++ b/crates/eigen-cli/src/eigen_address.rs @@ -17,6 +17,7 @@ pub struct EigenAddresses { slasher: Address, strategy_manager: Address, } + #[derive(Serialize, Deserialize, Debug, PartialEq)] pub struct EigenAddressesResponse { avs: AvsAddresses, @@ -44,6 +45,55 @@ pub struct AvsAddresses { } impl EigenAddresses { + /// Public function to get the Eigenlayer and AVS contract addresses. + /// + /// # Arguments + /// + /// * `args` - The command line arguments. + /// + /// # Returns + /// + /// * `EigenAddressesResponse` - The Eigenlayer and AVS contract addresses. + pub async fn get_addresses(args: Args) -> Result { + let rpc_url = args.rpc_url.clone(); + let client = get_provider(&rpc_url); + let chain_id = client + .get_chain_id() + .await + .map_err(|e| EigenAddressCliError::RpcError(e))? + .to_string(); + let (registry_coord_addr, service_manager_addr) = + EigenAddresses::get_registry_coord_and_service_manager_addr(args, client.clone()) + .await?; + + let avs = EigenAddresses::get_avs_contract_addresses(registry_coord_addr, client.clone()) + .await + .map_err(|e| EigenAddressCliError::ContractError(e))?; + + let eigenlayer = + EigenAddresses::get_eigenlayer_contract_addresses(service_manager_addr, client) + .await + .map_err(|e| EigenAddressCliError::ContractError(e))?; + + let network = NetworkInfo { rpc_url, chain_id }; + Ok(EigenAddressesResponse { + network, + eigenlayer, + avs, + }) + } + + /// Get the registry coordinator and service manager contract addresses. + /// + /// # Arguments + /// + /// * `args` - The command line arguments. + /// * `client` - The provider client. + /// + /// # Returns + /// + /// * `(Address, Address)` - The registry coordinator and service manager contract addresses, + /// used to call `get_avs_contract_addresses` and `get_eigenlayer_contract_addresses` functions. async fn get_registry_coord_and_service_manager_addr( args: Args, client: P, @@ -80,6 +130,16 @@ impl EigenAddresses { } } + /// Get the Eigenlayer contract addresses. + /// + /// # Arguments + /// + /// * `service_manager_addr` - The service manager contract address. + /// * `client` - The provider client. + /// + /// # Returns + /// + /// * `EigenAddresses` - The Eigenlayer contract addresses. async fn get_eigenlayer_contract_addresses( service_manager_addr: Address, client: P, @@ -102,6 +162,16 @@ impl EigenAddresses { }) } + /// Get the AVS contract addresses. + /// + /// # Arguments + /// + /// * `registry_coordinator` - The registry coordinator contract address. + /// * `client` - The provider client. + /// + /// # Returns + /// + /// * `AvsAddresses` - The AVS contract addresses. async fn get_avs_contract_addresses( registry_coordinator: Address, client: P, @@ -141,33 +211,4 @@ impl EigenAddresses { stake_registry, }) } - - pub async fn get_addresses(args: Args) -> Result { - let rpc_url = args.rpc_url.clone(); - let client = get_provider(&rpc_url); - let chain_id = client - .get_chain_id() - .await - .map_err(|e| EigenAddressCliError::RpcError(e))? - .to_string(); - let (registry_coord_addr, service_manager_addr) = - EigenAddresses::get_registry_coord_and_service_manager_addr(args, client.clone()) - .await?; - - let avs = EigenAddresses::get_avs_contract_addresses(registry_coord_addr, client.clone()) - .await - .map_err(|e| EigenAddressCliError::ContractError(e))?; - - let eigenlayer = - EigenAddresses::get_eigenlayer_contract_addresses(service_manager_addr, client) - .await - .map_err(|e| EigenAddressCliError::ContractError(e))?; - - let network = NetworkInfo { rpc_url, chain_id }; - Ok(EigenAddressesResponse { - network, - eigenlayer, - avs, - }) - } } From 3d672f59579501b0c52b622eca179d79ea32cdb4 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 2 Aug 2024 12:23:03 -0300 Subject: [PATCH 09/36] add param checking with clap --- crates/eigen-cli/src/args.rs | 7 ++++++- crates/eigen-cli/src/eigen_address.rs | 4 +--- crates/eigen-cli/src/lib.rs | 2 -- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index 82a39773..3104de88 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -1,8 +1,13 @@ use crate::ANVIL_RPC_URL; use alloy_primitives::Address; -use clap::Parser; +use clap::{ArgGroup, Parser}; #[derive(Parser, Debug)] +#[command(group( + ArgGroup::new("manager_or_coordinator") + .required(true) + .args(&["service_manager", "registry_coordinator"]), +))] #[command( version, about = "Used to help debug and test deployments and contract setups.", diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/src/eigen_address.rs index 7a450b41..2c0613d5 100644 --- a/crates/eigen-cli/src/eigen_address.rs +++ b/crates/eigen-cli/src/eigen_address.rs @@ -124,9 +124,7 @@ impl EigenAddresses { ._0; Ok((registry_coord_addr, service_manager_addr)) } - _ => Err(EigenAddressCliError::MissingArgs( - "must provide either --registry-coordinator or --service-manager flag".into(), - )), + _ => unreachable!(), } } diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 4fdaea62..278e4b63 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -10,8 +10,6 @@ pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; /// Possible errors raised while trying to get contract addresses #[derive(Error, Debug)] pub enum EigenAddressCliError { - #[error("missing arguments error")] - MissingArgs(String), #[error("contract error")] ContractError(ContractError), #[error("RPC error")] From 6cca229ec8f51b979584b4fed96ffe747c050512 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 2 Aug 2024 12:28:01 -0300 Subject: [PATCH 10/36] update tests expected result and rename addresses structs --- crates/eigen-cli/src/eigen_address.rs | 36 +++++++++++++-------------- crates/eigen-cli/src/lib.rs | 26 +++++++++---------- 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/src/eigen_address.rs index 2c0613d5..941a95f3 100644 --- a/crates/eigen-cli/src/eigen_address.rs +++ b/crates/eigen-cli/src/eigen_address.rs @@ -9,22 +9,22 @@ use eigen_utils::{ }; use serde::{Deserialize, Serialize}; +#[derive(Serialize, Deserialize, Debug, PartialEq)] +pub struct EigenAddresses { + avs: AvsAddresses, + eigenlayer: EigenLayerAddresses, + network: NetworkInfo, +} + #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all(serialize = "kebab-case"))] #[serde(rename_all(deserialize = "kebab-case"))] -pub struct EigenAddresses { +pub struct EigenLayerAddresses { delegation_manager: Address, slasher: Address, strategy_manager: Address, } -#[derive(Serialize, Deserialize, Debug, PartialEq)] -pub struct EigenAddressesResponse { - avs: AvsAddresses, - eigenlayer: EigenAddresses, - network: NetworkInfo, -} - #[derive(Serialize, Deserialize, Debug, PartialEq)] #[serde(rename_all(serialize = "kebab-case"))] #[serde(rename_all(deserialize = "kebab-case"))] @@ -53,14 +53,14 @@ impl EigenAddresses { /// /// # Returns /// - /// * `EigenAddressesResponse` - The Eigenlayer and AVS contract addresses. - pub async fn get_addresses(args: Args) -> Result { + /// * `EigenAddresses` - The Eigenlayer and AVS contract addresses. + pub async fn get_addresses(args: Args) -> Result { let rpc_url = args.rpc_url.clone(); let client = get_provider(&rpc_url); let chain_id = client .get_chain_id() .await - .map_err(|e| EigenAddressCliError::RpcError(e))? + .map_err(EigenAddressCliError::RpcError)? .to_string(); let (registry_coord_addr, service_manager_addr) = EigenAddresses::get_registry_coord_and_service_manager_addr(args, client.clone()) @@ -68,15 +68,15 @@ impl EigenAddresses { let avs = EigenAddresses::get_avs_contract_addresses(registry_coord_addr, client.clone()) .await - .map_err(|e| EigenAddressCliError::ContractError(e))?; + .map_err(EigenAddressCliError::ContractError)?; let eigenlayer = EigenAddresses::get_eigenlayer_contract_addresses(service_manager_addr, client) .await - .map_err(|e| EigenAddressCliError::ContractError(e))?; + .map_err(EigenAddressCliError::ContractError)?; let network = NetworkInfo { rpc_url, chain_id }; - Ok(EigenAddressesResponse { + Ok(EigenAddresses { network, eigenlayer, avs, @@ -110,7 +110,7 @@ impl EigenAddresses { .serviceManager() .call() .await - .map_err(|e| EigenAddressCliError::ContractError(e))? + .map_err(EigenAddressCliError::ContractError)? ._0; Ok((registry_coord_addr, service_manager_addr)) } @@ -120,7 +120,7 @@ impl EigenAddresses { .registryCoordinator() .call() .await - .map_err(|e| EigenAddressCliError::ContractError(e))? + .map_err(EigenAddressCliError::ContractError)? ._0; Ok((registry_coord_addr, service_manager_addr)) } @@ -141,7 +141,7 @@ impl EigenAddresses { async fn get_eigenlayer_contract_addresses( service_manager_addr: Address, client: P, - ) -> Result + ) -> Result where P: alloy_contract::private::Provider, T: alloy_contract::private::Transport + ::core::clone::Clone, @@ -153,7 +153,7 @@ impl EigenAddresses { let slasher = delegation_manager_client.slasher().call().await?._0; let strategy_manager = delegation_manager_client.strategyManager().call().await?._0; - Ok(EigenAddresses { + Ok(EigenLayerAddresses { slasher, delegation_manager, strategy_manager, diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 278e4b63..b18c64a1 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -20,7 +20,7 @@ pub enum EigenAddressCliError { mod test { use super::ANVIL_RPC_URL; use crate::args::Args; - use crate::eigen_address::{EigenAddresses, EigenAddressesResponse}; + use crate::eigen_address::EigenAddresses; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, }; @@ -36,14 +36,14 @@ mod test { service_manager: Some(service_manager_address), rpc_url: ANVIL_RPC_URL.into(), }; - let expected_addresses: EigenAddressesResponse = serde_json::from_str( + let expected_addresses: EigenAddresses = serde_json::from_str( r#"{ "avs": { - "bls-apk-registry": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", - "index-registry": "0x851356ae760d987E095750cCeb3bC6014560891C", - "registry-coordinator": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", - "service-manager": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", - "stake-registry": "0xf5059a5D33d5853360D16C683c16e67980206f36" + "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", + "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", + "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", + "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", + "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" }, "eigenlayer": { "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", @@ -71,14 +71,14 @@ mod test { service_manager: None, rpc_url: ANVIL_RPC_URL.into(), }; - let expected_addresses: EigenAddressesResponse = serde_json::from_str( + let expected_addresses: EigenAddresses = serde_json::from_str( r#"{ "avs": { - "bls-apk-registry": "0x1613beB3B2C4f22Ee086B2b38C1476A3cE7f78E8", - "index-registry": "0x851356ae760d987E095750cCeb3bC6014560891C", - "registry-coordinator": "0xa82fF9aFd8f496c3d6ac40E2a0F282E47488CFc9", - "service-manager": "0x84eA74d481Ee0A5332c457a4d796187F6Ba67fEB", - "stake-registry": "0xf5059a5D33d5853360D16C683c16e67980206f36" + "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", + "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", + "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", + "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", + "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" }, "eigenlayer": { "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", From 6b65333abf0d320ff6ac5c0da9cce6e8e9a686f0 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 2 Aug 2024 12:28:39 -0300 Subject: [PATCH 11/36] remove todo --- crates/eigen-cli/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index b18c64a1..8e786096 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -26,7 +26,6 @@ mod test { }; use tokio; - // TODO: start anvil with the right deployed state #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; From ad2f495927314ab62e17a4a34762d857f333f434 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 2 Aug 2024 12:42:20 -0300 Subject: [PATCH 12/36] add doc attribute in lib.rs --- crates/eigen-cli/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 8e786096..1bb54197 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -1,3 +1,7 @@ +#![doc( + html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", + issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" +)] use alloy_contract::Error as ContractError; use alloy_json_rpc::RpcError; use alloy_transport::TransportErrorKind; From fb718d4f1394b4029ebc56ed2337bfe9281e878c Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 2 Aug 2024 17:40:14 -0300 Subject: [PATCH 13/36] add egnkey initial implementation --- Cargo.lock | 35 +++++- Cargo.toml | 3 +- crates/eigen-cli/{ => egnaddrs}/Cargo.toml | 2 +- crates/eigen-cli/{ => egnaddrs}/src/args.rs | 0 .../{ => egnaddrs}/src/eigen_address.rs | 0 crates/eigen-cli/{ => egnaddrs}/src/lib.rs | 68 +++++----- crates/eigen-cli/{ => egnaddrs}/src/main.rs | 2 +- crates/eigen-cli/egnkey/Cargo.toml | 22 ++++ crates/eigen-cli/egnkey/src/args.rs | 71 +++++++++++ crates/eigen-cli/egnkey/src/generate.rs | 117 ++++++++++++++++++ crates/eigen-cli/egnkey/src/lib.rs | 20 +++ crates/eigen-cli/egnkey/src/main.rs | 8 ++ 12 files changed, 305 insertions(+), 43 deletions(-) rename crates/eigen-cli/{ => egnaddrs}/Cargo.toml (96%) rename crates/eigen-cli/{ => egnaddrs}/src/args.rs (100%) rename crates/eigen-cli/{ => egnaddrs}/src/eigen_address.rs (100%) rename crates/eigen-cli/{ => egnaddrs}/src/lib.rs (55%) rename crates/eigen-cli/{ => egnaddrs}/src/main.rs (79%) create mode 100644 crates/eigen-cli/egnkey/Cargo.toml create mode 100644 crates/eigen-cli/egnkey/src/args.rs create mode 100644 crates/eigen-cli/egnkey/src/generate.rs create mode 100644 crates/eigen-cli/egnkey/src/lib.rs create mode 100644 crates/eigen-cli/egnkey/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 9300b396..34652b9c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1943,18 +1943,25 @@ dependencies = [ ] [[package]] -name = "eigen-chainio-utils" +name = "egnaddrs" version = "0.0.1-alpha" dependencies = [ - "ark-bn254", - "ark-ff 0.4.2", - "eigen-crypto-bls", - "eigen-crypto-bn254", + "alloy-contract", + "alloy-json-rpc", + "alloy-primitives", + "alloy-provider", + "alloy-transport", + "clap", + "eigen-testing-utils", "eigen-utils", + "serde", + "serde_json", + "thiserror", + "tokio", ] [[package]] -name = "eigen-cli" +name = "egnkey" version = "0.0.1-alpha" dependencies = [ "alloy-contract", @@ -1965,10 +1972,23 @@ dependencies = [ "clap", "eigen-testing-utils", "eigen-utils", + "rand", "serde", "serde_json", "thiserror", "tokio", + "uuid 1.10.0", +] + +[[package]] +name = "eigen-chainio-utils" +version = "0.0.1-alpha" +dependencies = [ + "ark-bn254", + "ark-ff 0.4.2", + "eigen-crypto-bls", + "eigen-crypto-bn254", + "eigen-utils", ] [[package]] @@ -6223,6 +6243,9 @@ name = "uuid" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] [[package]] name = "valuable" diff --git a/Cargo.toml b/Cargo.toml index 11574b2c..250b6528 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,8 @@ members = [ "crates/utils/", "crates/crypto/bls/", "crates/crypto/keystore/", - "crates/eigen-cli/", + "crates/eigen-cli/egnaddrs", + "crates/eigen-cli/egnkey", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", "crates/services/avsregistry/", diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/egnaddrs/Cargo.toml similarity index 96% rename from crates/eigen-cli/Cargo.toml rename to crates/eigen-cli/egnaddrs/Cargo.toml index 6bc3a992..4a1844b9 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/egnaddrs/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "eigen-cli" +name = "egnaddrs" version.workspace = true edition.workspace = true rust-version.workspace = true diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/egnaddrs/src/args.rs similarity index 100% rename from crates/eigen-cli/src/args.rs rename to crates/eigen-cli/egnaddrs/src/args.rs diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/egnaddrs/src/eigen_address.rs similarity index 100% rename from crates/eigen-cli/src/eigen_address.rs rename to crates/eigen-cli/egnaddrs/src/eigen_address.rs diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/egnaddrs/src/lib.rs similarity index 55% rename from crates/eigen-cli/src/lib.rs rename to crates/eigen-cli/egnaddrs/src/lib.rs index 1bb54197..29fd564c 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/egnaddrs/src/lib.rs @@ -41,23 +41,23 @@ mod test { }; let expected_addresses: EigenAddresses = serde_json::from_str( r#"{ - "avs": { - "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", - "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", - "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", - "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", - "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" - }, - "eigenlayer": { - "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - }, - "network": { - "chain-id": "31337", - "rpc-url": "http://localhost:8545" - } - }"#, + "avs": { + "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", + "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", + "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", + "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", + "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" + }, + "eigenlayer": { + "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + }, + "network": { + "chain-id": "31337", + "rpc-url": "http://localhost:8545" + } + }"#, ) .unwrap(); let addresses = EigenAddresses::get_addresses(args).await.unwrap(); @@ -76,23 +76,23 @@ mod test { }; let expected_addresses: EigenAddresses = serde_json::from_str( r#"{ - "avs": { - "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", - "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", - "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", - "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", - "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" - }, - "eigenlayer": { - "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - }, - "network": { - "chain-id": "31337", - "rpc-url": "http://localhost:8545" - } - }"#, + "avs": { + "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", + "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", + "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", + "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", + "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" + }, + "eigenlayer": { + "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", + "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", + "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" + }, + "network": { + "chain-id": "31337", + "rpc-url": "http://localhost:8545" + } + }"#, ) .unwrap(); diff --git a/crates/eigen-cli/src/main.rs b/crates/eigen-cli/egnaddrs/src/main.rs similarity index 79% rename from crates/eigen-cli/src/main.rs rename to crates/eigen-cli/egnaddrs/src/main.rs index cfd62f9f..88caeaa9 100644 --- a/crates/eigen-cli/src/main.rs +++ b/crates/eigen-cli/egnaddrs/src/main.rs @@ -1,5 +1,5 @@ use clap::Parser; -use eigen_cli::{args::Args, eigen_address::EigenAddresses}; +use egnaddrs::{args::Args, eigen_address::EigenAddresses}; #[tokio::main] async fn main() { diff --git a/crates/eigen-cli/egnkey/Cargo.toml b/crates/eigen-cli/egnkey/Cargo.toml new file mode 100644 index 00000000..dc551617 --- /dev/null +++ b/crates/eigen-cli/egnkey/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "egnkey" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +repository.workspace = true + +[dependencies] +alloy-contract.workspace = true +alloy-json-rpc.workspace = true +alloy-primitives.workspace = true +alloy-provider.workspace = true +alloy-transport.workspace = true +clap.workspace = true +eigen-testing-utils.workspace = true +eigen-utils.workspace = true +serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +tokio.workspace = true +rand = "0.8" +uuid = { version = "1.10.0", features = ["v4"] } diff --git a/crates/eigen-cli/egnkey/src/args.rs b/crates/eigen-cli/egnkey/src/args.rs new file mode 100644 index 00000000..f4a8d54d --- /dev/null +++ b/crates/eigen-cli/egnkey/src/args.rs @@ -0,0 +1,71 @@ +use clap::{Parser, Subcommand}; + +#[derive(Parser, Debug)] +#[command( + about = "Eigenlayer batch keys manager", + long_about = "Used to manage batch keys for testing" +)] +pub struct Args { + #[command(subcommand)] + pub command: Commands, +} + +#[derive(Subcommand, Debug)] +pub enum Commands { + #[command( + about = "Generate keys for testing purpose. +This command creates ecdsa or bls key pair for testing purposes. It generates +all the relevant files for reading and keys and decrypted it and also gets +you the private keys in plaintext. + +It creates the following artifacts based on arguments +- passwords.txt - contains all passwords to decrypt keys +- private_key_hex.txt - will create plaintext private keys +- keys/* - create all the encrypted json files in this folder", + alias = "g" + )] + Generate { + #[arg(long, help = "key type to create (ecdsa or bls)")] + #[clap(value_enum)] + key_type: KeyType, + + #[arg(long, help = "number of keys to create", default_value = "1")] + num_keys: u32, + + #[arg(long, help = "folder to store keys")] + output_dir: Option, + }, + + #[command( + about = "Given a private key, output its associated operatorId (hash of bn254 G1 pubkey).", + alias = "d" + )] + DeriveOperatorId { + #[arg( + long, + help = "(bn254) private key from which to derive operatorId from" + )] + private_key: String, + }, + + #[command( + about = "Stores an ecdsa key to a file, in web3 secret storage format.", + alias = "c" + )] + Convert { + #[arg(long, help = "private key to store (in hex)")] + private_key: String, + + #[arg(long, help = "file to store key")] + output_file: Option, + + #[arg(long, help = "password to encrypt key")] + password: Option, + }, +} + +#[derive(clap::ValueEnum, Debug, Clone)] +pub enum KeyType { + Ecsda, + Bls, +} diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs new file mode 100644 index 00000000..e8e183e5 --- /dev/null +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -0,0 +1,117 @@ +use rand::{distributions::Alphanumeric, Rng}; +use std::{ + fs::{self, File}, + path::Path, +}; +use uuid::Uuid; + +use crate::args::KeyType; + +const PASSWORD_LENGTH: usize = 20; +const DEFAULT_KEY_FOLDER: &str = "keys"; +const PASSWORD_FILE: &str = "password.txt"; +const PRIVATE_KEY_HEX_FILE: &str = "private_key_hex.txt"; + +enum KeyGenerator { + ECDSAKeyGenerator, + BLSKeyGenerator, +} + +impl KeyGenerator { + pub fn generate_keys(self, num_keys: u32, dir_path: String, password: String) { + match self { + KeyGenerator::ECDSAKeyGenerator => { + Self::generate_ecdsa_key(num_keys, dir_path, password) + } + KeyGenerator::BLSKeyGenerator => Self::generate_bls_key(num_keys, dir_path, password), + } + } + + fn generate_ecdsa_key(num_keys: u32, path: String, password_file: String) { + todo!() + // for i := 0; i < numKeys; i++ { + // key, err := crypto.GenerateKey() + // privateKeyHex := hex.EncodeToString(key.D.Bytes()) + + // // Check if the length of privateKeyHex is 32 bytes (64 characters) + // lenPrivateKey := len(privateKeyHex) + // if lenPrivateKey != 64 { + // fmt.Printf("Private key Ignore: %s %d\n", privateKeyHex, lenPrivateKey) + // // Reset count + // i-- + // continue + // } + + // if err != nil { + // return err + // } + + // password := generateRandomPassword() + // if err != nil { + // return err + // } + + // fileName := fmt.Sprintf("%d.ecdsa.key.json", i+1) + // err = ecdsa.WriteKey(filepath.Clean(path+"/"+DefaultKeyFolder+"/"+fileName), key, password) + // if err != nil { + // return err + // } + + // _, err = passwordFile.WriteString(password + "\n") + // if err != nil { + // return err + // } + + // _, err = privateKeyFile.WriteString("0x" + privateKeyHex + "\n") + // if err != nil { + // return err + // } + + // if (i+1)%50 == 0 { + // fmt.Printf("Generated %d keys\n", i+1) + // } + // } + // return nil + } + + fn generate_bls_key(num_keys: u32, path: String, password_file: String) { + todo!() + } +} + +impl From for KeyGenerator { + fn from(value: KeyType) -> Self { + match value { + KeyType::Ecsda => KeyGenerator::ECDSAKeyGenerator, + KeyType::Bls => KeyGenerator::BLSKeyGenerator, + } + } +} + +fn generate_random_password() -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(PASSWORD_LENGTH) + .map(char::from) + .collect() +} + +pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { + // create dir + let dir_name = match output_dir { + None => { + let id = Uuid::new_v4(); + let key_name = match key_type { + KeyType::Ecsda => "ecsda", + KeyType::Bls => "bls", + }; + format!("{}-{}", key_name, id.to_string()) + } + Some(dir) => dir, + }; + fs::create_dir_all(&dir_name).unwrap(); + + // generate keys + let password = generate_random_password(); + KeyGenerator::from(key_type).generate_keys(num_keys, dir_name, password) +} diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs new file mode 100644 index 00000000..442fd689 --- /dev/null +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -0,0 +1,20 @@ +use args::{Args, Commands}; +use generate::generate; +pub mod args; +mod generate; + +pub fn execute_egnkey(args: Args) { + match args.command { + Commands::Generate { + key_type, + num_keys, + output_dir, + } => generate(key_type, num_keys, output_dir), + Commands::Convert { + private_key, + output_file, + password, + } => todo!(), + Commands::DeriveOperatorId { private_key } => todo!(), + }; +} diff --git a/crates/eigen-cli/egnkey/src/main.rs b/crates/eigen-cli/egnkey/src/main.rs new file mode 100644 index 00000000..19a65909 --- /dev/null +++ b/crates/eigen-cli/egnkey/src/main.rs @@ -0,0 +1,8 @@ +use clap::Parser; +use egnkey::{args::Args, execute_egnkey}; + +#[tokio::main] +async fn main() { + let args = Args::parse(); + execute_egnkey(args); +} From ba64fe7deeafd90dc5723042d1f75860e57e50a5 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 2 Aug 2024 18:58:08 -0300 Subject: [PATCH 14/36] add ecdsa key generation Co-authored-by: Mateo Rico --- Cargo.lock | 4 ++ Cargo.toml | 2 + crates/eigen-cli/egnkey/Cargo.toml | 4 ++ crates/eigen-cli/egnkey/src/generate.rs | 96 ++++++++++++------------- 4 files changed, 54 insertions(+), 52 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 34652b9c..25f5002e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1972,7 +1972,11 @@ dependencies = [ "clap", "eigen-testing-utils", "eigen-utils", + "eth-keystore", + "hex", + "k256", "rand", + "rand_core", "serde", "serde_json", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 250b6528..0dcd8583 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -96,6 +96,8 @@ hex-literal = "0.4.1" k256 = "0.13.3" serde_json = "1.0.121" clap = { version = "4.5.11", features = ["derive"] } +rand_core = "0.6" +hex = "0.4" ethers-signers = "2.0.14" eth-keystore = "0.5.0" aws-config = "1.5.4" diff --git a/crates/eigen-cli/egnkey/Cargo.toml b/crates/eigen-cli/egnkey/Cargo.toml index dc551617..320e5ca8 100644 --- a/crates/eigen-cli/egnkey/Cargo.toml +++ b/crates/eigen-cli/egnkey/Cargo.toml @@ -14,9 +14,13 @@ alloy-transport.workspace = true clap.workspace = true eigen-testing-utils.workspace = true eigen-utils.workspace = true +eth-keystore.workspace = true +hex.workspace = true +k256.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio.workspace = true rand = "0.8" +rand_core.workspace = true uuid = { version = "1.10.0", features = ["v4"] } diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs index e8e183e5..18670689 100644 --- a/crates/eigen-cli/egnkey/src/generate.rs +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -1,12 +1,15 @@ +use crate::args::KeyType; +use eth_keystore::encrypt_key; +use k256::SecretKey; use rand::{distributions::Alphanumeric, Rng}; +use rand_core::OsRng; +use std::io::Write; use std::{ fs::{self, File}, path::Path, }; use uuid::Uuid; -use crate::args::KeyType; - const PASSWORD_LENGTH: usize = 20; const DEFAULT_KEY_FOLDER: &str = "keys"; const PASSWORD_FILE: &str = "password.txt"; @@ -18,63 +21,50 @@ enum KeyGenerator { } impl KeyGenerator { - pub fn generate_keys(self, num_keys: u32, dir_path: String, password: String) { + pub fn generate_keys(self, num_keys: u32, dir_path: &Path, password: String) { match self { KeyGenerator::ECDSAKeyGenerator => { - Self::generate_ecdsa_key(num_keys, dir_path, password) + Self::generate_ecdsa_key(num_keys, &dir_path, password) } KeyGenerator::BLSKeyGenerator => Self::generate_bls_key(num_keys, dir_path, password), } } - fn generate_ecdsa_key(num_keys: u32, path: String, password_file: String) { - todo!() - // for i := 0; i < numKeys; i++ { - // key, err := crypto.GenerateKey() - // privateKeyHex := hex.EncodeToString(key.D.Bytes()) - - // // Check if the length of privateKeyHex is 32 bytes (64 characters) - // lenPrivateKey := len(privateKeyHex) - // if lenPrivateKey != 64 { - // fmt.Printf("Private key Ignore: %s %d\n", privateKeyHex, lenPrivateKey) - // // Reset count - // i-- - // continue - // } - - // if err != nil { - // return err - // } - - // password := generateRandomPassword() - // if err != nil { - // return err - // } - - // fileName := fmt.Sprintf("%d.ecdsa.key.json", i+1) - // err = ecdsa.WriteKey(filepath.Clean(path+"/"+DefaultKeyFolder+"/"+fileName), key, password) - // if err != nil { - // return err - // } - - // _, err = passwordFile.WriteString(password + "\n") - // if err != nil { - // return err - // } - - // _, err = privateKeyFile.WriteString("0x" + privateKeyHex + "\n") - // if err != nil { - // return err - // } - - // if (i+1)%50 == 0 { - // fmt.Printf("Generated %d keys\n", i+1) - // } - // } - // return nil + fn generate_ecdsa_key(num_keys: u32, path: &Path, password: String) { + let key_path = path.join(DEFAULT_KEY_FOLDER); + let private_key_path = path.join(PRIVATE_KEY_HEX_FILE); + let password_path = path.join(PASSWORD_FILE); + + for i in 0..num_keys { + let private_key = SecretKey::random(&mut OsRng); + let private_key_hex = hex::encode(private_key.to_bytes()); + + // encrypt the private key into `path` directory + let name = format!("{}.ecdsa.key.json", i + 1); + encrypt_key( + key_path.clone(), + &mut OsRng, + private_key_hex.clone(), + password.clone(), + Some(&name), + ) + .unwrap(); + + // write the private key into `private_key_file` + let mut pk_file = File::create(private_key_path.clone()).unwrap(); + pk_file.write_all(private_key_hex.as_bytes()).unwrap(); + + // write the password into `password_file` + let mut password_file = File::create(password_path.clone()).unwrap(); + password_file.write_all(password.as_bytes()).unwrap(); + + if (i + 1) % 50 == 0 { + println!("Generated {} keys\n", i + 1); + } + } } - fn generate_bls_key(num_keys: u32, path: String, password_file: String) { + fn generate_bls_key(num_keys: u32, path: &Path, password_file: String) { todo!() } } @@ -109,9 +99,11 @@ pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { } Some(dir) => dir, }; - fs::create_dir_all(&dir_name).unwrap(); + let dir_path = Path::new(&dir_name); + let key_path = dir_path.join(DEFAULT_KEY_FOLDER); + fs::create_dir_all(&key_path).unwrap(); // generate keys let password = generate_random_password(); - KeyGenerator::from(key_type).generate_keys(num_keys, dir_name, password) + KeyGenerator::from(key_type).generate_keys(num_keys, dir_path, password) } From 3746bf808194ec888a2324e7ee9d1b9e3970fd74 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 6 Aug 2024 12:11:45 -0300 Subject: [PATCH 15/36] add ecdsa test --- Cargo.lock | 1 + crates/eigen-cli/egnkey/Cargo.toml | 3 ++ crates/eigen-cli/egnkey/src/args.rs | 2 +- crates/eigen-cli/egnkey/src/generate.rs | 14 ++++----- crates/eigen-cli/egnkey/src/lib.rs | 40 +++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 25f5002e..b8d88eec 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1979,6 +1979,7 @@ dependencies = [ "rand_core", "serde", "serde_json", + "tempfile", "thiserror", "tokio", "uuid 1.10.0", diff --git a/crates/eigen-cli/egnkey/Cargo.toml b/crates/eigen-cli/egnkey/Cargo.toml index 320e5ca8..40f84710 100644 --- a/crates/eigen-cli/egnkey/Cargo.toml +++ b/crates/eigen-cli/egnkey/Cargo.toml @@ -24,3 +24,6 @@ tokio.workspace = true rand = "0.8" rand_core.workspace = true uuid = { version = "1.10.0", features = ["v4"] } + +[dev-dependencies] +tempfile = "3" diff --git a/crates/eigen-cli/egnkey/src/args.rs b/crates/eigen-cli/egnkey/src/args.rs index f4a8d54d..8089eb97 100644 --- a/crates/eigen-cli/egnkey/src/args.rs +++ b/crates/eigen-cli/egnkey/src/args.rs @@ -66,6 +66,6 @@ It creates the following artifacts based on arguments #[derive(clap::ValueEnum, Debug, Clone)] pub enum KeyType { - Ecsda, + Ecdsa, Bls, } diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs index 18670689..dc5dc746 100644 --- a/crates/eigen-cli/egnkey/src/generate.rs +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -11,9 +11,9 @@ use std::{ use uuid::Uuid; const PASSWORD_LENGTH: usize = 20; -const DEFAULT_KEY_FOLDER: &str = "keys"; -const PASSWORD_FILE: &str = "password.txt"; -const PRIVATE_KEY_HEX_FILE: &str = "private_key_hex.txt"; +pub const DEFAULT_KEY_FOLDER: &str = "keys"; +pub const PASSWORD_FILE: &str = "password.txt"; +pub const PRIVATE_KEY_HEX_FILE: &str = "private_key_hex.txt"; enum KeyGenerator { ECDSAKeyGenerator, @@ -24,7 +24,7 @@ impl KeyGenerator { pub fn generate_keys(self, num_keys: u32, dir_path: &Path, password: String) { match self { KeyGenerator::ECDSAKeyGenerator => { - Self::generate_ecdsa_key(num_keys, &dir_path, password) + Self::generate_ecdsa_key(num_keys, dir_path, password) } KeyGenerator::BLSKeyGenerator => Self::generate_bls_key(num_keys, dir_path, password), } @@ -44,7 +44,7 @@ impl KeyGenerator { encrypt_key( key_path.clone(), &mut OsRng, - private_key_hex.clone(), + private_key.to_bytes(), password.clone(), Some(&name), ) @@ -72,7 +72,7 @@ impl KeyGenerator { impl From for KeyGenerator { fn from(value: KeyType) -> Self { match value { - KeyType::Ecsda => KeyGenerator::ECDSAKeyGenerator, + KeyType::Ecdsa => KeyGenerator::ECDSAKeyGenerator, KeyType::Bls => KeyGenerator::BLSKeyGenerator, } } @@ -92,7 +92,7 @@ pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { None => { let id = Uuid::new_v4(); let key_name = match key_type { - KeyType::Ecsda => "ecsda", + KeyType::Ecdsa => "ecdsa", KeyType::Bls => "bls", }; format!("{}-{}", key_name, id.to_string()) diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs index 442fd689..a9bf2c21 100644 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -18,3 +18,43 @@ pub fn execute_egnkey(args: Args) { Commands::DeriveOperatorId { private_key } => todo!(), }; } + +#[cfg(test)] +pub mod test { + use crate::{ + args::{Args, Commands, KeyType}, + execute_egnkey, + generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, + }; + use eth_keystore::decrypt_key; + use k256::SecretKey; + use std::fs; + use tempfile::tempdir; + + #[test] + fn generate_ecdsa_key() { + let output_dir = tempdir().unwrap(); + let output_path = output_dir.path(); + let command = Commands::Generate { + key_type: KeyType::Ecdsa, + num_keys: 1, + output_dir: output_path.to_str().map(String::from), + }; + let args = Args { command }; + + execute_egnkey(args); + + let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); + let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); + let key_path = output_path + .join(DEFAULT_KEY_FOLDER) + .join("1.ecdsa.key.json"); + + let decrypted_bytes = decrypt_key(key_path, password).unwrap(); + let decrypted_private_key = SecretKey::from_slice(&decrypted_bytes).unwrap().to_bytes(); + + let private_key = hex::decode(private_key_hex).unwrap(); + + assert_eq!(private_key, decrypted_private_key.as_slice()); + } +} From 57d51043561363373db9d482d18360c4c371f1d3 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 6 Aug 2024 14:28:54 -0300 Subject: [PATCH 16/36] add generate bls keys implementation --- Cargo.lock | 40 +++++++++++++++++++++ crates/eigen-cli/egnkey/Cargo.toml | 6 +++- crates/eigen-cli/egnkey/src/args.rs | 1 + crates/eigen-cli/egnkey/src/generate.rs | 47 ++++++++++++++++--------- crates/eigen-cli/egnkey/src/lib.rs | 15 +++++--- 5 files changed, 87 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b8d88eec..2d987bb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1969,7 +1969,10 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-transport", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", "clap", + "eigen-crypto-bls", "eigen-testing-utils", "eigen-utils", "eth-keystore", @@ -1977,6 +1980,7 @@ dependencies = [ "k256", "rand", "rand_core", + "rstest", "serde", "serde_json", "tempfile", @@ -4677,6 +4681,12 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "reqwest" version = "0.11.27" @@ -4849,6 +4859,36 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "rstest" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b423f0e62bdd61734b67cd21ff50871dfaeb9cc74f869dcd6af974fbcb19936" +dependencies = [ + "futures", + "futures-timer", + "rstest_macros", + "rustc_version 0.4.0", +] + +[[package]] +name = "rstest_macros" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e1711e7d14f74b12a58411c542185ef7fb7f2e7f8ee6e2940a883628522b42" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.0", + "syn 2.0.67", + "unicode-ident", +] + [[package]] name = "ruint" version = "1.12.3" diff --git a/crates/eigen-cli/egnkey/Cargo.toml b/crates/eigen-cli/egnkey/Cargo.toml index 40f84710..13a2ca0d 100644 --- a/crates/eigen-cli/egnkey/Cargo.toml +++ b/crates/eigen-cli/egnkey/Cargo.toml @@ -11,8 +11,10 @@ alloy-json-rpc.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true alloy-transport.workspace = true +ark-ff.workspace = true +ark-serialize = "0.4.2" clap.workspace = true -eigen-testing-utils.workspace = true +eigen-crypto-bls.workspace = true eigen-utils.workspace = true eth-keystore.workspace = true hex.workspace = true @@ -27,3 +29,5 @@ uuid = { version = "1.10.0", features = ["v4"] } [dev-dependencies] tempfile = "3" +rstest = "0.22.0" +eigen-testing-utils.workspace = true diff --git a/crates/eigen-cli/egnkey/src/args.rs b/crates/eigen-cli/egnkey/src/args.rs index 8089eb97..82d692cb 100644 --- a/crates/eigen-cli/egnkey/src/args.rs +++ b/crates/eigen-cli/egnkey/src/args.rs @@ -1,4 +1,5 @@ use clap::{Parser, Subcommand}; +use std::fmt; #[derive(Parser, Debug)] #[command( diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs index dc5dc746..f6006400 100644 --- a/crates/eigen-cli/egnkey/src/generate.rs +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -1,6 +1,9 @@ use crate::args::KeyType; +use ark_ff::UniformRand; +use ark_serialize::CanonicalSerialize; +use eigen_crypto_bls::PrivateKey; use eth_keystore::encrypt_key; -use k256::SecretKey; +use k256::{FieldBytes, SecretKey}; use rand::{distributions::Alphanumeric, Rng}; use rand_core::OsRng; use std::io::Write; @@ -21,30 +24,25 @@ enum KeyGenerator { } impl KeyGenerator { - pub fn generate_keys(self, num_keys: u32, dir_path: &Path, password: String) { - match self { - KeyGenerator::ECDSAKeyGenerator => { - Self::generate_ecdsa_key(num_keys, dir_path, password) - } - KeyGenerator::BLSKeyGenerator => Self::generate_bls_key(num_keys, dir_path, password), - } - } - - fn generate_ecdsa_key(num_keys: u32, path: &Path, password: String) { + pub fn generate_keys(self, num_keys: u32, path: &Path, password: String) { let key_path = path.join(DEFAULT_KEY_FOLDER); let private_key_path = path.join(PRIVATE_KEY_HEX_FILE); let password_path = path.join(PASSWORD_FILE); for i in 0..num_keys { - let private_key = SecretKey::random(&mut OsRng); - let private_key_hex = hex::encode(private_key.to_bytes()); + let private_key = self.random_key(); + let private_key_hex = hex::encode(private_key.clone()); // encrypt the private key into `path` directory - let name = format!("{}.ecdsa.key.json", i + 1); + let key_name = match self { + KeyGenerator::ECDSAKeyGenerator => "ecdsa", + KeyGenerator::BLSKeyGenerator => "bls", + }; + let name = format!("{}.{}.key.json", i + 1, key_name); encrypt_key( key_path.clone(), &mut OsRng, - private_key.to_bytes(), + private_key, password.clone(), Some(&name), ) @@ -64,8 +62,23 @@ impl KeyGenerator { } } - fn generate_bls_key(num_keys: u32, path: &Path, password_file: String) { - todo!() + fn random_key(&self) -> Vec { + match self { + KeyGenerator::ECDSAKeyGenerator => Self::random_ecdsa_key(), + KeyGenerator::BLSKeyGenerator => Self::random_bls_key(), + } + } + + fn random_ecdsa_key() -> Vec { + let private_key = SecretKey::random(&mut OsRng); + private_key.to_bytes().as_slice().to_vec() + } + + fn random_bls_key() -> Vec { + let mut buffer = Vec::new(); + let private_key = PrivateKey::rand(&mut OsRng); + private_key.serialize_uncompressed(&mut buffer).unwrap(); + buffer } } diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs index a9bf2c21..ac927df4 100644 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -28,15 +28,18 @@ pub mod test { }; use eth_keystore::decrypt_key; use k256::SecretKey; + use rstest::rstest; use std::fs; use tempfile::tempdir; - #[test] - fn generate_ecdsa_key() { + #[rstest] + #[case(KeyType::Ecdsa)] + #[case(KeyType::Bls)] + fn generate_key(#[case] key_type: KeyType) { let output_dir = tempdir().unwrap(); let output_path = output_dir.path(); let command = Commands::Generate { - key_type: KeyType::Ecdsa, + key_type: key_type.clone(), num_keys: 1, output_dir: output_path.to_str().map(String::from), }; @@ -46,9 +49,13 @@ pub mod test { let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); + let key_name = match key_type { + KeyType::Ecdsa => "ecdsa", + KeyType::Bls => "bls", + }; let key_path = output_path .join(DEFAULT_KEY_FOLDER) - .join("1.ecdsa.key.json"); + .join(format!("1.{}.key.json", key_name)); let decrypted_bytes = decrypt_key(key_path, password).unwrap(); let decrypted_private_key = SecretKey::from_slice(&decrypted_bytes).unwrap().to_bytes(); From 47a34c4e106ae8a8396444d2f7ac0fdd948e2a02 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Tue, 6 Aug 2024 14:57:35 -0300 Subject: [PATCH 17/36] add convert command functionality --- crates/eigen-cli/egnkey/src/convert.rs | 35 ++++++++++++++++++++++++++ crates/eigen-cli/egnkey/src/lib.rs | 4 ++- 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 crates/eigen-cli/egnkey/src/convert.rs diff --git a/crates/eigen-cli/egnkey/src/convert.rs b/crates/eigen-cli/egnkey/src/convert.rs new file mode 100644 index 00000000..0d014757 --- /dev/null +++ b/crates/eigen-cli/egnkey/src/convert.rs @@ -0,0 +1,35 @@ +use eth_keystore::{encrypt_key, KeystoreError}; +use rand_core::OsRng; +use std::path::Path; + +/// Stores an ecdsa key to a file, in web3 secret storage format. +/// +/// # Arguments +/// +/// * `private_key` - A private key to store (in hexadecimal). +/// * `output_file` - The name of the file where the key is going to be stored. +/// * `password` - The password used to encrypt the key. +/// +/// # Returns +/// +/// - Nothing (unit type ()). +/// +/// # Errors +/// +/// - If the key encryption fails. +pub fn store( + private_key: String, + output_file: Option, + password: Option, +) -> Result<(), KeystoreError> { + let dir = Path::new("."); + encrypt_key( + dir, + &mut OsRng, + private_key, + password.unwrap_or_default(), + Some(output_file.unwrap_or("key.json".into()).as_str()), + )?; + + Ok(()) +} diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs index ac927df4..2836373b 100644 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -1,6 +1,8 @@ use args::{Args, Commands}; +use convert::store; use generate::generate; pub mod args; +mod convert; mod generate; pub fn execute_egnkey(args: Args) { @@ -14,7 +16,7 @@ pub fn execute_egnkey(args: Args) { private_key, output_file, password, - } => todo!(), + } => store(private_key, output_file, password).unwrap(), Commands::DeriveOperatorId { private_key } => todo!(), }; } From a3513e8aa81ac79a536864c6311b2339ddb7bd28 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Tue, 6 Aug 2024 16:30:12 -0300 Subject: [PATCH 18/36] add documentation to KeyGenerator functions --- crates/eigen-cli/egnkey/src/generate.rs | 100 ++++++++++++++++-------- crates/eigen-cli/egnkey/src/lib.rs | 4 +- 2 files changed, 69 insertions(+), 35 deletions(-) diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs index f6006400..0c837cc6 100644 --- a/crates/eigen-cli/egnkey/src/generate.rs +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -3,7 +3,7 @@ use ark_ff::UniformRand; use ark_serialize::CanonicalSerialize; use eigen_crypto_bls::PrivateKey; use eth_keystore::encrypt_key; -use k256::{FieldBytes, SecretKey}; +use k256::SecretKey; use rand::{distributions::Alphanumeric, Rng}; use rand_core::OsRng; use std::io::Write; @@ -18,13 +18,49 @@ pub const DEFAULT_KEY_FOLDER: &str = "keys"; pub const PASSWORD_FILE: &str = "password.txt"; pub const PRIVATE_KEY_HEX_FILE: &str = "private_key_hex.txt"; -enum KeyGenerator { +pub enum KeyGenerator { ECDSAKeyGenerator, BLSKeyGenerator, } impl KeyGenerator { - pub fn generate_keys(self, num_keys: u32, path: &Path, password: String) { + /// Generates a number of private keys in the given directory. + /// + /// # Arguments + /// + /// * `key_type` - The type of the key to generate. + /// * `num_keys` - The number of keys to generate. + /// * `output_dir` - The directory where the key files are generated. + pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { + // create dir + let dir_name = match output_dir { + None => { + let id = Uuid::new_v4(); + let key_name = match key_type { + KeyType::Ecdsa => "ecdsa", + KeyType::Bls => "bls", + }; + format!("{}-{}", key_name, id.to_string()) + } + Some(dir) => dir, + }; + let dir_path = Path::new(&dir_name); + let key_path = dir_path.join(DEFAULT_KEY_FOLDER); + fs::create_dir_all(&key_path).unwrap(); + + // generate keys + let password = KeyGenerator::generate_random_password(); + KeyGenerator::from(key_type).generate_keys(num_keys, dir_path, password) + } + + /// Generates a number of private keys and stores them both encrypted and in plaintext. + /// + /// # Arguments + /// + /// * `num_keys` - The number of keys to generate. + /// * `path` - The path to the directory where the generated files are stored. + /// * `password` - The password used to encrypt the keys. + fn generate_keys(self, num_keys: u32, path: &Path, password: String) { let key_path = path.join(DEFAULT_KEY_FOLDER); let private_key_path = path.join(PRIVATE_KEY_HEX_FILE); let password_path = path.join(PASSWORD_FILE); @@ -62,6 +98,11 @@ impl KeyGenerator { } } + /// Generates a random key which can be of type ecdsa or BLS. + /// + /// # Returns + /// + /// * A private key as a vector of bytes. fn random_key(&self) -> Vec { match self { KeyGenerator::ECDSAKeyGenerator => Self::random_ecdsa_key(), @@ -69,17 +110,40 @@ impl KeyGenerator { } } + /// Generates a random ecdsa key. + /// + /// # Returns + /// + /// * An ecdsa private key as a vector of bytes. fn random_ecdsa_key() -> Vec { let private_key = SecretKey::random(&mut OsRng); private_key.to_bytes().as_slice().to_vec() } + /// Generates a random BLS key. + /// + /// # Returns + /// + /// * A BLS private key as a vector of bytes. fn random_bls_key() -> Vec { let mut buffer = Vec::new(); let private_key = PrivateKey::rand(&mut OsRng); private_key.serialize_uncompressed(&mut buffer).unwrap(); buffer } + + /// Generates a 20-character random password. + /// + /// # Returns + /// + /// * A random password. + fn generate_random_password() -> String { + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(PASSWORD_LENGTH) + .map(char::from) + .collect() + } } impl From for KeyGenerator { @@ -90,33 +154,3 @@ impl From for KeyGenerator { } } } - -fn generate_random_password() -> String { - rand::thread_rng() - .sample_iter(&Alphanumeric) - .take(PASSWORD_LENGTH) - .map(char::from) - .collect() -} - -pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { - // create dir - let dir_name = match output_dir { - None => { - let id = Uuid::new_v4(); - let key_name = match key_type { - KeyType::Ecdsa => "ecdsa", - KeyType::Bls => "bls", - }; - format!("{}-{}", key_name, id.to_string()) - } - Some(dir) => dir, - }; - let dir_path = Path::new(&dir_name); - let key_path = dir_path.join(DEFAULT_KEY_FOLDER); - fs::create_dir_all(&key_path).unwrap(); - - // generate keys - let password = generate_random_password(); - KeyGenerator::from(key_type).generate_keys(num_keys, dir_path, password) -} diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs index 2836373b..c9a54df4 100644 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -1,6 +1,6 @@ use args::{Args, Commands}; use convert::store; -use generate::generate; +use generate::KeyGenerator; pub mod args; mod convert; mod generate; @@ -11,7 +11,7 @@ pub fn execute_egnkey(args: Args) { key_type, num_keys, output_dir, - } => generate(key_type, num_keys, output_dir), + } => KeyGenerator::generate(key_type, num_keys, output_dir), Commands::Convert { private_key, output_file, From aae6b193ef9c09b70ba0fdaada0ebb5c6233c19b Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 6 Aug 2024 17:16:03 -0300 Subject: [PATCH 19/36] add error handling and move password creation --- crates/eigen-cli/egnkey/src/args.rs | 1 - crates/eigen-cli/egnkey/src/generate.rs | 69 +++++++++++++++---------- crates/eigen-cli/egnkey/src/lib.rs | 20 +++++-- crates/eigen-cli/egnkey/src/main.rs | 2 +- 4 files changed, 58 insertions(+), 34 deletions(-) diff --git a/crates/eigen-cli/egnkey/src/args.rs b/crates/eigen-cli/egnkey/src/args.rs index 82d692cb..8089eb97 100644 --- a/crates/eigen-cli/egnkey/src/args.rs +++ b/crates/eigen-cli/egnkey/src/args.rs @@ -1,5 +1,4 @@ use clap::{Parser, Subcommand}; -use std::fmt; #[derive(Parser, Debug)] #[command( diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/egnkey/src/generate.rs index 0c837cc6..ff59337a 100644 --- a/crates/eigen-cli/egnkey/src/generate.rs +++ b/crates/eigen-cli/egnkey/src/generate.rs @@ -1,9 +1,10 @@ use crate::args::KeyType; +use crate::EigenKeyCliError; use ark_ff::UniformRand; use ark_serialize::CanonicalSerialize; -use eigen_crypto_bls::PrivateKey; +use eigen_crypto_bls; use eth_keystore::encrypt_key; -use k256::SecretKey; +use k256; use rand::{distributions::Alphanumeric, Rng}; use rand_core::OsRng; use std::io::Write; @@ -31,50 +32,48 @@ impl KeyGenerator { /// * `key_type` - The type of the key to generate. /// * `num_keys` - The number of keys to generate. /// * `output_dir` - The directory where the key files are generated. - pub fn generate(key_type: KeyType, num_keys: u32, output_dir: Option) { - // create dir + pub fn generate( + self, + num_keys: u32, + output_dir: Option, + ) -> Result<(), EigenKeyCliError> { let dir_name = match output_dir { None => { let id = Uuid::new_v4(); - let key_name = match key_type { - KeyType::Ecdsa => "ecdsa", - KeyType::Bls => "bls", - }; - format!("{}-{}", key_name, id.to_string()) + format!("{}-{}", self.key_name(), id.to_string()) } Some(dir) => dir, }; let dir_path = Path::new(&dir_name); let key_path = dir_path.join(DEFAULT_KEY_FOLDER); - fs::create_dir_all(&key_path).unwrap(); + fs::create_dir_all(&key_path).map_err(EigenKeyCliError::FileError)?; - // generate keys - let password = KeyGenerator::generate_random_password(); - KeyGenerator::from(key_type).generate_keys(num_keys, dir_path, password) + self.generate_keys(num_keys, dir_path) } /// Generates a number of private keys and stores them both encrypted and in plaintext. + /// It creates the following files: + /// - `passwords.txt`: contains all passwords to decrypt keys + /// - `private_key_hex.txt`: plaintext private keys + /// - `keys/*`: all the encrypted json files in this folder /// /// # Arguments /// /// * `num_keys` - The number of keys to generate. /// * `path` - The path to the directory where the generated files are stored. /// * `password` - The password used to encrypt the keys. - fn generate_keys(self, num_keys: u32, path: &Path, password: String) { + fn generate_keys(self, num_keys: u32, path: &Path) -> Result<(), EigenKeyCliError> { let key_path = path.join(DEFAULT_KEY_FOLDER); let private_key_path = path.join(PRIVATE_KEY_HEX_FILE); let password_path = path.join(PASSWORD_FILE); for i in 0..num_keys { + let password = KeyGenerator::generate_random_password(); let private_key = self.random_key(); let private_key_hex = hex::encode(private_key.clone()); // encrypt the private key into `path` directory - let key_name = match self { - KeyGenerator::ECDSAKeyGenerator => "ecdsa", - KeyGenerator::BLSKeyGenerator => "bls", - }; - let name = format!("{}.{}.key.json", i + 1, key_name); + let name = format!("{}.{}.key.json", i + 1, self.key_name()); encrypt_key( key_path.clone(), &mut OsRng, @@ -82,20 +81,23 @@ impl KeyGenerator { password.clone(), Some(&name), ) - .unwrap(); + .map_err(EigenKeyCliError::KeystoreError)?; // write the private key into `private_key_file` - let mut pk_file = File::create(private_key_path.clone()).unwrap(); - pk_file.write_all(private_key_hex.as_bytes()).unwrap(); + File::create(private_key_path.clone()) + .and_then(|mut file| file.write_all(private_key_hex.as_bytes())) + .map_err(EigenKeyCliError::FileError)?; // write the password into `password_file` - let mut password_file = File::create(password_path.clone()).unwrap(); - password_file.write_all(password.as_bytes()).unwrap(); + File::create(password_path.clone()) + .and_then(|mut file| file.write_all(password.as_bytes())) + .map_err(EigenKeyCliError::FileError)?; if (i + 1) % 50 == 0 { println!("Generated {} keys\n", i + 1); } } + Ok(()) } /// Generates a random key which can be of type ecdsa or BLS. @@ -116,7 +118,7 @@ impl KeyGenerator { /// /// * An ecdsa private key as a vector of bytes. fn random_ecdsa_key() -> Vec { - let private_key = SecretKey::random(&mut OsRng); + let private_key = k256::SecretKey::random(&mut OsRng); private_key.to_bytes().as_slice().to_vec() } @@ -127,8 +129,8 @@ impl KeyGenerator { /// * A BLS private key as a vector of bytes. fn random_bls_key() -> Vec { let mut buffer = Vec::new(); - let private_key = PrivateKey::rand(&mut OsRng); - private_key.serialize_uncompressed(&mut buffer).unwrap(); + let private_key = eigen_crypto_bls::PrivateKey::rand(&mut OsRng); + private_key.serialize_uncompressed(&mut buffer).unwrap(); // handle unwrap buffer } @@ -144,6 +146,19 @@ impl KeyGenerator { .map(char::from) .collect() } + + /// Get the key type. + /// + /// # Returns + /// + /// * The key type as a string. + fn key_name(&self) -> String { + match self { + KeyGenerator::ECDSAKeyGenerator => "ecdsa", + KeyGenerator::BLSKeyGenerator => "bls", + } + .to_string() + } } impl From for KeyGenerator { diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs index c9a54df4..7d2a3c80 100644 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ b/crates/eigen-cli/egnkey/src/lib.rs @@ -4,21 +4,31 @@ use generate::KeyGenerator; pub mod args; mod convert; mod generate; +use eth_keystore::KeystoreError; +use thiserror::Error; -pub fn execute_egnkey(args: Args) { +#[derive(Error, Debug)] +pub enum EigenKeyCliError { + #[error("file error")] + FileError(std::io::Error), + #[error("encription error")] + KeystoreError(KeystoreError), +} + +pub fn execute_egnkey(args: Args) -> Result<(), EigenKeyCliError> { match args.command { Commands::Generate { key_type, num_keys, output_dir, - } => KeyGenerator::generate(key_type, num_keys, output_dir), + } => KeyGenerator::from(key_type).generate(num_keys, output_dir), Commands::Convert { private_key, output_file, password, - } => store(private_key, output_file, password).unwrap(), + } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), Commands::DeriveOperatorId { private_key } => todo!(), - }; + } } #[cfg(test)] @@ -47,7 +57,7 @@ pub mod test { }; let args = Args { command }; - execute_egnkey(args); + execute_egnkey(args).unwrap(); let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); diff --git a/crates/eigen-cli/egnkey/src/main.rs b/crates/eigen-cli/egnkey/src/main.rs index 19a65909..10f371fc 100644 --- a/crates/eigen-cli/egnkey/src/main.rs +++ b/crates/eigen-cli/egnkey/src/main.rs @@ -4,5 +4,5 @@ use egnkey::{args::Args, execute_egnkey}; #[tokio::main] async fn main() { let args = Args::parse(); - execute_egnkey(args); + execute_egnkey(args).unwrap(); } From 5bb7ab31de0ab3c76db98c4a847fd2fa4e3e4e99 Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Tue, 6 Aug 2024 18:53:20 -0300 Subject: [PATCH 20/36] fix merge egnaddrs --- crates/eigen-cli/egnaddrs/Cargo.toml | 20 -- crates/eigen-cli/egnaddrs/src/args.rs | 25 --- .../eigen-cli/egnaddrs/src/eigen_address.rs | 212 ------------------ crates/eigen-cli/egnaddrs/src/lib.rs | 103 --------- crates/eigen-cli/egnaddrs/src/main.rs | 10 - 5 files changed, 370 deletions(-) delete mode 100644 crates/eigen-cli/egnaddrs/Cargo.toml delete mode 100644 crates/eigen-cli/egnaddrs/src/args.rs delete mode 100644 crates/eigen-cli/egnaddrs/src/eigen_address.rs delete mode 100644 crates/eigen-cli/egnaddrs/src/lib.rs delete mode 100644 crates/eigen-cli/egnaddrs/src/main.rs diff --git a/crates/eigen-cli/egnaddrs/Cargo.toml b/crates/eigen-cli/egnaddrs/Cargo.toml deleted file mode 100644 index 4a1844b9..00000000 --- a/crates/eigen-cli/egnaddrs/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "egnaddrs" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -repository.workspace = true - -[dependencies] -alloy-contract.workspace = true -alloy-json-rpc.workspace = true -alloy-primitives.workspace = true -alloy-provider.workspace = true -alloy-transport.workspace = true -clap.workspace = true -eigen-testing-utils.workspace = true -eigen-utils.workspace = true -serde.workspace = true -serde_json.workspace = true -thiserror.workspace = true -tokio.workspace = true diff --git a/crates/eigen-cli/egnaddrs/src/args.rs b/crates/eigen-cli/egnaddrs/src/args.rs deleted file mode 100644 index 3104de88..00000000 --- a/crates/eigen-cli/egnaddrs/src/args.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::ANVIL_RPC_URL; -use alloy_primitives::Address; -use clap::{ArgGroup, Parser}; - -#[derive(Parser, Debug)] -#[command(group( - ArgGroup::new("manager_or_coordinator") - .required(true) - .args(&["service_manager", "registry_coordinator"]), -))] -#[command( - version, - about = "Used to help debug and test deployments and contract setups.", - long_about = "This utility facilitates the debugging and testing of Eigenlayer and AVS contract deployments by retrieving and displaying a comprehensive list of contract addresses. Starting from an initial contract address provided, it recursively identifies and prints addresses for all relevant Eigenlayer and AVS contracts within the network. This includes service managers, registry coordinators, and various registries, thus providing a view of the deployment's structure within the network." -)] -pub struct Args { - #[arg(long, help = "ServiceManager contract address")] - pub service_manager: Option
, - - #[arg(long, help = "BLSRegistryCoordinatorWithIndices contract address")] - pub registry_coordinator: Option
, - - #[arg(long, help = "rpc url", default_value = ANVIL_RPC_URL)] - pub rpc_url: String, -} diff --git a/crates/eigen-cli/egnaddrs/src/eigen_address.rs b/crates/eigen-cli/egnaddrs/src/eigen_address.rs deleted file mode 100644 index 941a95f3..00000000 --- a/crates/eigen-cli/egnaddrs/src/eigen_address.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::args::Args; -use crate::EigenAddressCliError; -use alloy_contract::Error as ContractError; -use alloy_primitives::Address; -use alloy_provider::Provider; -use eigen_utils::{ - binding::{DelegationManager, IBLSSignatureChecker, RegistryCoordinator}, - get_provider, -}; -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -pub struct EigenAddresses { - avs: AvsAddresses, - eigenlayer: EigenLayerAddresses, - network: NetworkInfo, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct EigenLayerAddresses { - delegation_manager: Address, - slasher: Address, - strategy_manager: Address, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct NetworkInfo { - chain_id: String, - rpc_url: String, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq)] -#[serde(rename_all(serialize = "kebab-case"))] -#[serde(rename_all(deserialize = "kebab-case"))] -pub struct AvsAddresses { - bls_apk_registry: Address, - index_registry: Address, - registry_coordinator: Address, - service_manager: Address, - stake_registry: Address, -} - -impl EigenAddresses { - /// Public function to get the Eigenlayer and AVS contract addresses. - /// - /// # Arguments - /// - /// * `args` - The command line arguments. - /// - /// # Returns - /// - /// * `EigenAddresses` - The Eigenlayer and AVS contract addresses. - pub async fn get_addresses(args: Args) -> Result { - let rpc_url = args.rpc_url.clone(); - let client = get_provider(&rpc_url); - let chain_id = client - .get_chain_id() - .await - .map_err(EigenAddressCliError::RpcError)? - .to_string(); - let (registry_coord_addr, service_manager_addr) = - EigenAddresses::get_registry_coord_and_service_manager_addr(args, client.clone()) - .await?; - - let avs = EigenAddresses::get_avs_contract_addresses(registry_coord_addr, client.clone()) - .await - .map_err(EigenAddressCliError::ContractError)?; - - let eigenlayer = - EigenAddresses::get_eigenlayer_contract_addresses(service_manager_addr, client) - .await - .map_err(EigenAddressCliError::ContractError)?; - - let network = NetworkInfo { rpc_url, chain_id }; - Ok(EigenAddresses { - network, - eigenlayer, - avs, - }) - } - - /// Get the registry coordinator and service manager contract addresses. - /// - /// # Arguments - /// - /// * `args` - The command line arguments. - /// * `client` - The provider client. - /// - /// # Returns - /// - /// * `(Address, Address)` - The registry coordinator and service manager contract addresses, - /// used to call `get_avs_contract_addresses` and `get_eigenlayer_contract_addresses` functions. - async fn get_registry_coord_and_service_manager_addr( - args: Args, - client: P, - ) -> Result<(Address, Address), EigenAddressCliError> - where - T: alloy_contract::private::Transport + ::core::clone::Clone, - P: alloy_contract::private::Provider, - N: alloy_contract::private::Network, - { - match (args.registry_coordinator, args.service_manager) { - (Some(registry_coord_addr), _) => { - let registry_coordinator = RegistryCoordinator::new(registry_coord_addr, &client); - let service_manager_addr = registry_coordinator - .serviceManager() - .call() - .await - .map_err(EigenAddressCliError::ContractError)? - ._0; - Ok((registry_coord_addr, service_manager_addr)) - } - (_, Some(service_manager_addr)) => { - let service_manager = IBLSSignatureChecker::new(service_manager_addr, client); - let registry_coord_addr = service_manager - .registryCoordinator() - .call() - .await - .map_err(EigenAddressCliError::ContractError)? - ._0; - Ok((registry_coord_addr, service_manager_addr)) - } - _ => unreachable!(), - } - } - - /// Get the Eigenlayer contract addresses. - /// - /// # Arguments - /// - /// * `service_manager_addr` - The service manager contract address. - /// * `client` - The provider client. - /// - /// # Returns - /// - /// * `EigenAddresses` - The Eigenlayer contract addresses. - async fn get_eigenlayer_contract_addresses( - service_manager_addr: Address, - client: P, - ) -> Result - where - P: alloy_contract::private::Provider, - T: alloy_contract::private::Transport + ::core::clone::Clone, - N: alloy_contract::private::Network, - { - let service_manager = IBLSSignatureChecker::new(service_manager_addr, &client); - let delegation_manager = service_manager.delegation().call().await?._0; - let delegation_manager_client = DelegationManager::new(delegation_manager, &client); - let slasher = delegation_manager_client.slasher().call().await?._0; - let strategy_manager = delegation_manager_client.strategyManager().call().await?._0; - - Ok(EigenLayerAddresses { - slasher, - delegation_manager, - strategy_manager, - }) - } - - /// Get the AVS contract addresses. - /// - /// # Arguments - /// - /// * `registry_coordinator` - The registry coordinator contract address. - /// * `client` - The provider client. - /// - /// # Returns - /// - /// * `AvsAddresses` - The AVS contract addresses. - async fn get_avs_contract_addresses( - registry_coordinator: Address, - client: P, - ) -> Result - where - P: alloy_contract::private::Provider, - T: alloy_contract::private::Transport + ::core::clone::Clone, - N: alloy_contract::private::Network, - { - let registry_coordinator_instance = RegistryCoordinator::new(registry_coordinator, &client); - let service_manager = registry_coordinator_instance - .serviceManager() - .call() - .await? - ._0; - let bls_apk_registry = registry_coordinator_instance - .blsApkRegistry() - .call() - .await? - ._0; - let index_registry = registry_coordinator_instance - .indexRegistry() - .call() - .await? - ._0; - let stake_registry = registry_coordinator_instance - .stakeRegistry() - .call() - .await? - ._0; - - Ok(AvsAddresses { - service_manager, - registry_coordinator, - bls_apk_registry, - index_registry, - stake_registry, - }) - } -} diff --git a/crates/eigen-cli/egnaddrs/src/lib.rs b/crates/eigen-cli/egnaddrs/src/lib.rs deleted file mode 100644 index 29fd564c..00000000 --- a/crates/eigen-cli/egnaddrs/src/lib.rs +++ /dev/null @@ -1,103 +0,0 @@ -#![doc( - html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", - issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" -)] -use alloy_contract::Error as ContractError; -use alloy_json_rpc::RpcError; -use alloy_transport::TransportErrorKind; -use thiserror::Error; -pub mod args; -pub mod eigen_address; - -pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; - -/// Possible errors raised while trying to get contract addresses -#[derive(Error, Debug)] -pub enum EigenAddressCliError { - #[error("contract error")] - ContractError(ContractError), - #[error("RPC error")] - RpcError(RpcError), -} - -#[cfg(test)] -mod test { - use super::ANVIL_RPC_URL; - use crate::args::Args; - use crate::eigen_address::EigenAddresses; - use eigen_testing_utils::anvil_constants::{ - get_registry_coordinator_address, get_service_manager_address, - }; - use tokio; - - #[tokio::test] - async fn egnaddrs_with_service_manager_flag() { - let service_manager_address = get_service_manager_address().await; - - let args = Args { - registry_coordinator: None, - service_manager: Some(service_manager_address), - rpc_url: ANVIL_RPC_URL.into(), - }; - let expected_addresses: EigenAddresses = serde_json::from_str( - r#"{ - "avs": { - "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", - "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", - "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", - "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", - "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" - }, - "eigenlayer": { - "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - }, - "network": { - "chain-id": "31337", - "rpc-url": "http://localhost:8545" - } - }"#, - ) - .unwrap(); - let addresses = EigenAddresses::get_addresses(args).await.unwrap(); - - assert_eq!(expected_addresses, addresses); - } - - #[tokio::test] - async fn egnaddrs_with_registry_coordinator_flag() { - let registry_coordinator_address = get_registry_coordinator_address().await; - - let args = Args { - registry_coordinator: Some(registry_coordinator_address), - service_manager: None, - rpc_url: ANVIL_RPC_URL.into(), - }; - let expected_addresses: EigenAddresses = serde_json::from_str( - r#"{ - "avs": { - "bls-apk-registry": "0x84ea74d481ee0a5332c457a4d796187f6ba67feb", - "index-registry": "0x9e545e3c0baab3e08cdfd552c960a1050f373042", - "registry-coordinator": "0xc3e53f4d16ae77db1c982e75a937b9f60fe63690", - "service-manager": "0x67d269191c92caf3cd7723f116c85e6e9bf55933", - "stake-registry": "0xa82ff9afd8f496c3d6ac40e2a0f282e47488cfc9" - }, - "eigenlayer": { - "delegation-manager": "0xDc64a140Aa3E981100a9becA4E685f962f0cF6C9", - "slasher": "0xa513E6E4b8f2a923D98304ec87F64353C4D5C853", - "strategy-manager": "0x5FC8d32690cc91D4c39d9d3abcBD16989F875707" - }, - "network": { - "chain-id": "31337", - "rpc-url": "http://localhost:8545" - } - }"#, - ) - .unwrap(); - - let addresses = EigenAddresses::get_addresses(args).await.unwrap(); - - assert_eq!(expected_addresses, addresses); - } -} diff --git a/crates/eigen-cli/egnaddrs/src/main.rs b/crates/eigen-cli/egnaddrs/src/main.rs deleted file mode 100644 index 88caeaa9..00000000 --- a/crates/eigen-cli/egnaddrs/src/main.rs +++ /dev/null @@ -1,10 +0,0 @@ -use clap::Parser; -use egnaddrs::{args::Args, eigen_address::EigenAddresses}; - -#[tokio::main] -async fn main() { - let args = Args::parse(); - let addresses = EigenAddresses::get_addresses(args).await.unwrap(); - - println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); -} From 68e16d8651aa3cf06904edb96caca6ce89c3c027 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 12:11:47 -0300 Subject: [PATCH 21/36] join egnaddr and egnkey into a single crate --- Cargo.lock | 48 ++-------- crates/eigen-cli/Cargo.toml | 14 +++ crates/eigen-cli/egnkey/Cargo.toml | 33 ------- crates/eigen-cli/egnkey/src/args.rs | 71 -------------- crates/eigen-cli/egnkey/src/lib.rs | 79 --------------- crates/eigen-cli/egnkey/src/main.rs | 8 -- crates/eigen-cli/src/args.rs | 56 +++++++++++ crates/eigen-cli/{egnkey => }/src/convert.rs | 0 crates/eigen-cli/{egnkey => }/src/generate.rs | 0 crates/eigen-cli/src/lib.rs | 96 ++++++++++++++++++- crates/eigen-cli/src/main.rs | 22 +---- 11 files changed, 174 insertions(+), 253 deletions(-) delete mode 100644 crates/eigen-cli/egnkey/Cargo.toml delete mode 100644 crates/eigen-cli/egnkey/src/args.rs delete mode 100644 crates/eigen-cli/egnkey/src/lib.rs delete mode 100644 crates/eigen-cli/egnkey/src/main.rs rename crates/eigen-cli/{egnkey => }/src/convert.rs (100%) rename crates/eigen-cli/{egnkey => }/src/generate.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 8488f3d8..702a08e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1943,25 +1943,18 @@ dependencies = [ ] [[package]] -name = "egnaddrs" +name = "eigen-chainio-utils" version = "0.0.1-alpha" dependencies = [ - "alloy-contract", - "alloy-json-rpc", - "alloy-primitives", - "alloy-provider", - "alloy-transport", - "clap", - "eigen-testing-utils", + "ark-bn254", + "ark-ff 0.4.2", + "eigen-crypto-bls", + "eigen-crypto-bn254", "eigen-utils", - "serde", - "serde_json", - "thiserror", - "tokio", ] [[package]] -name = "egnkey" +name = "eigen-cli" version = "0.0.1-alpha" dependencies = [ "alloy-contract", @@ -1989,35 +1982,6 @@ dependencies = [ "uuid 1.10.0", ] -[[package]] -name = "eigen-chainio-utils" -version = "0.0.1-alpha" -dependencies = [ - "ark-bn254", - "ark-ff 0.4.2", - "eigen-crypto-bls", - "eigen-crypto-bn254", - "eigen-utils", -] - -[[package]] -name = "eigen-cli" -version = "0.0.1-alpha" -dependencies = [ - "alloy-contract", - "alloy-json-rpc", - "alloy-primitives", - "alloy-provider", - "alloy-transport", - "clap", - "eigen-testing-utils", - "eigen-utils", - "serde", - "serde_json", - "thiserror", - "tokio", -] - [[package]] name = "eigen-client-avsregistry" version = "0.0.1-alpha" diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index 6bc3a992..64988050 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -11,10 +11,24 @@ alloy-json-rpc.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true alloy-transport.workspace = true +ark-ff.workspace = true +ark-serialize = "0.4.2" clap.workspace = true +eigen-crypto-bls.workspace = true eigen-testing-utils.workspace = true eigen-utils.workspace = true +eth-keystore.workspace = true +hex.workspace = true +k256.workspace = true +rand = "0.8" +rand_core.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio.workspace = true +uuid = { version = "1.10.0", features = ["v4"] } + +[dev-dependencies] +eigen-testing-utils.workspace = true +rstest = "0.22.0" +tempfile = "3" \ No newline at end of file diff --git a/crates/eigen-cli/egnkey/Cargo.toml b/crates/eigen-cli/egnkey/Cargo.toml deleted file mode 100644 index 13a2ca0d..00000000 --- a/crates/eigen-cli/egnkey/Cargo.toml +++ /dev/null @@ -1,33 +0,0 @@ -[package] -name = "egnkey" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -repository.workspace = true - -[dependencies] -alloy-contract.workspace = true -alloy-json-rpc.workspace = true -alloy-primitives.workspace = true -alloy-provider.workspace = true -alloy-transport.workspace = true -ark-ff.workspace = true -ark-serialize = "0.4.2" -clap.workspace = true -eigen-crypto-bls.workspace = true -eigen-utils.workspace = true -eth-keystore.workspace = true -hex.workspace = true -k256.workspace = true -serde.workspace = true -serde_json.workspace = true -thiserror.workspace = true -tokio.workspace = true -rand = "0.8" -rand_core.workspace = true -uuid = { version = "1.10.0", features = ["v4"] } - -[dev-dependencies] -tempfile = "3" -rstest = "0.22.0" -eigen-testing-utils.workspace = true diff --git a/crates/eigen-cli/egnkey/src/args.rs b/crates/eigen-cli/egnkey/src/args.rs deleted file mode 100644 index 8089eb97..00000000 --- a/crates/eigen-cli/egnkey/src/args.rs +++ /dev/null @@ -1,71 +0,0 @@ -use clap::{Parser, Subcommand}; - -#[derive(Parser, Debug)] -#[command( - about = "Eigenlayer batch keys manager", - long_about = "Used to manage batch keys for testing" -)] -pub struct Args { - #[command(subcommand)] - pub command: Commands, -} - -#[derive(Subcommand, Debug)] -pub enum Commands { - #[command( - about = "Generate keys for testing purpose. -This command creates ecdsa or bls key pair for testing purposes. It generates -all the relevant files for reading and keys and decrypted it and also gets -you the private keys in plaintext. - -It creates the following artifacts based on arguments -- passwords.txt - contains all passwords to decrypt keys -- private_key_hex.txt - will create plaintext private keys -- keys/* - create all the encrypted json files in this folder", - alias = "g" - )] - Generate { - #[arg(long, help = "key type to create (ecdsa or bls)")] - #[clap(value_enum)] - key_type: KeyType, - - #[arg(long, help = "number of keys to create", default_value = "1")] - num_keys: u32, - - #[arg(long, help = "folder to store keys")] - output_dir: Option, - }, - - #[command( - about = "Given a private key, output its associated operatorId (hash of bn254 G1 pubkey).", - alias = "d" - )] - DeriveOperatorId { - #[arg( - long, - help = "(bn254) private key from which to derive operatorId from" - )] - private_key: String, - }, - - #[command( - about = "Stores an ecdsa key to a file, in web3 secret storage format.", - alias = "c" - )] - Convert { - #[arg(long, help = "private key to store (in hex)")] - private_key: String, - - #[arg(long, help = "file to store key")] - output_file: Option, - - #[arg(long, help = "password to encrypt key")] - password: Option, - }, -} - -#[derive(clap::ValueEnum, Debug, Clone)] -pub enum KeyType { - Ecdsa, - Bls, -} diff --git a/crates/eigen-cli/egnkey/src/lib.rs b/crates/eigen-cli/egnkey/src/lib.rs deleted file mode 100644 index 7d2a3c80..00000000 --- a/crates/eigen-cli/egnkey/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -use args::{Args, Commands}; -use convert::store; -use generate::KeyGenerator; -pub mod args; -mod convert; -mod generate; -use eth_keystore::KeystoreError; -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum EigenKeyCliError { - #[error("file error")] - FileError(std::io::Error), - #[error("encription error")] - KeystoreError(KeystoreError), -} - -pub fn execute_egnkey(args: Args) -> Result<(), EigenKeyCliError> { - match args.command { - Commands::Generate { - key_type, - num_keys, - output_dir, - } => KeyGenerator::from(key_type).generate(num_keys, output_dir), - Commands::Convert { - private_key, - output_file, - password, - } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), - Commands::DeriveOperatorId { private_key } => todo!(), - } -} - -#[cfg(test)] -pub mod test { - use crate::{ - args::{Args, Commands, KeyType}, - execute_egnkey, - generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, - }; - use eth_keystore::decrypt_key; - use k256::SecretKey; - use rstest::rstest; - use std::fs; - use tempfile::tempdir; - - #[rstest] - #[case(KeyType::Ecdsa)] - #[case(KeyType::Bls)] - fn generate_key(#[case] key_type: KeyType) { - let output_dir = tempdir().unwrap(); - let output_path = output_dir.path(); - let command = Commands::Generate { - key_type: key_type.clone(), - num_keys: 1, - output_dir: output_path.to_str().map(String::from), - }; - let args = Args { command }; - - execute_egnkey(args).unwrap(); - - let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); - let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); - let key_name = match key_type { - KeyType::Ecdsa => "ecdsa", - KeyType::Bls => "bls", - }; - let key_path = output_path - .join(DEFAULT_KEY_FOLDER) - .join(format!("1.{}.key.json", key_name)); - - let decrypted_bytes = decrypt_key(key_path, password).unwrap(); - let decrypted_private_key = SecretKey::from_slice(&decrypted_bytes).unwrap().to_bytes(); - - let private_key = hex::decode(private_key_hex).unwrap(); - - assert_eq!(private_key, decrypted_private_key.as_slice()); - } -} diff --git a/crates/eigen-cli/egnkey/src/main.rs b/crates/eigen-cli/egnkey/src/main.rs deleted file mode 100644 index 10f371fc..00000000 --- a/crates/eigen-cli/egnkey/src/main.rs +++ /dev/null @@ -1,8 +0,0 @@ -use clap::Parser; -use egnkey::{args::Args, execute_egnkey}; - -#[tokio::main] -async fn main() { - let args = Args::parse(); - execute_egnkey(args).unwrap(); -} diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index d09c2cdc..75addf00 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -42,4 +42,60 @@ outputs addresses for all relevant Eigenlayer and AVS contracts within the netwo #[arg(long, help = "rpc url", default_value = ANVIL_RPC_URL)] rpc_url: String, }, + #[command( + about = "Generate keys for testing purpose. +This command creates ecdsa or bls key pair for testing purposes. It generates +all the relevant files for reading and keys and decrypted it and also gets +you the private keys in plaintext. + +It creates the following artifacts based on arguments +- passwords.txt - contains all passwords to decrypt keys +- private_key_hex.txt - will create plaintext private keys +- keys/* - create all the encrypted json files in this folder", + alias = "g" + )] + Generate { + #[arg(long, help = "key type to create (ecdsa or bls)")] + #[clap(value_enum)] + key_type: KeyType, + + #[arg(long, help = "number of keys to create", default_value = "1")] + num_keys: u32, + + #[arg(long, help = "folder to store keys")] + output_dir: Option, + }, + + #[command( + about = "Given a private key, output its associated operatorId (hash of bn254 G1 pubkey).", + alias = "d" + )] + DeriveOperatorId { + #[arg( + long, + help = "(bn254) private key from which to derive operatorId from" + )] + private_key: String, + }, + + #[command( + about = "Stores an ecdsa key to a file, in web3 secret storage format.", + alias = "c" + )] + Convert { + #[arg(long, help = "private key to store (in hex)")] + private_key: String, + + #[arg(long, help = "file to store key")] + output_file: Option, + + #[arg(long, help = "password to encrypt key")] + password: Option, + }, +} + +#[derive(clap::ValueEnum, Debug, Clone)] +pub enum KeyType { + Ecdsa, + Bls, } diff --git a/crates/eigen-cli/egnkey/src/convert.rs b/crates/eigen-cli/src/convert.rs similarity index 100% rename from crates/eigen-cli/egnkey/src/convert.rs rename to crates/eigen-cli/src/convert.rs diff --git a/crates/eigen-cli/egnkey/src/generate.rs b/crates/eigen-cli/src/generate.rs similarity index 100% rename from crates/eigen-cli/egnkey/src/generate.rs rename to crates/eigen-cli/src/generate.rs diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 89fc68cf..17b3809d 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -8,6 +8,14 @@ use alloy_transport::TransportErrorKind; use thiserror::Error; pub mod args; pub mod eigen_address; +use args::{Args, Commands}; +use convert::store; +use generate::KeyGenerator; +mod convert; +mod generate; +use crate::eigen_address::ContractAddresses; +use eth_keystore::KeystoreError; +use tokio::runtime::Runtime; pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; @@ -20,15 +28,101 @@ pub enum EigenAddressCliError { RpcError(RpcError), } +#[derive(Error, Debug)] +pub enum EigenKeyCliError { + #[error("file error")] + FileError(std::io::Error), + #[error("encription error")] + KeystoreError(KeystoreError), +} + +pub fn execute_command(args: Args) -> Result<(), EigenKeyCliError> { + match args.command { + Commands::GetAddresses { + service_manager, + registry_coordinator, + rpc_url, + } => { + let rt = Runtime::new().unwrap(); + rt.block_on(async { + let addresses = ContractAddresses::get_addresses( + service_manager, + registry_coordinator, + rpc_url, + ) + .await + .unwrap(); + println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); + }); + // TODO: add error handling + Ok(()) + } + Commands::Generate { + key_type, + num_keys, + output_dir, + } => KeyGenerator::from(key_type).generate(num_keys, output_dir), + Commands::Convert { + private_key, + output_file, + password, + } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), + Commands::DeriveOperatorId { private_key } => todo!(), + } +} + #[cfg(test)] -mod test { +pub mod test { use super::ANVIL_RPC_URL; use crate::eigen_address::ContractAddresses; + use crate::{ + args::{Args, Commands, KeyType}, + execute_command, + generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, + }; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, }; + use eth_keystore::decrypt_key; + use k256::SecretKey; + use rstest::rstest; + use std::fs; + use tempfile::tempdir; use tokio; + #[rstest] + #[case(KeyType::Ecdsa)] + #[case(KeyType::Bls)] + fn generate_key(#[case] key_type: KeyType) { + let output_dir = tempdir().unwrap(); + let output_path = output_dir.path(); + let command = Commands::Generate { + key_type: key_type.clone(), + num_keys: 1, + output_dir: output_path.to_str().map(String::from), + }; + let args = Args { command }; + + execute_command(args).unwrap(); + + let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); + let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); + let key_name = match key_type { + KeyType::Ecdsa => "ecdsa", + KeyType::Bls => "bls", + }; + let key_path = output_path + .join(DEFAULT_KEY_FOLDER) + .join(format!("1.{}.key.json", key_name)); + + let decrypted_bytes = decrypt_key(key_path, password).unwrap(); + let decrypted_private_key = SecretKey::from_slice(&decrypted_bytes).unwrap().to_bytes(); + + let private_key = hex::decode(private_key_hex).unwrap(); + + assert_eq!(private_key, decrypted_private_key.as_slice()); + } + #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; diff --git a/crates/eigen-cli/src/main.rs b/crates/eigen-cli/src/main.rs index 3c14127e..af7107f9 100644 --- a/crates/eigen-cli/src/main.rs +++ b/crates/eigen-cli/src/main.rs @@ -1,23 +1,7 @@ use clap::Parser; -use eigen_cli::{ - args::{Args, Commands}, - eigen_address::ContractAddresses, -}; +use eigen_cli::{args::Args, execute_command}; -#[tokio::main] -async fn main() { +fn main() { let args = Args::parse(); - match args.command { - Commands::GetAddresses { - service_manager, - registry_coordinator, - rpc_url, - } => { - let addresses = - ContractAddresses::get_addresses(service_manager, registry_coordinator, rpc_url) - .await - .unwrap(); - println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); - } - } + execute_command(args).unwrap(); } From bdf98e3ce5580e05cf6aacc99e8a2c8bb5dc2f85 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 12:45:34 -0300 Subject: [PATCH 22/36] change error handling in execute_command function --- crates/eigen-cli/src/lib.rs | 35 +++++++++++++++++++++-------------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 17b3809d..1691df83 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -19,6 +19,14 @@ use tokio::runtime::Runtime; pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; +#[derive(Error, Debug)] +pub enum EigenCliError { + #[error("address error")] + EigenAddressCliError(EigenAddressCliError), + #[error("key error")] + EigenKeyCliError(EigenKeyCliError), +} + /// Possible errors raised while trying to get contract addresses #[derive(Error, Debug)] pub enum EigenAddressCliError { @@ -36,7 +44,7 @@ pub enum EigenKeyCliError { KeystoreError(KeystoreError), } -pub fn execute_command(args: Args) -> Result<(), EigenKeyCliError> { +pub fn execute_command(args: Args) -> Result<(), EigenCliError> { match args.command { Commands::GetAddresses { service_manager, @@ -44,29 +52,28 @@ pub fn execute_command(args: Args) -> Result<(), EigenKeyCliError> { rpc_url, } => { let rt = Runtime::new().unwrap(); - rt.block_on(async { - let addresses = ContractAddresses::get_addresses( - service_manager, - registry_coordinator, - rpc_url, - ) - .await - .unwrap(); - println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); - }); - // TODO: add error handling + let addresses = rt.block_on(async { + ContractAddresses::get_addresses(service_manager, registry_coordinator, rpc_url) + .await + .map_err(EigenCliError::EigenAddressCliError) + })?; + println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); Ok(()) } Commands::Generate { key_type, num_keys, output_dir, - } => KeyGenerator::from(key_type).generate(num_keys, output_dir), + } => KeyGenerator::from(key_type) + .generate(num_keys, output_dir) + .map_err(EigenCliError::EigenKeyCliError), Commands::Convert { private_key, output_file, password, - } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), + } => store(private_key, output_file, password) + .map_err(EigenKeyCliError::KeystoreError) + .map_err(EigenCliError::EigenKeyCliError), Commands::DeriveOperatorId { private_key } => todo!(), } } From 6cf80a6b6a07040d3f947688f5007ec34d2bcf2d Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 13:14:46 -0300 Subject: [PATCH 23/36] change args commands so that it matches the eigensdk-go spec --- crates/eigen-cli/src/args.rs | 14 ++++++++-- crates/eigen-cli/src/lib.rs | 51 ++++++++++++++++++++---------------- crates/eigen-cli/src/main.rs | 2 +- 3 files changed, 42 insertions(+), 25 deletions(-) diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index 75addf00..a4f01cd6 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -17,14 +17,14 @@ pub enum Commands { #[command( about = "Given an initial contract address, which can be either a registry coordinator or service manager address, outputs addresses for all relevant Eigenlayer and AVS contracts within the network", - alias = "a", + name = "egnaddrs", group( ArgGroup::new("manager_or_coordinator") .required(true) .args(&["service_manager", "registry_coordinator"]), ) )] - GetAddresses { + EigenAddress { #[arg( long, help = "ServiceManager contract address", @@ -42,6 +42,16 @@ outputs addresses for all relevant Eigenlayer and AVS contracts within the netwo #[arg(long, help = "rpc url", default_value = ANVIL_RPC_URL)] rpc_url: String, }, + + #[command(about = "EigenLayer CLI Key tools", name = "egnkey")] + EigenKey { + #[command(subcommand)] + subcommand: EigenKeyCommand, + }, +} + +#[derive(Subcommand, Debug)] +pub enum EigenKeyCommand { #[command( about = "Generate keys for testing purpose. This command creates ecdsa or bls key pair for testing purposes. It generates diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 1691df83..71357aed 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -8,7 +8,7 @@ use alloy_transport::TransportErrorKind; use thiserror::Error; pub mod args; pub mod eigen_address; -use args::{Args, Commands}; +use args::{Args, Commands, EigenKeyCommand}; use convert::store; use generate::KeyGenerator; mod convert; @@ -44,9 +44,29 @@ pub enum EigenKeyCliError { KeystoreError(KeystoreError), } -pub fn execute_command(args: Args) -> Result<(), EigenCliError> { - match args.command { - Commands::GetAddresses { +pub fn execute_egnkey(subcommand: EigenKeyCommand) -> Result<(), EigenCliError> { + match subcommand { + EigenKeyCommand::Generate { + key_type, + num_keys, + output_dir, + } => KeyGenerator::from(key_type) + .generate(num_keys, output_dir) + .map_err(EigenCliError::EigenKeyCliError), + EigenKeyCommand::Convert { + private_key, + output_file, + password, + } => store(private_key, output_file, password) + .map_err(EigenKeyCliError::KeystoreError) + .map_err(EigenCliError::EigenKeyCliError), + EigenKeyCommand::DeriveOperatorId { private_key } => todo!(), + } +} + +pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { + match command { + Commands::EigenAddress { service_manager, registry_coordinator, rpc_url, @@ -60,27 +80,14 @@ pub fn execute_command(args: Args) -> Result<(), EigenCliError> { println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); Ok(()) } - Commands::Generate { - key_type, - num_keys, - output_dir, - } => KeyGenerator::from(key_type) - .generate(num_keys, output_dir) - .map_err(EigenCliError::EigenKeyCliError), - Commands::Convert { - private_key, - output_file, - password, - } => store(private_key, output_file, password) - .map_err(EigenKeyCliError::KeystoreError) - .map_err(EigenCliError::EigenKeyCliError), - Commands::DeriveOperatorId { private_key } => todo!(), + Commands::EigenKey { subcommand } => execute_egnkey(subcommand), } } #[cfg(test)] pub mod test { use super::ANVIL_RPC_URL; + use crate::args::EigenKeyCommand; use crate::eigen_address::ContractAddresses; use crate::{ args::{Args, Commands, KeyType}, @@ -103,14 +110,14 @@ pub mod test { fn generate_key(#[case] key_type: KeyType) { let output_dir = tempdir().unwrap(); let output_path = output_dir.path(); - let command = Commands::Generate { + let subcommand = EigenKeyCommand::Generate { key_type: key_type.clone(), num_keys: 1, output_dir: output_path.to_str().map(String::from), }; - let args = Args { command }; + let command = Commands::EigenKey { subcommand }; - execute_command(args).unwrap(); + execute_command(command).unwrap(); let private_key_hex = fs::read_to_string(output_path.join(PRIVATE_KEY_HEX_FILE)).unwrap(); let password = fs::read_to_string(output_path.join(PASSWORD_FILE)).unwrap(); diff --git a/crates/eigen-cli/src/main.rs b/crates/eigen-cli/src/main.rs index af7107f9..2eb13bc0 100644 --- a/crates/eigen-cli/src/main.rs +++ b/crates/eigen-cli/src/main.rs @@ -3,5 +3,5 @@ use eigen_cli::{args::Args, execute_command}; fn main() { let args = Args::parse(); - execute_command(args).unwrap(); + execute_command(args.command).unwrap(); } From 9ba38159acdfc51b313037d674db7009f3ca556e Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 14:40:17 -0300 Subject: [PATCH 24/36] add documentation --- crates/eigen-cli/src/lib.rs | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 71357aed..63618da5 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -8,7 +8,7 @@ use alloy_transport::TransportErrorKind; use thiserror::Error; pub mod args; pub mod eigen_address; -use args::{Args, Commands, EigenKeyCommand}; +use args::{Commands, EigenKeyCommand}; use convert::store; use generate::KeyGenerator; mod convert; @@ -44,7 +44,20 @@ pub enum EigenKeyCliError { KeystoreError(KeystoreError), } -pub fn execute_egnkey(subcommand: EigenKeyCommand) -> Result<(), EigenCliError> { +/// Executes a CLI command. +/// +/// # Arguments +/// +/// * `command` - An egnkey subcommand which can be `generate`, `convert` or `derive-operator-id`. +/// +/// # Returns +/// +/// - Nothing (unit type ()). +/// +/// # Errors +/// +/// - If the subcommand execution fails (see `EigenKeyCliError`). +pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), EigenCliError> { match subcommand { EigenKeyCommand::Generate { key_type, @@ -64,6 +77,19 @@ pub fn execute_egnkey(subcommand: EigenKeyCommand) -> Result<(), EigenCliError> } } +/// Executes a CLI command. +/// +/// # Arguments +/// +/// * `command` - A CLI command which can be `egnaddrs` or `egnkey` +/// +/// # Returns +/// +/// - Nothing (unit type ()). +/// +/// # Errors +/// +/// - If the command execution fails (see `EigenCliError`). pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { match command { Commands::EigenAddress { @@ -80,7 +106,7 @@ pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); Ok(()) } - Commands::EigenKey { subcommand } => execute_egnkey(subcommand), + Commands::EigenKey { subcommand } => execute_egnkey_subcommand(subcommand), } } @@ -90,7 +116,7 @@ pub mod test { use crate::args::EigenKeyCommand; use crate::eigen_address::ContractAddresses; use crate::{ - args::{Args, Commands, KeyType}, + args::{Commands, KeyType}, execute_command, generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, }; From ed13aeb2b642aeb01a510aea79629b8854228508 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 16:00:27 -0300 Subject: [PATCH 25/36] add derive-operator-id command implementation --- Cargo.lock | 7 +++++-- crates/eigen-cli/Cargo.toml | 6 ++++-- crates/eigen-cli/src/lib.rs | 12 ++++++++++-- crates/eigen-cli/src/operator_id.rs | 18 ++++++++++++++++++ 4 files changed, 37 insertions(+), 6 deletions(-) create mode 100644 crates/eigen-cli/src/operator_id.rs diff --git a/Cargo.lock b/Cargo.lock index 702a08e8..94de73fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1962,15 +1962,18 @@ dependencies = [ "alloy-primitives", "alloy-provider", "alloy-transport", + "ark-ec", "ark-ff 0.4.2", "ark-serialize 0.4.2", "clap", "eigen-crypto-bls", "eigen-testing-utils", + "eigen-types", "eigen-utils", "eth-keystore", "hex", "k256", + "num-bigint", "rand", "rand_core", "rstest", @@ -3916,9 +3919,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index 64988050..2bf2f15b 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -16,6 +16,7 @@ ark-serialize = "0.4.2" clap.workspace = true eigen-crypto-bls.workspace = true eigen-testing-utils.workspace = true +eigen-types.workspace = true eigen-utils.workspace = true eth-keystore.workspace = true hex.workspace = true @@ -27,8 +28,9 @@ serde_json.workspace = true thiserror.workspace = true tokio.workspace = true uuid = { version = "1.10.0", features = ["v4"] } - +ark-ec = "0.4" +num-bigint = "0.4.6" [dev-dependencies] eigen-testing-utils.workspace = true rstest = "0.22.0" -tempfile = "3" \ No newline at end of file +tempfile = "3" diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 63618da5..0d772365 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -11,8 +11,10 @@ pub mod eigen_address; use args::{Commands, EigenKeyCommand}; use convert::store; use generate::KeyGenerator; +use operator_id::derive_operator_id; mod convert; mod generate; +mod operator_id; use crate::eigen_address::ContractAddresses; use eth_keystore::KeystoreError; use tokio::runtime::Runtime; @@ -73,7 +75,10 @@ pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), Eige } => store(private_key, output_file, password) .map_err(EigenKeyCliError::KeystoreError) .map_err(EigenCliError::EigenKeyCliError), - EigenKeyCommand::DeriveOperatorId { private_key } => todo!(), + EigenKeyCommand::DeriveOperatorId { private_key } => { + derive_operator_id(private_key); + Ok(()) + } } } @@ -106,7 +111,10 @@ pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { println!("{}", serde_json::to_string_pretty(&addresses).unwrap()); Ok(()) } - Commands::EigenKey { subcommand } => execute_egnkey_subcommand(subcommand), + Commands::EigenKey { subcommand } => { + execute_egnkey_subcommand(subcommand); + Ok(()) + } } } diff --git a/crates/eigen-cli/src/operator_id.rs b/crates/eigen-cli/src/operator_id.rs new file mode 100644 index 00000000..3bd1b629 --- /dev/null +++ b/crates/eigen-cli/src/operator_id.rs @@ -0,0 +1,18 @@ +use alloy_primitives::keccak256; +use ark_ec::CurveGroup; +use eigen_crypto_bls::attestation::KeyPair; + +pub fn derive_operator_id(private_key: String) { + let key_pair = KeyPair::from_string(private_key).unwrap(); + let pub_key = key_pair.get_pub_key_g1(); + let pub_key_affine = pub_key.into_affine(); + + let x_int: num_bigint::BigUint = pub_key_affine.x.into(); + let y_int: num_bigint::BigUint = pub_key_affine.y.into(); + + let x_bytes = x_int.to_bytes_be(); + let y_bytes = y_int.to_bytes_be(); + + let hash = keccak256([x_bytes, y_bytes].concat()); + println!("{}", hex::encode(hash)); +} From f371a7a936d378cc232bc90fd30ceaef8f83ad29 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 16:25:56 -0300 Subject: [PATCH 26/36] add test for derive-operator-id command --- crates/eigen-cli/Cargo.toml | 1 + crates/eigen-cli/src/lib.rs | 14 +++++++++++++- crates/eigen-cli/src/operator_id.rs | 4 ++-- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index 2bf2f15b..a54079e4 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -30,6 +30,7 @@ tokio.workspace = true uuid = { version = "1.10.0", features = ["v4"] } ark-ec = "0.4" num-bigint = "0.4.6" + [dev-dependencies] eigen-testing-utils.workspace = true rstest = "0.22.0" diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 0d772365..ef11d446 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -76,7 +76,8 @@ pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), Eige .map_err(EigenKeyCliError::KeystoreError) .map_err(EigenCliError::EigenKeyCliError), EigenKeyCommand::DeriveOperatorId { private_key } => { - derive_operator_id(private_key); + let operator_id = derive_operator_id(private_key); + println!("{}", operator_id); Ok(()) } } @@ -127,6 +128,7 @@ pub mod test { args::{Commands, KeyType}, execute_command, generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, + operator_id::derive_operator_id, }; use eigen_testing_utils::anvil_constants::{ get_registry_coordinator_address, get_service_manager_address, @@ -171,6 +173,16 @@ pub mod test { assert_eq!(private_key, decrypted_private_key.as_slice()); } + #[test] + fn egnkey_derive_operator_id() { + let private_key = + "1e4fa82657771dc209c466a0c2f696b39320a0284bf725cf1740971fe7e2d3cf".to_string(); + let operator_id = derive_operator_id(private_key); + let expected_operator_id = + "48beccce16ccdf8000c13d5af5f91c7c3dac6c47b339d993d229af1500dbe4a9".to_string(); + assert_eq!(expected_operator_id, operator_id); + } + #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; diff --git a/crates/eigen-cli/src/operator_id.rs b/crates/eigen-cli/src/operator_id.rs index 3bd1b629..ab6d7d47 100644 --- a/crates/eigen-cli/src/operator_id.rs +++ b/crates/eigen-cli/src/operator_id.rs @@ -2,7 +2,7 @@ use alloy_primitives::keccak256; use ark_ec::CurveGroup; use eigen_crypto_bls::attestation::KeyPair; -pub fn derive_operator_id(private_key: String) { +pub fn derive_operator_id(private_key: String) -> String { let key_pair = KeyPair::from_string(private_key).unwrap(); let pub_key = key_pair.get_pub_key_g1(); let pub_key_affine = pub_key.into_affine(); @@ -14,5 +14,5 @@ pub fn derive_operator_id(private_key: String) { let y_bytes = y_int.to_bytes_be(); let hash = keccak256([x_bytes, y_bytes].concat()); - println!("{}", hex::encode(hash)); + hex::encode(hash) } From 13fe3f32fe1d1f468f853187679b58ddaa8c8f05 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 17:08:07 -0300 Subject: [PATCH 27/36] add documentation and error handling --- crates/eigen-cli/src/generate.rs | 2 -- crates/eigen-cli/src/lib.rs | 50 +++++++++++++---------------- crates/eigen-cli/src/operator_id.rs | 21 +++++++++--- 3 files changed, 40 insertions(+), 33 deletions(-) diff --git a/crates/eigen-cli/src/generate.rs b/crates/eigen-cli/src/generate.rs index ff59337a..63284cdb 100644 --- a/crates/eigen-cli/src/generate.rs +++ b/crates/eigen-cli/src/generate.rs @@ -29,7 +29,6 @@ impl KeyGenerator { /// /// # Arguments /// - /// * `key_type` - The type of the key to generate. /// * `num_keys` - The number of keys to generate. /// * `output_dir` - The directory where the key files are generated. pub fn generate( @@ -61,7 +60,6 @@ impl KeyGenerator { /// /// * `num_keys` - The number of keys to generate. /// * `path` - The path to the directory where the generated files are stored. - /// * `password` - The password used to encrypt the keys. fn generate_keys(self, num_keys: u32, path: &Path) -> Result<(), EigenKeyCliError> { let key_path = path.join(DEFAULT_KEY_FOLDER); let private_key_path = path.join(PRIVATE_KEY_HEX_FILE); diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index ef11d446..295e5c38 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -2,25 +2,27 @@ html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] +use crate::eigen_address::ContractAddresses; use alloy_contract::Error as ContractError; use alloy_json_rpc::RpcError; use alloy_transport::TransportErrorKind; -use thiserror::Error; -pub mod args; -pub mod eigen_address; use args::{Commands, EigenKeyCommand}; use convert::store; +use eigen_crypto_bls::error::BlsError; use generate::KeyGenerator; use operator_id::derive_operator_id; +use thiserror::Error; +pub mod args; mod convert; +pub mod eigen_address; mod generate; mod operator_id; -use crate::eigen_address::ContractAddresses; use eth_keystore::KeystoreError; use tokio::runtime::Runtime; pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; +/// Possible errors raised while executing a CLI command #[derive(Error, Debug)] pub enum EigenCliError { #[error("address error")] @@ -38,45 +40,43 @@ pub enum EigenAddressCliError { RpcError(RpcError), } +/// Possible errors raised while executing egnkey commands #[derive(Error, Debug)] pub enum EigenKeyCliError { #[error("file error")] FileError(std::io::Error), #[error("encription error")] KeystoreError(KeystoreError), + #[error("BLS error")] + BLSError(BlsError), } -/// Executes a CLI command. +/// Executes an `egnkey` subcommand. /// /// # Arguments /// -/// * `command` - An egnkey subcommand which can be `generate`, `convert` or `derive-operator-id`. -/// -/// # Returns -/// -/// - Nothing (unit type ()). +/// * `subcommand` - An egnkey subcommand which can be `generate`, `convert` or `derive-operator-id`. /// /// # Errors /// -/// - If the subcommand execution fails (see `EigenKeyCliError`). -pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), EigenCliError> { +/// - If the subcommand execution fails (`EigenKeyCliError`). +pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), EigenKeyCliError> { match subcommand { EigenKeyCommand::Generate { key_type, num_keys, output_dir, - } => KeyGenerator::from(key_type) - .generate(num_keys, output_dir) - .map_err(EigenCliError::EigenKeyCliError), + } => KeyGenerator::from(key_type).generate(num_keys, output_dir), + EigenKeyCommand::Convert { private_key, output_file, password, - } => store(private_key, output_file, password) - .map_err(EigenKeyCliError::KeystoreError) - .map_err(EigenCliError::EigenKeyCliError), + } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), + EigenKeyCommand::DeriveOperatorId { private_key } => { - let operator_id = derive_operator_id(private_key); + let operator_id = + derive_operator_id(private_key).map_err(EigenKeyCliError::BLSError)?; println!("{}", operator_id); Ok(()) } @@ -87,15 +87,11 @@ pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), Eige /// /// # Arguments /// -/// * `command` - A CLI command which can be `egnaddrs` or `egnkey` -/// -/// # Returns -/// -/// - Nothing (unit type ()). +/// * `command` - A CLI command which can be `Commands::EigenAddress` or `Commands::EigenKey` /// /// # Errors /// -/// - If the command execution fails (see `EigenCliError`). +/// - If the command execution fails (`EigenCliError`). pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { match command { Commands::EigenAddress { @@ -113,7 +109,7 @@ pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { Ok(()) } Commands::EigenKey { subcommand } => { - execute_egnkey_subcommand(subcommand); + execute_egnkey_subcommand(subcommand).map_err(EigenCliError::EigenKeyCliError)?; Ok(()) } } @@ -177,7 +173,7 @@ pub mod test { fn egnkey_derive_operator_id() { let private_key = "1e4fa82657771dc209c466a0c2f696b39320a0284bf725cf1740971fe7e2d3cf".to_string(); - let operator_id = derive_operator_id(private_key); + let operator_id = derive_operator_id(private_key).unwrap(); let expected_operator_id = "48beccce16ccdf8000c13d5af5f91c7c3dac6c47b339d993d229af1500dbe4a9".to_string(); assert_eq!(expected_operator_id, operator_id); diff --git a/crates/eigen-cli/src/operator_id.rs b/crates/eigen-cli/src/operator_id.rs index ab6d7d47..4dbad54a 100644 --- a/crates/eigen-cli/src/operator_id.rs +++ b/crates/eigen-cli/src/operator_id.rs @@ -1,9 +1,22 @@ use alloy_primitives::keccak256; use ark_ec::CurveGroup; -use eigen_crypto_bls::attestation::KeyPair; +use eigen_crypto_bls::{attestation::KeyPair, error::BlsError}; -pub fn derive_operator_id(private_key: String) -> String { - let key_pair = KeyPair::from_string(private_key).unwrap(); +/// Derives an operator ID from a private key +/// +/// # Arguments +/// +/// * `private_key` - A private key used to derive the operator ID +/// +/// # Returns +/// +/// * The operator ID as `String` +/// +/// # Errors +/// +/// * If the private key is not valid +pub fn derive_operator_id(private_key: String) -> Result { + let key_pair = KeyPair::from_string(private_key)?; let pub_key = key_pair.get_pub_key_g1(); let pub_key_affine = pub_key.into_affine(); @@ -14,5 +27,5 @@ pub fn derive_operator_id(private_key: String) -> String { let y_bytes = y_int.to_bytes_be(); let hash = keccak256([x_bytes, y_bytes].concat()); - hex::encode(hash) + Ok(hex::encode(hash)) } From 5a540fb9c767b48913e2a777c3a4ca4865584493 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Wed, 7 Aug 2024 18:12:34 -0300 Subject: [PATCH 28/36] fix cargo.toml --- Cargo.toml | 29 ++++++++++++++++++----------- crates/eigen-cli/Cargo.toml | 15 ++++++++------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 93133714..e131dd46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,30 +4,30 @@ members = [ "crates/chainio/clients/elcontracts/", "crates/chainio/clients/eth/", "crates/chainio/clients/fireblocks/", - "crates/contracts/bindings/", "crates/chainio/utils/", - "crates/crypto/bn254/", - "crates/utils/", + "crates/contracts/bindings/", "crates/crypto/bls/", + "crates/crypto/bn254/", "crates/crypto/keystore/", "crates/eigen-cli/", + "crates/logging/", + "crates/metrics/", "crates/metrics/collectors/economic/", "crates/metrics/collectors/rpc_calls/", + "crates/metrics/metrics-derive", "crates/services/avsregistry/", "crates/services/bls_aggregation/", - "crates/metrics/metrics-derive", "crates/services/operatorsinfo/", - "crates/types/", - "crates/metrics/", - "crates/types/", "crates/signer/", - "crates/logging/", "crates/signer/", - "examples/info-operator-service/", - "testing/testing-utils/", + "crates/types/", + "crates/types/", + "crates/utils/", + "examples/anvil-utils", "examples/avsregistry-read", "examples/avsregistry-write", - "examples/anvil-utils", + "examples/info-operator-service/", + "testing/testing-utils/", ] resolver = "2" @@ -49,7 +49,9 @@ rust.rust_2018_idioms = { level = "deny", priority = -1 } rustdoc.all = "warn" [workspace.dependencies] +ark-ec = "0.4" ark-ff = "0.4.0" +ark-serialize = "0.4.2" async-trait = "0.1.81" aws-config = "1.5.4" aws-sdk-kms = "1.37.0" @@ -86,21 +88,26 @@ info-operator-service = { path = "examples/info-operator-service" } k256 = "0.13.3" metrics = "0.21.1" metrics-exporter-prometheus = "0.12.0" +num-bigint = "0.4.6" once_cell = "1.17" prometheus-client = "0.22.2" quote = "1.0" +rand = "0.8" rand_core = "0.6" reqwest = "0.12.4" reth = { git = "https://github.com/paradigmxyz/reth" } +rstest = "0.22.0" serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.121" syn = "2.0" +tempfile = "3" testcontainers = "0.20.1" thiserror = "1.0" tokio = { version = "1.37.0", features = ["test-util", "full", "sync"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3", features = ["json"] } url = "2.5.2" +uuid = { version = "1.10.0", features = ["v4"] } #misc parking_lot = "0.12" diff --git a/crates/eigen-cli/Cargo.toml b/crates/eigen-cli/Cargo.toml index a54079e4..27b4bb67 100644 --- a/crates/eigen-cli/Cargo.toml +++ b/crates/eigen-cli/Cargo.toml @@ -11,8 +11,9 @@ alloy-json-rpc.workspace = true alloy-primitives.workspace = true alloy-provider.workspace = true alloy-transport.workspace = true +ark-ec.workspace = true ark-ff.workspace = true -ark-serialize = "0.4.2" +ark-serialize.workspace = true clap.workspace = true eigen-crypto-bls.workspace = true eigen-testing-utils.workspace = true @@ -21,17 +22,17 @@ eigen-utils.workspace = true eth-keystore.workspace = true hex.workspace = true k256.workspace = true -rand = "0.8" +num-bigint.workspace = true +rand.workspace = true rand_core.workspace = true serde.workspace = true serde_json.workspace = true thiserror.workspace = true tokio.workspace = true -uuid = { version = "1.10.0", features = ["v4"] } -ark-ec = "0.4" -num-bigint = "0.4.6" +uuid.workspace = true + [dev-dependencies] eigen-testing-utils.workspace = true -rstest = "0.22.0" -tempfile = "3" +rstest.workspace = true +tempfile.workspace = true From 5eca30eeafba6381e0814cece7786db1bdeb713d Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 8 Aug 2024 14:32:53 -0300 Subject: [PATCH 29/36] add test for 'convert' command --- Cargo.lock | 2 ++ Cargo.toml | 2 +- crates/eigen-cli/src/convert.rs | 15 +++++++-------- crates/eigen-cli/src/generate.rs | 4 ++-- crates/eigen-cli/src/lib.rs | 20 ++++++++++++++++++-- 5 files changed, 30 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 94de73fc..361ddfd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,6 +415,8 @@ dependencies = [ "alloy-primitives", "alloy-signer", "async-trait", + "elliptic-curve", + "eth-keystore", "k256", "rand", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index e131dd46..8f4f94d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,7 +142,7 @@ alloy-rpc-types-txpool = { version = "0.1", default-features = false } alloy-serde = { version = "0.1", default-features = false } alloy-signer = { version = "0.1", default-features = false } alloy-signer-aws = "0.1" -alloy-signer-local = { version = "0.1", default-features = false } +alloy-signer-local = { version = "0.1", features = ["keystore"] } alloy-sol-types = "0.7.2" alloy-transport = { version = "0.1" } alloy-transport-http = { version = "0.1", features = [ diff --git a/crates/eigen-cli/src/convert.rs b/crates/eigen-cli/src/convert.rs index 0d014757..74b59585 100644 --- a/crates/eigen-cli/src/convert.rs +++ b/crates/eigen-cli/src/convert.rs @@ -2,33 +2,32 @@ use eth_keystore::{encrypt_key, KeystoreError}; use rand_core::OsRng; use std::path::Path; +const DEFAULT_KEYSTORE_NAME: &str = "key.json"; + /// Stores an ecdsa key to a file, in web3 secret storage format. /// /// # Arguments /// -/// * `private_key` - A private key to store (in hexadecimal). +/// * `private_key` - A private key to store. /// * `output_file` - The name of the file where the key is going to be stored. -/// * `password` - The password used to encrypt the key. -/// -/// # Returns -/// -/// - Nothing (unit type ()). +/// * `password` - The password used to encrypt the key. *Note:* If `password` is `None` then the empty string is used as password. /// /// # Errors /// /// - If the key encryption fails. pub fn store( - private_key: String, + private_key: Vec, output_file: Option, password: Option, ) -> Result<(), KeystoreError> { let dir = Path::new("."); + encrypt_key( dir, &mut OsRng, private_key, password.unwrap_or_default(), - Some(output_file.unwrap_or("key.json".into()).as_str()), + Some(&output_file.unwrap_or(DEFAULT_KEYSTORE_NAME.into())), )?; Ok(()) diff --git a/crates/eigen-cli/src/generate.rs b/crates/eigen-cli/src/generate.rs index 63284cdb..2c851b16 100644 --- a/crates/eigen-cli/src/generate.rs +++ b/crates/eigen-cli/src/generate.rs @@ -115,7 +115,7 @@ impl KeyGenerator { /// # Returns /// /// * An ecdsa private key as a vector of bytes. - fn random_ecdsa_key() -> Vec { + pub fn random_ecdsa_key() -> Vec { let private_key = k256::SecretKey::random(&mut OsRng); private_key.to_bytes().as_slice().to_vec() } @@ -137,7 +137,7 @@ impl KeyGenerator { /// # Returns /// /// * A random password. - fn generate_random_password() -> String { + pub fn generate_random_password() -> String { rand::thread_rng() .sample_iter(&Alphanumeric) .take(PASSWORD_LENGTH) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 295e5c38..6ffc3619 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -72,7 +72,8 @@ pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), Eige private_key, output_file, password, - } => store(private_key, output_file, password).map_err(EigenKeyCliError::KeystoreError), + } => store(private_key.into(), output_file, password) + .map_err(EigenKeyCliError::KeystoreError), EigenKeyCommand::DeriveOperatorId { private_key } => { let operator_id = @@ -119,11 +120,12 @@ pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { pub mod test { use super::ANVIL_RPC_URL; use crate::args::EigenKeyCommand; + use crate::convert::store; use crate::eigen_address::ContractAddresses; use crate::{ args::{Commands, KeyType}, execute_command, - generate::{DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, + generate::{KeyGenerator, DEFAULT_KEY_FOLDER, PASSWORD_FILE, PRIVATE_KEY_HEX_FILE}, operator_id::derive_operator_id, }; use eigen_testing_utils::anvil_constants::{ @@ -179,6 +181,20 @@ pub mod test { assert_eq!(expected_operator_id, operator_id); } + #[test] + fn convert() { + let private_key = KeyGenerator::random_ecdsa_key(); + let password = KeyGenerator::generate_random_password(); + let file = "key.json".to_string(); + let path = "./key.json".to_string(); + + store(private_key.clone(), Some(file), Some(password.clone())).unwrap(); + let decrypted_key = decrypt_key(path.clone(), password).unwrap(); + std::fs::remove_file(path).unwrap(); + + assert_eq!(private_key, decrypted_key); + } + #[tokio::test] async fn egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; From a77ca67dd3677db6020515a69471a5d31fe8690d Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 8 Aug 2024 14:49:27 -0300 Subject: [PATCH 30/36] add serializaton error handling and fix Cargo.toml --- Cargo.lock | 2 -- Cargo.toml | 2 +- crates/eigen-cli/src/generate.rs | 20 +++++++++++--------- crates/eigen-cli/src/lib.rs | 3 +++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 361ddfd9..94de73fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -415,8 +415,6 @@ dependencies = [ "alloy-primitives", "alloy-signer", "async-trait", - "elliptic-curve", - "eth-keystore", "k256", "rand", "thiserror", diff --git a/Cargo.toml b/Cargo.toml index 8f4f94d7..e131dd46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -142,7 +142,7 @@ alloy-rpc-types-txpool = { version = "0.1", default-features = false } alloy-serde = { version = "0.1", default-features = false } alloy-signer = { version = "0.1", default-features = false } alloy-signer-aws = "0.1" -alloy-signer-local = { version = "0.1", features = ["keystore"] } +alloy-signer-local = { version = "0.1", default-features = false } alloy-sol-types = "0.7.2" alloy-transport = { version = "0.1" } alloy-transport-http = { version = "0.1", features = [ diff --git a/crates/eigen-cli/src/generate.rs b/crates/eigen-cli/src/generate.rs index 2c851b16..e9bf4472 100644 --- a/crates/eigen-cli/src/generate.rs +++ b/crates/eigen-cli/src/generate.rs @@ -1,7 +1,7 @@ use crate::args::KeyType; use crate::EigenKeyCliError; use ark_ff::UniformRand; -use ark_serialize::CanonicalSerialize; +use ark_serialize::{CanonicalSerialize, SerializationError}; use eigen_crypto_bls; use eth_keystore::encrypt_key; use k256; @@ -67,7 +67,9 @@ impl KeyGenerator { for i in 0..num_keys { let password = KeyGenerator::generate_random_password(); - let private_key = self.random_key(); + let private_key = self + .random_key() + .map_err(EigenKeyCliError::SerializationError)?; let private_key_hex = hex::encode(private_key.clone()); // encrypt the private key into `path` directory @@ -98,15 +100,15 @@ impl KeyGenerator { Ok(()) } - /// Generates a random key which can be of type ecdsa or BLS. + /// Generates a random key which can be type ecdsa or BLS. /// /// # Returns /// /// * A private key as a vector of bytes. - fn random_key(&self) -> Vec { + fn random_key(&self) -> Result, SerializationError> { match self { - KeyGenerator::ECDSAKeyGenerator => Self::random_ecdsa_key(), - KeyGenerator::BLSKeyGenerator => Self::random_bls_key(), + KeyGenerator::ECDSAKeyGenerator => Ok(Self::random_ecdsa_key()), + KeyGenerator::BLSKeyGenerator => Ok(Self::random_bls_key()?), } } @@ -125,11 +127,11 @@ impl KeyGenerator { /// # Returns /// /// * A BLS private key as a vector of bytes. - fn random_bls_key() -> Vec { + fn random_bls_key() -> Result, SerializationError> { let mut buffer = Vec::new(); let private_key = eigen_crypto_bls::PrivateKey::rand(&mut OsRng); - private_key.serialize_uncompressed(&mut buffer).unwrap(); // handle unwrap - buffer + private_key.serialize_uncompressed(&mut buffer)?; + Ok(buffer) } /// Generates a 20-character random password. diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 6ffc3619..9633cc37 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -7,6 +7,7 @@ use alloy_contract::Error as ContractError; use alloy_json_rpc::RpcError; use alloy_transport::TransportErrorKind; use args::{Commands, EigenKeyCommand}; +use ark_serialize::SerializationError; use convert::store; use eigen_crypto_bls::error::BlsError; use generate::KeyGenerator; @@ -49,6 +50,8 @@ pub enum EigenKeyCliError { KeystoreError(KeystoreError), #[error("BLS error")] BLSError(BlsError), + #[error("serialization error")] + SerializationError(SerializationError), } /// Executes an `egnkey` subcommand. From 9abfa5bad76319dc0ed92bcb14bef05ffd2d7936 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Thu, 8 Aug 2024 14:59:29 -0300 Subject: [PATCH 31/36] fix clippy warnings --- crates/eigen-cli/src/eigen_address.rs | 2 +- crates/eigen-cli/src/generate.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/eigen-cli/src/eigen_address.rs b/crates/eigen-cli/src/eigen_address.rs index e477955a..086bc6c1 100644 --- a/crates/eigen-cli/src/eigen_address.rs +++ b/crates/eigen-cli/src/eigen_address.rs @@ -105,7 +105,7 @@ impl ContractAddresses { /// # Returns /// /// * `(Address, Address)` - The registry coordinator and service manager contract addresses, - /// used to call `get_avs_contract_addresses` and `get_eigenlayer_contract_addresses` functions. + /// used to call `get_avs_contract_addresses` and `get_eigenlayer_contract_addresses` functions. async fn get_registry_coord_and_service_manager_addr( registry_coordinator: Option
, service_manager: Option
, diff --git a/crates/eigen-cli/src/generate.rs b/crates/eigen-cli/src/generate.rs index e9bf4472..94899067 100644 --- a/crates/eigen-cli/src/generate.rs +++ b/crates/eigen-cli/src/generate.rs @@ -2,9 +2,7 @@ use crate::args::KeyType; use crate::EigenKeyCliError; use ark_ff::UniformRand; use ark_serialize::{CanonicalSerialize, SerializationError}; -use eigen_crypto_bls; use eth_keystore::encrypt_key; -use k256; use rand::{distributions::Alphanumeric, Rng}; use rand_core::OsRng; use std::io::Write; @@ -39,7 +37,7 @@ impl KeyGenerator { let dir_name = match output_dir { None => { let id = Uuid::new_v4(); - format!("{}-{}", self.key_name(), id.to_string()) + format!("{}-{}", self.key_name(), id) } Some(dir) => dir, }; From 4d9bdb718e24c89282182fdd522794aaebe568e4 Mon Sep 17 00:00:00 2001 From: Pablo Deymonnaz Date: Thu, 8 Aug 2024 16:30:35 -0300 Subject: [PATCH 32/36] Update crates/eigen-cli/src/lib.rs --- crates/eigen-cli/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 9633cc37..1dbde6d8 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -120,7 +120,7 @@ pub fn execute_command(command: Commands) -> Result<(), EigenCliError> { } #[cfg(test)] -pub mod test { +mod test { use super::ANVIL_RPC_URL; use crate::args::EigenKeyCommand; use crate::convert::store; From 3b577ffda2e894b1cd8185d4a641048a203de37c Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 9 Aug 2024 09:29:03 -0300 Subject: [PATCH 33/36] rename EigenKeyCommand::Convert to ConvertECDSA and fix clippy warning --- crates/eigen-cli/src/args.rs | 2 +- crates/eigen-cli/src/lib.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index a4f01cd6..4aadda77 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -92,7 +92,7 @@ It creates the following artifacts based on arguments about = "Stores an ecdsa key to a file, in web3 secret storage format.", alias = "c" )] - Convert { + ConvertECDSA { #[arg(long, help = "private key to store (in hex)")] private_key: String, diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 1dbde6d8..009dad8a 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -71,7 +71,7 @@ pub fn execute_egnkey_subcommand(subcommand: EigenKeyCommand) -> Result<(), Eige output_dir, } => KeyGenerator::from(key_type).generate(num_keys, output_dir), - EigenKeyCommand::Convert { + EigenKeyCommand::ConvertECDSA { private_key, output_file, password, @@ -139,7 +139,6 @@ mod test { use rstest::rstest; use std::fs; use tempfile::tempdir; - use tokio; #[rstest] #[case(KeyType::Ecdsa)] From c0e9423d63adb1f93769469f8851f20e62a1c29d Mon Sep 17 00:00:00 2001 From: tomasarrachea Date: Fri, 9 Aug 2024 10:53:21 -0300 Subject: [PATCH 34/36] separate module declarations --- crates/eigen-cli/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 009dad8a..e2472f67 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -2,6 +2,14 @@ html_logo_url = "https://github.com/Layr-Labs/eigensdk-rs/assets/91280922/bd13caec-3c00-4afc-839a-b83d2890beb5", issue_tracker_base_url = "https://github.com/Layr-Labs/eigensdk-rs/issues/" )] +pub mod args; +mod convert; +pub mod eigen_address; +mod generate; +mod operator_id; +use eth_keystore::KeystoreError; +use tokio::runtime::Runtime; + use crate::eigen_address::ContractAddresses; use alloy_contract::Error as ContractError; use alloy_json_rpc::RpcError; @@ -13,13 +21,6 @@ use eigen_crypto_bls::error::BlsError; use generate::KeyGenerator; use operator_id::derive_operator_id; use thiserror::Error; -pub mod args; -mod convert; -pub mod eigen_address; -mod generate; -mod operator_id; -use eth_keystore::KeystoreError; -use tokio::runtime::Runtime; pub const ANVIL_RPC_URL: &str = "http://localhost:8545"; @@ -46,7 +47,7 @@ pub enum EigenAddressCliError { pub enum EigenKeyCliError { #[error("file error")] FileError(std::io::Error), - #[error("encription error")] + #[error("keystore error")] KeystoreError(KeystoreError), #[error("BLS error")] BLSError(BlsError), From fcdd811150c13af127b031715f3b6d066b63f5d3 Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 9 Aug 2024 11:03:41 -0300 Subject: [PATCH 35/36] add prefix 'test' to the cli tests --- crates/eigen-cli/src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/eigen-cli/src/lib.rs b/crates/eigen-cli/src/lib.rs index 009dad8a..41d06070 100644 --- a/crates/eigen-cli/src/lib.rs +++ b/crates/eigen-cli/src/lib.rs @@ -143,7 +143,7 @@ mod test { #[rstest] #[case(KeyType::Ecdsa)] #[case(KeyType::Bls)] - fn generate_key(#[case] key_type: KeyType) { + fn test_generate_key(#[case] key_type: KeyType) { let output_dir = tempdir().unwrap(); let output_path = output_dir.path(); let subcommand = EigenKeyCommand::Generate { @@ -174,7 +174,7 @@ mod test { } #[test] - fn egnkey_derive_operator_id() { + fn test_egnkey_derive_operator_id() { let private_key = "1e4fa82657771dc209c466a0c2f696b39320a0284bf725cf1740971fe7e2d3cf".to_string(); let operator_id = derive_operator_id(private_key).unwrap(); @@ -184,7 +184,7 @@ mod test { } #[test] - fn convert() { + fn test_convert_ecdsa() { let private_key = KeyGenerator::random_ecdsa_key(); let password = KeyGenerator::generate_random_password(); let file = "key.json".to_string(); @@ -198,7 +198,7 @@ mod test { } #[tokio::test] - async fn egnaddrs_with_service_manager_flag() { + async fn test_egnaddrs_with_service_manager_flag() { let service_manager_address = get_service_manager_address().await; let expected_addresses: ContractAddresses = serde_json::from_str( @@ -234,7 +234,7 @@ mod test { } #[tokio::test] - async fn egnaddrs_with_registry_coordinator_flag() { + async fn test_egnaddrs_with_registry_coordinator_flag() { let registry_coordinator_address = get_registry_coordinator_address().await; let expected_addresses: ContractAddresses = serde_json::from_str( From e89518baa2cfd435131a066607b531c19fea011b Mon Sep 17 00:00:00 2001 From: ricomateo Date: Fri, 9 Aug 2024 14:08:52 -0300 Subject: [PATCH 36/36] fix egnkey command description --- crates/eigen-cli/src/args.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/eigen-cli/src/args.rs b/crates/eigen-cli/src/args.rs index 4aadda77..40afea61 100644 --- a/crates/eigen-cli/src/args.rs +++ b/crates/eigen-cli/src/args.rs @@ -55,7 +55,7 @@ pub enum EigenKeyCommand { #[command( about = "Generate keys for testing purpose. This command creates ecdsa or bls key pair for testing purposes. It generates -all the relevant files for reading and keys and decrypted it and also gets +all the relevant files for reading the key and decrypts it and also gets you the private keys in plaintext. It creates the following artifacts based on arguments