diff --git a/Cargo.lock b/Cargo.lock index f388c1cb..07d65f33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1584,6 +1584,20 @@ dependencies = [ "tracing", ] +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "futures-core", + "getrandom", + "instant", + "pin-project-lite", + "rand", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -2486,6 +2500,7 @@ version = "0.1.1" dependencies = [ "alloy", "async-trait", + "backoff", "eigen-logging", "eigen-signer", "eigen-testing-utils", diff --git a/Cargo.toml b/Cargo.toml index 28e08347..c4896552 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,14 @@ rust.rust_2018_idioms = { level = "deny", priority = -1 } rustdoc.all = "warn" clippy.unwrap_used = "warn" clippy.expect_used = "warn" +clippy.panic = "warn" clippy.todo = "warn" +clippy.indexing_slicing = "warn" +clippy.string_slice = "warn" +clippy.panic_in_result_fn = "warn" +clippy.panicking_overflow_checks = "warn" +clippy.question_mark = "warn" +clippy.implicit_return = "allow" [workspace.dependencies] ark-bn254 = "0.5.0" @@ -56,6 +63,7 @@ ark-serialize = "0.5.0" async-trait = "0.1.83" aws-config = "1.5.9" aws-sdk-kms = "1.49.0" +backoff = { version = "0.4.0", features = ["futures", "tokio"] } clap = { version = "4.5.20", features = ["derive"] } eigen-chainio-txmanager = { path = "crates/chainio/txmanager/" } eigen-client-avsregistry = { path = "crates/chainio/clients/avsregistry" } @@ -110,14 +118,23 @@ tracing-subscriber = { version = "0.3", features = ["json"] } url = "2.5" #misc -rust-bls-bn254 = { version = "0.2.1" , features = ["std"] } +rust-bls-bn254 = { version = "0.2.1", features = ["std"] } uuid = { version = "1.11", features = ["v4"] } #misc parking_lot = "0.12" + +anvil-utils = { path = "examples/anvil-utils" } + #alloy +alloy = { version = "0.7.0", features = [ + "sol-types", + "contract", + "full", + "signer-aws", +] } alloy-json-rpc = { version = "0.7", default-features = false } alloy-network = { version = "0.7", default-features = false } alloy-node-bindings = { version = "0.7", default-features = false } @@ -138,10 +155,11 @@ alloy-signer-aws = "0.7" alloy-signer-local = { version = "0.7", default-features = false } alloy-sol-types = "0.8" alloy-transport = { version = "0.7" } -alloy-transport-http = { version = "0.7", features = ["reqwest-rustls-tls"], default-features = false } +alloy-transport-http = { version = "0.7", features = [ + "reqwest-rustls-tls", +], default-features = false } alloy-transport-ipc = { version = "0.7.0", default-features = false } alloy-transport-ws = { version = "0.7.0", default-features = false } -alloy = { version = "0.7.0", features = ["sol-types", "contract","full","signer-aws"] } -anvil-utils = { path = "examples/anvil-utils" } + avsregistry-read = { path = "examples/avsregistry-read" } avsregistry-write = { path = "examples/avsregistry-write" } diff --git a/README.md b/README.md index 0c8e5649..ef90011f 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,26 @@ Example : cargo run --example get_quorum_count ``` +## Contract Bindings + +The main branch of this repo is intended to be syncronized with mainnet version of core contracts. + +To update the bindings of this repo: + +- Inside the `crates/contracts` folder, run: + +```bash +forge bind --alloy --bindings-path /crates/utils --overwrite -C src/contracts +``` + +where `path-eigensdk-rs` is the full path to the eigensdk-rs (this) repo. + +This command will generate the bindings files in the folder: `/crates/utils`. + +⚠️ It rewrites Cargo.toml file, this file must be restored to the current version. + +- Fix all compilation warnings. + ## Contributor Guidelines We are actively looking for contributors. Thank you for your interest. We have strict ci checks in place. In case of any questions and support, feel free to raise an issue. @@ -105,7 +125,6 @@ Rolling `MSRV` policy of 6 months. The current `MSRV` is 1.79 🚧 Eigensdk-rs is under active development and has not been audited. Eigensdk-rs is rapidly being upgraded, features may be added, removed or otherwise improved or modified and interfaces will have breaking changes. Eigensdk-rs should be used only for testing purposes and not in production. Eigensdk-rs is provided "as is" and Eigen Labs, Inc. does not guarantee its functionality or provide support for its use in production. 🚧 - ## Credits - [eigensdk-go](https://github.com/Layr-Labs/eigensdk-go/tree/master) diff --git a/crates/chainio/clients/avsregistry/src/reader.rs b/crates/chainio/clients/avsregistry/src/reader.rs index 19471547..bdac856f 100644 --- a/crates/chainio/clients/avsregistry/src/reader.rs +++ b/crates/chainio/clients/avsregistry/src/reader.rs @@ -304,7 +304,6 @@ impl AvsRegistryChainReader { /// - a vector of the quorum numbers the operator was registered for at `block_number`. /// - for each of the quorums mentioned above, a vector of the operators registered for /// that quorum at `block_number`, containing each operator's `operatorId` and `stake`. - pub async fn get_operators_stake_in_quorums_of_operator_at_block( &self, operator_id: B256, @@ -399,6 +398,44 @@ impl AvsRegistryChainReader { Ok(quorum_stakes) } + /// Query registration detail + /// + /// # Arguments + /// + /// * `operator_address` - The operator address. + /// + /// # Returns + /// + /// A vector of booleans, where each boolean represents if the operator + /// is registered for a quorum. + /// + /// # Errors + /// + /// Returns an error if the operator id cannot be fetched or if the quorum bitmap + pub async fn query_registration_detail( + &self, + operator_address: Address, + ) -> Result<[bool; 64], AvsRegistryError> { + let operator_id = self.get_operator_id(operator_address).await?; + + let provider = get_provider(&self.provider); + let registry_coordinator = + RegistryCoordinator::new(self.registry_coordinator_addr, &provider); + let quorum_bitmap = registry_coordinator + .getCurrentQuorumBitmap(operator_id) + .call() + .await?; + + let inner_value = quorum_bitmap._0.into_limbs()[0]; + let mut quorums: [bool; 64] = [false; 64]; + for i in 0..64_u64 { + if let Some(value) = quorums.get_mut(i as usize) { + *value = inner_value & (1 << i) != 0; + } + } + Ok(quorums) + } + /// Get operator id /// /// # Arguments @@ -597,23 +634,18 @@ impl AvsRegistryChainReader { mod tests { use super::*; use eigen_logging::get_test_logger; + use eigen_testing_utils::m2_holesky_constants::{ + HOLESKY_RPC_PROVIDER, OPERATOR_STATE_RETRIEVER, REGISTRY_COORDINATOR, + }; use hex::FromHex; use std::str::FromStr; - const HOLESKY_REGISTRY_COORDINATOR: &str = "0x53012C69A189cfA2D9d29eb6F19B32e0A2EA3490"; - const HOLESKY_OPERATOR_STATE_RETRIEVER: &str = "0xB4baAfee917fb4449f5ec64804217bccE9f46C67"; async fn build_avs_registry_chain_reader() -> AvsRegistryChainReader { - let holesky_registry_coordinator = - Address::from_str(HOLESKY_REGISTRY_COORDINATOR).expect("failed to parse address"); - let holesky_operator_state_retriever = - Address::from_str(HOLESKY_OPERATOR_STATE_RETRIEVER).expect("failed to parse address"); - - let holesky_provider = "https://ethereum-holesky.blockpi.network/v1/rpc/public"; AvsRegistryChainReader::new( get_test_logger(), - holesky_registry_coordinator, - holesky_operator_state_retriever, - holesky_provider.to_string(), + REGISTRY_COORDINATOR, + OPERATOR_STATE_RETRIEVER, + HOLESKY_RPC_PROVIDER.to_string(), ) .await .unwrap() @@ -697,9 +729,11 @@ mod tests { #[tokio::test] async fn test_is_operator_registered() { let avs_reader = build_avs_registry_chain_reader().await; - let address = Address::from_str(HOLESKY_REGISTRY_COORDINATOR).unwrap(); - let is_registered = avs_reader.is_operator_registered(address).await.unwrap(); + let is_registered = avs_reader + .is_operator_registered(REGISTRY_COORDINATOR) + .await + .unwrap(); assert!(!is_registered); } @@ -727,4 +761,40 @@ mod tests { .await .unwrap(); } + + #[tokio::test] + async fn test_query_registration_detail() { + let avs_reader = build_avs_registry_chain_reader().await; + + let operator_id = U256::from_str( + "35344093966194310405039483339636912150346494903629410125452342281826147822033", + ) + .unwrap(); + + let operator_id_b256: B256 = operator_id.into(); + + let operator_address = avs_reader + .get_operator_from_id(operator_id_b256.into()) + .await + .unwrap(); + + let ret_query_registration_detail = avs_reader + .query_registration_detail(operator_address) + .await + .unwrap(); + + println!("{:?}", ret_query_registration_detail); + + // all the value are false + for ret_value in ret_query_registration_detail.iter() { + assert!(!ret_value); + } + + // register an operator + let is_registered = avs_reader + .is_operator_registered(operator_address) + .await + .unwrap(); + assert!(!is_registered); + } } diff --git a/crates/chainio/clients/fireblocks/src/lib.rs b/crates/chainio/clients/fireblocks/src/lib.rs index edbdb2c5..34d16ebb 100644 --- a/crates/chainio/clients/fireblocks/src/lib.rs +++ b/crates/chainio/clients/fireblocks/src/lib.rs @@ -98,7 +98,13 @@ impl FireblocksWallet { match contains_account { true => { - if self.whitelisted_accounts.get(&address).unwrap().id().eq("") { + if self + .whitelisted_accounts + .get(&address) + .unwrap() + .id() + .is_empty() + { Err(FireBlockError::AccountNotFoundError(address.to_string())) } else { Ok(self.whitelisted_accounts.get(&address).unwrap().clone()) @@ -146,7 +152,7 @@ impl FireblocksWallet { .get(&address) .unwrap() .id() - .eq("") + .is_empty() { Err(FireBlockError::ContractNotFound(address.to_string())) } else { diff --git a/crates/chainio/txmanager/Cargo.toml b/crates/chainio/txmanager/Cargo.toml index 5525bbfa..afec9039 100644 --- a/crates/chainio/txmanager/Cargo.toml +++ b/crates/chainio/txmanager/Cargo.toml @@ -15,6 +15,7 @@ eigen-signer.workspace = true reqwest.workspace = true thiserror.workspace = true tokio.workspace = true +backoff.workspace = true [dev-dependencies] eigen-testing-utils.workspace = true diff --git a/crates/chainio/txmanager/src/simple_tx_manager.rs b/crates/chainio/txmanager/src/simple_tx_manager.rs index e52c31c9..889be616 100644 --- a/crates/chainio/txmanager/src/simple_tx_manager.rs +++ b/crates/chainio/txmanager/src/simple_tx_manager.rs @@ -4,9 +4,11 @@ use alloy::primitives::U256; use alloy::providers::{PendingTransactionBuilder, Provider, ProviderBuilder, RootProvider}; use alloy::rpc::types::eth::{TransactionInput, TransactionReceipt, TransactionRequest}; use alloy::signers::local::PrivateKeySigner; +use backoff::{future::retry, ExponentialBackoffBuilder}; use eigen_logging::logger::SharedLogger; use eigen_signer::signer::Config; use reqwest::Url; +use std::time::Duration; use thiserror::Error; static FALLBACK_GAS_TIP_CAP: u128 = 5_000_000_000; @@ -14,7 +16,7 @@ static FALLBACK_GAS_TIP_CAP: u128 = 5_000_000_000; pub type Transport = alloy::transports::http::Http; /// Possible errors raised in Tx Manager -#[derive(Error, Debug)] +#[derive(Error, Debug, PartialEq)] pub enum TxManagerError { #[error("signer error")] SignerError, @@ -156,6 +158,48 @@ impl SimpleTxManager { SimpleTxManager::wait_for_receipt(self, pending_tx).await } + /// Send a transaction to the Ethereum node. It takes an unsigned/signed transaction, + /// sends it to the Ethereum node and waits for the receipt. + /// If you pass in a signed transaction it will ignore the signature + /// and re-sign the transaction after adding the nonce and gas limit. + /// If the transaction fails, it will retry sending the transaction until it gets a receipt, + /// using an **exponential backoff** strategy. + /// If no receipt is received after `max_elapsed_time`, it will return an error. + /// + /// # Arguments + /// + /// * `tx`: The transaction to be sent. + /// * `initial_interval`: The initial interval duration for the backoff. + /// * `max_elapsed_time`: The maximum elapsed time for retrying. + /// * `multiplier`: The multiplier used to compute the exponential backoff. + /// + /// # Returns + /// + /// * `TransactionReceipt` The transaction receipt. + /// + /// # Errors + /// + /// * `TxManagerError` - If the transaction cannot be sent, or there is an error + /// signing the transaction or estimating gas and nonce. + pub async fn send_tx_with_retries( + &self, + tx: &mut TransactionRequest, + initial_interval: Duration, + max_elapsed_time: Duration, + multiplier: f64, + ) -> Result { + let backoff_config = ExponentialBackoffBuilder::default() + .with_initial_interval(initial_interval) + .with_max_elapsed_time(Some(max_elapsed_time)) + .with_multiplier(multiplier) + .build(); + retry(backoff_config, || async { + let mut cloned_tx = tx.clone(); + Ok(self.send_tx(&mut cloned_tx).await?) + }) + .await + } + /// Estimates the gas and nonce for a transaction. /// /// # Arguments @@ -270,14 +314,16 @@ impl SimpleTxManager { #[cfg(test)] mod tests { - use super::SimpleTxManager; + use super::{SimpleTxManager, TxManagerError}; use alloy::consensus::TxLegacy; use alloy::network::TransactionBuilder; use alloy::primitives::{address, bytes, TxKind::Call, U256}; use alloy::rpc::types::eth::TransactionRequest; use eigen_logging::get_test_logger; use eigen_testing_utils::anvil::start_anvil_container; + use std::time::Duration; use tokio; + use tokio::time::Instant; #[tokio::test] async fn test_send_transaction_from_legacy() { @@ -339,4 +385,40 @@ mod tests { assert!(block_number > 0); assert_eq!(receipt.to, Some(to)); } + + #[tokio::test] + async fn test_send_transaction_with_retries_returns_after_timeout() { + let rpc_url = "http://fake:8545"; + let logger = get_test_logger(); + let private_key = + "ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".to_string(); + let simple_tx_manager = + SimpleTxManager::new(logger, 1.0, private_key.as_str(), rpc_url).unwrap(); + let to = address!("a0Ee7A142d267C1f36714E4a8F75612F20a79720"); + + let account_nonce = 0x69; + let mut tx = TransactionRequest::default() + .with_to(to) + .with_nonce(account_nonce) + .with_chain_id(31337) + .with_value(U256::from(100)) + .with_gas_limit(21_000) + .with_max_priority_fee_per_gas(1_000_000_000) + .with_max_fee_per_gas(20_000_000_000) + .with_gas_price(21_000_000_000); + let start = Instant::now(); + + let result = simple_tx_manager + .send_tx_with_retries( + &mut tx, + Duration::from_millis(5), + Duration::from_secs(1), + 1.0, + ) + .await; + assert_eq!(result, Err(TxManagerError::SendTxError)); + // substract one interval for asserting, because if the last try does not fit in the max_elapsed_time, it will not be executed + let elapsed = start.elapsed(); + assert!(elapsed >= Duration::from_secs(1) - Duration::from_millis(5)); + } } diff --git a/crates/eigensdk/README.md b/crates/eigensdk/README.md index 29afde54..3c960d13 100644 --- a/crates/eigensdk/README.md +++ b/crates/eigensdk/README.md @@ -36,6 +36,26 @@ Example : cargo run --example get_quorum_count ``` +## Contract Bindings + +The main branch of this repo is intended to be syncronized with mainnet version of core contracts. + +To update the bindings of this repo: + +- Inside the `crates/contracts` folder, run: + +```bash +forge bind --alloy --bindings-path /crates/utils --overwrite -C src/contracts +``` + +where `path-eigensdk-rs` is the full path to the eigensdk-rs (this) repo. + +This command will generate the bindings files in the folder: `/crates/utils`. + +⚠️ It rewrites Cargo.toml file, this file must be restored to the current version. + +- Fix all compilation warnings. + ## Contributor Guidelines We are actively looking for contributors. Thank you for your interest. We have strict ci checks in place. In case of any questions and support, feel free to raise an issue. diff --git a/crates/services/bls_aggregation/Cargo.toml b/crates/services/bls_aggregation/Cargo.toml index 410ba81e..35de702a 100644 --- a/crates/services/bls_aggregation/Cargo.toml +++ b/crates/services/bls_aggregation/Cargo.toml @@ -16,6 +16,7 @@ ark-ec.workspace = true eigen-client-avsregistry.workspace = true eigen-crypto-bls.workspace = true eigen-crypto-bn254.workspace = true +eigen-logging.workspace = true eigen-services-avsregistry.workspace = true eigen-types.workspace = true parking_lot.workspace = true diff --git a/crates/services/bls_aggregation/src/bls_agg.rs b/crates/services/bls_aggregation/src/bls_agg.rs index 8e2a49b9..5cebfb4b 100644 --- a/crates/services/bls_aggregation/src/bls_agg.rs +++ b/crates/services/bls_aggregation/src/bls_agg.rs @@ -1,18 +1,19 @@ +use super::bls_aggregation_service_error::BlsAggregationServiceError; +use super::bls_aggregation_service_response::BlsAggregationServiceResponse; use alloy_primitives::{FixedBytes, Uint, U256}; use ark_bn254::{G1Affine, G2Affine}; use ark_ec::AffineRepr; use eigen_crypto_bls::{BlsG1Point, BlsG2Point, Signature}; use eigen_crypto_bn254::utils::verify_message; +use eigen_logging::logger::SharedLogger; use eigen_services_avsregistry::AvsRegistryService; use eigen_types::{ avs::{SignatureVerificationError, SignedTaskResponseDigest, TaskIndex, TaskResponseDigest}, operator::{OperatorAvsState, QuorumThresholdPercentage, QuorumThresholdPercentages}, }; use parking_lot::RwLock; -use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; -use thiserror::Error; use tokio::{ sync::{ mpsc::{self, UnboundedReceiver, UnboundedSender}, @@ -21,41 +22,6 @@ use tokio::{ time::Duration, }; -/// The response from the BLS aggregation service -#[allow(unused)] -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct BlsAggregationServiceResponse { - pub task_index: TaskIndex, - pub task_response_digest: TaskResponseDigest, - pub non_signers_pub_keys_g1: Vec, - pub quorum_apks_g1: Vec, - pub signers_apk_g2: BlsG2Point, - pub signers_agg_sig_g1: Signature, - pub non_signer_quorum_bitmap_indices: Vec, - pub quorum_apk_indices: Vec, - pub total_stake_indices: Vec, - pub non_signer_stake_indices: Vec>, -} - -/// Possible errors raised in BLS aggregation -#[derive(Error, Debug, Clone, PartialEq, Eq)] -pub enum BlsAggregationServiceError { - #[error("task expired error")] - TaskExpired, - #[error("task not found error")] - TaskNotFound, - #[error("signature verification error")] - SignatureVerificationError(SignatureVerificationError), - #[error("signatures channel was closed, can't send signatures to aggregator")] - SignaturesChannelClosed, - #[error("error sending to channel")] - ChannelError, - #[error("Avs Registry Error")] - RegistryError, - #[error("duplicate task index error")] - DuplicateTaskIndex, -} - /// Contains the aggregated operators signers information #[derive(Debug, Clone)] pub struct AggregatedOperators { @@ -71,6 +37,7 @@ pub struct BlsAggregatorService where A: Clone, { + logger: SharedLogger, aggregated_response_sender: UnboundedSender>, pub aggregated_response_receiver: Arc< @@ -90,9 +57,11 @@ impl BlsAggregatorService /// # Arguments /// /// * `avs_registry_service` - The AVS registry service - pub fn new(avs_registry_service: A) -> Self { + /// * `logger` - Logger to log messages + pub fn new(avs_registry_service: A, logger: SharedLogger) -> Self { let (tx, rx) = tokio::sync::mpsc::unbounded_channel(); Self { + logger, aggregated_response_sender: tx, aggregated_response_receiver: Arc::new(Mutex::new(rx)), signed_task_response: Arc::new(RwLock::new(HashMap::new())), @@ -169,6 +138,14 @@ impl BlsAggregatorService let avs_registry_service = self.avs_registry_service.clone(); let aggregated_response_sender = self.aggregated_response_sender.clone(); + self.logger.debug( + &format!( + "Create task to process new signed task responses for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.initialize_new_task_with_window", + ); + let logger = self.logger.clone(); tokio::spawn(async move { // Process each signed response here let _ = BlsAggregatorService::::single_task_aggregator( @@ -181,6 +158,7 @@ impl BlsAggregatorService aggregated_response_sender, signatures_rx, window_duration, + logger, ) .await .inspect_err(|err| { @@ -228,6 +206,13 @@ impl BlsAggregatorService .get(&task_index) .ok_or(BlsAggregationServiceError::TaskNotFound)?; + self.logger.debug( + &format!( + "send the task to the aggregator thread for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.process_new_signature", + ); // send the task to the aggregator thread sender .send(task) @@ -236,6 +221,13 @@ impl BlsAggregatorService // release the lock }; + self.logger.debug( + &format!( + "receive the signature verification result for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.process_new_signature", + ); // return the signature verification result rx.recv() .await @@ -250,6 +242,7 @@ impl BlsAggregatorService /// - `aggregated_operators` - Contains the information of all the aggregated operators. /// - `operator_state` - The state of the operator, contains information about its stake. /// - `signed_task_digest` - Contains the id and signature of the new operator. + /// - `logger` - The logger to log messages. /// /// # Returns /// @@ -258,6 +251,7 @@ impl BlsAggregatorService aggregated_operators: &mut AggregatedOperators, operator_state: OperatorAvsState, signed_task_digest: SignedTaskResponseDigest, + logger: SharedLogger, ) -> &mut AggregatedOperators { let operator_g2_pubkey = operator_state .operator_info @@ -269,6 +263,15 @@ impl BlsAggregatorService aggregated_operators .signers_operator_ids_set .insert(signed_task_digest.operator_id, true); + + logger.debug( + &format!( + "operator {} inserted in signers_operator_ids_set", + signed_task_digest.operator_id + ), + "eigen-services-blsaggregation.bls_agg.aggregate_new_operator", + ); + for (quorum_num, stake) in operator_state.stake_per_quorum.iter() { // For each quorum the operator has stake in, we aggregate the signature and update the stake aggregated_operators.signers_agg_sig_g1 = Signature::new( @@ -303,7 +306,9 @@ impl BlsAggregatorService /// * `quorum_threshold_percentages` - The quorum threshold percentages for the task /// * `time_to_expiry` - The timeout for the task reader to expire /// * `aggregated_response_sender` - The sender channel for the aggregated responses - /// * `rx` - The receiver channel for the signed task responses + /// * `signatures_rx` - The receiver channel for the signed task responses + /// * `window_duration` - The duration of the window to wait for signatures after quorum is reached + /// * `logger` - The logger to log messages. #[allow(clippy::too_many_arguments)] pub async fn single_task_aggregator( avs_registry_service: A, @@ -317,6 +322,7 @@ impl BlsAggregatorService >, signatures_rx: UnboundedReceiver, window_duration: Duration, + logger: SharedLogger, ) -> Result<(), BlsAggregationServiceError> { let quorum_threshold_percentage_map: HashMap = quorum_nums .iter() @@ -357,6 +363,7 @@ impl BlsAggregatorService quorum_apks_g1, quorum_nums, window_duration, + logger, ) .await } @@ -377,6 +384,7 @@ impl BlsAggregatorService quorum_apks_g1: Vec, quorum_nums: Vec, window_duration: Duration, + logger: SharedLogger, ) -> Result<(), BlsAggregationServiceError> { let mut aggregated_operators: HashMap, AggregatedOperators> = HashMap::new(); let mut open_window = false; @@ -389,50 +397,82 @@ impl BlsAggregatorService tokio::select! { _ = &mut task_expired_timer => { // Task expired. If window is open, send aggregated reponse. Else, send error - dbg!("Task expired for task index: {:?}", task_index); - if open_window { - aggregated_response_sender - .send(Ok(current_aggregated_response.unwrap())) - .map_err(|_| BlsAggregationServiceError::ChannelError)?; - } else { - let _ = aggregated_response_sender.send(Err(BlsAggregationServiceError::TaskExpired)); - } - return Ok(()); - }, - _ = window_rx.recv() => { - // Window finished. Send aggregated response + + if open_window { + logger.debug( + &format!( + "task_expired_timer while in the waiting window for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); aggregated_response_sender .send(Ok(current_aggregated_response.unwrap())) .map_err(|_| BlsAggregationServiceError::ChannelError)?; - return Ok(()); - }, - signed_task_digest = signatures_rx.recv() =>{ - // New signature, aggregate it. If threshold is met, start window - let Some(digest) = signed_task_digest else { - return Err(BlsAggregationServiceError::SignaturesChannelClosed); - }; - // check if the operator has already signed for this digest - if aggregated_operators - .get(&digest.task_response_digest) - .map(|operators| { - operators - .signers_operator_ids_set - .contains_key(&digest.operator_id) - }) - .unwrap_or(false) - { - digest - .signature_verification_channel - .send(Err(SignatureVerificationError::DuplicateSignature)) - .await - .map_err(|_| BlsAggregationServiceError::ChannelError)?; - continue; - } + } else { + logger.debug( + &format!( + "task_expired_timer NOT in the waiting window for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); + + let _ = aggregated_response_sender.send(Err(BlsAggregationServiceError::TaskExpired)); + } + return Ok(()); + }, + _ = window_rx.recv() => { + logger.debug( + &format!( + "Window finished. Send aggregated response for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); + + // Window finished. Send aggregated response + aggregated_response_sender + .send(Ok(current_aggregated_response.unwrap())) + .map_err(|_| BlsAggregationServiceError::ChannelError)?; + return Ok(()); + }, + signed_task_digest = signatures_rx.recv() =>{ + logger.debug( + &format!( + "New signature received for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); + + // New signature, aggregate it. If threshold is met, start window + let Some(digest) = signed_task_digest else { + return Err(BlsAggregationServiceError::SignaturesChannelClosed); + }; + // check if the operator has already signed for this digest + if aggregated_operators + .get(&digest.task_response_digest) + .map(|operators| { + operators + .signers_operator_ids_set + .contains_key(&digest.operator_id) + }) + .unwrap_or(false) + { + digest + .signature_verification_channel + .send(Err(SignatureVerificationError::DuplicateSignature)) + .await + .map_err(|_| BlsAggregationServiceError::ChannelError)?; + continue; + } let verification_result = BlsAggregatorService::::verify_signature( task_index, &digest, &operator_state_avs, + logger.clone(), ) .await; let verification_failed = verification_result.is_err(); @@ -444,7 +484,6 @@ impl BlsAggregatorService .map_err(|_| BlsAggregationServiceError::ChannelError)?; if verification_failed { - dbg!("Signature verification failed for digest: {:?}", digest); continue; } @@ -467,6 +506,7 @@ impl BlsAggregatorService digest_aggregated_operators, operator_state.clone(), digest.clone(), + logger.clone() ) .clone() }) @@ -496,6 +536,8 @@ impl BlsAggregatorService } }); + + aggregated_operators.insert( digest.task_response_digest, digest_aggregated_operators.clone(), @@ -506,18 +548,33 @@ impl BlsAggregatorService &total_stake_per_quorum, &quorum_threshold_percentage_map, ) { - dbg!("Stake threshold not met for task index: {:?}", task_index); continue; } + logger.debug( + &format!( + "Signature threshold is met for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); + if !open_window { open_window = true; let sender_cloned = window_tx.clone(); + + logger.debug( + &format!( + "Create window to wait for new signatures for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.loop_task_aggregator", + ); + tokio::spawn(async move { tokio::time::sleep(window_duration).await; let _ = sender_cloned.send(true); }); - dbg!("Opened window for task index: {:?}", task_index); } current_aggregated_response = Some(BlsAggregatorService::build_aggregated_response( @@ -529,6 +586,7 @@ impl BlsAggregatorService &avs_registry_service, &quorum_apks_g1, &quorum_nums, + logger.clone(), ) .await?); @@ -549,6 +607,7 @@ impl BlsAggregatorService /// * `avs_registry_service` - The avs registry service. /// * `quorum_apks_g1` - The quorum aggregated public keys. /// * `quorum_nums` - The quorum numbers. + /// * `logger` - The logger to log messages. /// /// # Returns /// @@ -563,7 +622,13 @@ impl BlsAggregatorService avs_registry_service: &A, quorum_apks_g1: &[BlsG1Point], quorum_nums: &[u8], + logger: SharedLogger, ) -> Result { + logger.debug( + &format!("Build aggregated response for task index: {}", task_index), + "eigen-services-blsaggregation.bls_agg.build_aggregated_response", + ); + let mut non_signers_operators_ids: Vec> = operator_state_avs .keys() .filter(|operator_id| { @@ -615,6 +680,7 @@ impl BlsAggregatorService /// * `signed_task_response_digest` - The signed task response digest /// * `operator_avs_state` - A hashmap containing the staked of all the operator indexed by operator_id. /// This is used to get the `operator_state` to obtain the operator public key. + /// * `logger` - The logger to log messages. /// /// # Error /// @@ -623,16 +689,28 @@ impl BlsAggregatorService /// - `SignatureVerificationError::OperatorPublicKeyNotFound` if the operator public key is not found, /// - `SignatureVerificationError::IncorrectSignature` if the signature is incorrect. pub async fn verify_signature( - _task_index: TaskIndex, + task_index: TaskIndex, signed_task_response_digest: &SignedTaskResponseDigest, operator_avs_state: &HashMap, OperatorAvsState>, + logger: SharedLogger, ) -> Result<(), SignatureVerificationError> { let Some(operator_state) = operator_avs_state.get(&signed_task_response_digest.operator_id) else { + logger.error( + &format!("Operator Not Found for task index: {}", task_index), + "eigen-services-blsaggregation.bls_agg.verify_signature", + ); return Err(SignatureVerificationError::OperatorNotFound); }; let Some(pub_keys) = &operator_state.operator_info.pub_keys else { + logger.error( + &format!( + "Operator Public Key Not Found for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.verify_signature", + ); return Err(SignatureVerificationError::OperatorPublicKeyNotFound); }; @@ -649,6 +727,24 @@ impl BlsAggregatorService ) .then_some(()) .ok_or(SignatureVerificationError::IncorrectSignature) + .inspect(|_| { + logger.debug( + &format!( + "Signature verification successful for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.verify_signature", + ); + }) + .inspect_err(|_| { + logger.error( + &format!( + "Signature verification failed for task index: {}", + task_index + ), + "eigen-services-blsaggregation.bls_agg.verify_signature", + ); + }) } /// Checks if the stake thresholds are met for the given set of quorum members. @@ -692,6 +788,7 @@ mod tests { use super::{BlsAggregationServiceError, BlsAggregationServiceResponse, BlsAggregatorService}; use alloy_primitives::{B256, U256}; use eigen_crypto_bls::{BlsG1Point, BlsG2Point, BlsKeyPair, Signature}; + use eigen_logging::get_test_logger; use eigen_services_avsregistry::fake_avs_registry_service::FakeAvsRegistryService; use eigen_types::avs::SignatureVerificationError::{DuplicateSignature, IncorrectSignature}; use eigen_types::operator::{QuorumNum, QuorumThresholdPercentages}; @@ -763,7 +860,8 @@ mod tests { .sign_message(task_response_digest.as_ref()); let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, vec![test_operator_1.clone()]); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( task_index, @@ -837,7 +935,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( task_index, @@ -954,7 +1053,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1060,7 +1160,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1151,7 +1252,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); // initialize 2 concurrent tasks let task_1_index = 1; @@ -1320,7 +1422,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, vec![test_operator_1.clone()]); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( task_index, @@ -1371,7 +1474,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1449,7 +1553,8 @@ mod tests { .sign_message(task_response_digest.as_ref()); let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1510,7 +1615,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1619,7 +1725,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators.clone()); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1729,7 +1836,8 @@ mod tests { let task_response_digest = hash(task_response); let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1801,7 +1909,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, vec![test_operator_1.clone()]); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1866,7 +1975,8 @@ mod tests { let test_operators = vec![test_operator_1.clone(), test_operator_2.clone()]; let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -1921,7 +2031,8 @@ mod tests { let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, vec![test_operator_1.clone()]); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); let bls_sig_op_1 = test_operator_1 .bls_keypair @@ -1958,7 +2069,8 @@ mod tests { let quorum_threshold_percentages: QuorumThresholdPercentages = vec![100u8]; let time_to_expiry = Duration::from_secs(1); let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( @@ -2035,7 +2147,8 @@ mod tests { .sign_message(hash(task_response).as_ref()); let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, vec![test_operator_1.clone()]); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); bls_agg_service .initialize_new_task( task_index, @@ -2105,7 +2218,8 @@ mod tests { let quorum_numbers: Vec = vec![0]; let quorum_threshold_percentages: QuorumThresholdPercentages = vec![50_u8]; let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); let time_to_expiry = Duration::from_secs(5); let window_duration = Duration::from_secs(1); @@ -2230,7 +2344,8 @@ mod tests { let quorum_numbers: Vec = vec![0]; let quorum_threshold_percentages: QuorumThresholdPercentages = vec![40_u8]; let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); let time_to_expiry = Duration::from_secs(2); let window_duration = Duration::from_secs(10); @@ -2335,7 +2450,8 @@ mod tests { let quorum_numbers: Vec = vec![0]; let quorum_threshold_percentages: QuorumThresholdPercentages = vec![40_u8]; let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); let time_to_expiry = Duration::from_secs(2); let window_duration = Duration::ZERO; @@ -2383,7 +2499,7 @@ mod tests { ) .await; assert_eq!( - Err(BlsAggregationServiceError::ChannelError), + Err(BlsAggregationServiceError::ChannelError), // TODO: change this error to be more representative process_signature_result ); @@ -2442,7 +2558,8 @@ mod tests { let quorum_numbers: Vec = vec![0]; let quorum_threshold_percentages: QuorumThresholdPercentages = vec![40_u8]; let fake_avs_registry_service = FakeAvsRegistryService::new(block_number, test_operators); - let bls_agg_service = BlsAggregatorService::new(fake_avs_registry_service); + let bls_agg_service = + BlsAggregatorService::new(fake_avs_registry_service, get_test_logger()); let time_to_expiry = Duration::from_secs(5); let window_duration = Duration::from_secs(1); @@ -2490,7 +2607,7 @@ mod tests { ) .await; assert_eq!( - Err(BlsAggregationServiceError::ChannelError), + Err(BlsAggregationServiceError::ChannelError), // TODO: change this error to be more representative process_signature_result ); diff --git a/crates/services/bls_aggregation/src/bls_agg_test.rs b/crates/services/bls_aggregation/src/bls_agg_test.rs index 528df1cc..9a937df9 100644 --- a/crates/services/bls_aggregation/src/bls_agg_test.rs +++ b/crates/services/bls_aggregation/src/bls_agg_test.rs @@ -1,6 +1,7 @@ #[cfg(test)] pub mod integration_test { - use crate::bls_agg::{BlsAggregationServiceResponse, BlsAggregatorService}; + use crate::bls_agg::BlsAggregatorService; + use crate::bls_aggregation_service_response::BlsAggregationServiceResponse; use alloy::providers::Provider; use alloy_primitives::{aliases::U96, hex, Bytes, FixedBytes, B256, U256}; use eigen_client_avsregistry::{ @@ -191,7 +192,7 @@ pub mod integration_test { let avs_registry_service = AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info); - let bls_agg_service = BlsAggregatorService::new(avs_registry_service); + let bls_agg_service = BlsAggregatorService::new(avs_registry_service, get_test_logger()); let current_block_num = provider.get_block_number().await.unwrap(); mine_anvil_blocks(&container, 1).await; @@ -375,7 +376,7 @@ pub mod integration_test { let avs_registry_service = AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info); - let bls_agg_service = BlsAggregatorService::new(avs_registry_service); + let bls_agg_service = BlsAggregatorService::new(avs_registry_service, get_test_logger()); let current_block_num = provider.get_block_number().await.unwrap(); @@ -595,7 +596,7 @@ pub mod integration_test { let avs_registry_service = AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info); - let bls_agg_service = BlsAggregatorService::new(avs_registry_service); + let bls_agg_service = BlsAggregatorService::new(avs_registry_service, get_test_logger()); let current_block_num = provider.get_block_number().await.unwrap(); @@ -804,7 +805,7 @@ pub mod integration_test { let avs_registry_service = AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info); - let bls_agg_service = BlsAggregatorService::new(avs_registry_service); + let bls_agg_service = BlsAggregatorService::new(avs_registry_service, get_test_logger()); let current_block_num = provider.get_block_number().await.unwrap(); @@ -984,7 +985,7 @@ pub mod integration_test { let avs_registry_service = AvsRegistryServiceChainCaller::new(avs_registry_reader.clone(), operators_info); - let bls_agg_service = BlsAggregatorService::new(avs_registry_service); + let bls_agg_service = BlsAggregatorService::new(avs_registry_service, get_test_logger()); let current_block_num = provider.get_block_number().await.unwrap(); mine_anvil_blocks(&container, 1).await; diff --git a/crates/services/bls_aggregation/src/bls_aggregation_service_error.rs b/crates/services/bls_aggregation/src/bls_aggregation_service_error.rs new file mode 100644 index 00000000..1d6d0711 --- /dev/null +++ b/crates/services/bls_aggregation/src/bls_aggregation_service_error.rs @@ -0,0 +1,21 @@ +use eigen_types::avs::SignatureVerificationError; +use thiserror::Error; + +/// Possible errors raised in BLS aggregation +#[derive(Error, Debug, Clone, PartialEq, Eq)] +pub enum BlsAggregationServiceError { + #[error("task expired error")] + TaskExpired, + #[error("task not found error")] + TaskNotFound, + #[error("signature verification error")] + SignatureVerificationError(SignatureVerificationError), + #[error("signatures channel was closed, can't send signatures to aggregator")] + SignaturesChannelClosed, + #[error("error sending to channel")] + ChannelError, + #[error("Avs Registry Error")] + RegistryError, + #[error("duplicate task index error")] + DuplicateTaskIndex, +} diff --git a/crates/services/bls_aggregation/src/bls_aggregation_service_response.rs b/crates/services/bls_aggregation/src/bls_aggregation_service_response.rs new file mode 100644 index 00000000..ebcb38f6 --- /dev/null +++ b/crates/services/bls_aggregation/src/bls_aggregation_service_response.rs @@ -0,0 +1,19 @@ +use eigen_crypto_bls::{BlsG1Point, BlsG2Point, Signature}; +use eigen_types::avs::{TaskIndex, TaskResponseDigest}; +use serde::{Deserialize, Serialize}; + +/// The response from the BLS aggregation service +#[allow(unused)] +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct BlsAggregationServiceResponse { + pub task_index: TaskIndex, + pub task_response_digest: TaskResponseDigest, + pub non_signers_pub_keys_g1: Vec, + pub quorum_apks_g1: Vec, + pub signers_apk_g2: BlsG2Point, + pub signers_agg_sig_g1: Signature, + pub non_signer_quorum_bitmap_indices: Vec, + pub quorum_apk_indices: Vec, + pub total_stake_indices: Vec, + pub non_signer_stake_indices: Vec>, +} diff --git a/crates/services/bls_aggregation/src/lib.rs b/crates/services/bls_aggregation/src/lib.rs index 669a6aa2..02159997 100644 --- a/crates/services/bls_aggregation/src/lib.rs +++ b/crates/services/bls_aggregation/src/lib.rs @@ -9,3 +9,5 @@ pub mod bls_agg; mod bls_agg_test; +pub mod bls_aggregation_service_error; +pub mod bls_aggregation_service_response; diff --git a/crates/services/operatorsinfo/src/operatorsinfo_inmemory.rs b/crates/services/operatorsinfo/src/operatorsinfo_inmemory.rs index 9876db13..fbc640f7 100644 --- a/crates/services/operatorsinfo/src/operatorsinfo_inmemory.rs +++ b/crates/services/operatorsinfo/src/operatorsinfo_inmemory.rs @@ -427,7 +427,7 @@ mod tests { use eigen_client_avsregistry::writer::AvsRegistryChainWriter; use eigen_client_elcontracts::{reader::ELChainReader, writer::ELChainWriter}; use eigen_crypto_bls::BlsKeyPair; - use eigen_logging::{get_logger, get_test_logger, init_logger}; + use eigen_logging::get_test_logger; use eigen_testing_utils::anvil::start_anvil_container; use eigen_testing_utils::anvil_constants::{ get_avs_directory_address, get_delegation_manager_address, @@ -444,8 +444,7 @@ mod tests { #[tokio::test] async fn test_query_past_registered_operator_events_and_fill_db() { let (_container, http_endpoint, ws_endpoint) = start_anvil_container().await; - init_logger(eigen_logging::log_level::LogLevel::Debug); - let test_logger = get_logger(); + let test_logger = get_test_logger(); register_operator( http_endpoint.clone(), "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6", diff --git a/testing/testing-utils/src/anvil_constants.rs b/testing/testing-utils/src/anvil_constants.rs index 2a282cd6..33d6655b 100644 --- a/testing/testing-utils/src/anvil_constants.rs +++ b/testing/testing-utils/src/anvil_constants.rs @@ -14,8 +14,6 @@ pub const ANVIL_HTTP_URL: &str = "http://localhost:8545"; /// Local anvil rpc WS url pub const ANVIL_WS_URL: &str = "ws://localhost:8545"; -#[allow(clippy::type_complexity)] - /// Service Manager contract address pub async fn get_service_manager_address(rpc_url: String) -> Address { let provider = get_provider(&rpc_url); diff --git a/testing/testing-utils/src/m2_holesky_constants.rs b/testing/testing-utils/src/m2_holesky_constants.rs index cba586b3..fcf9186d 100644 --- a/testing/testing-utils/src/m2_holesky_constants.rs +++ b/testing/testing-utils/src/m2_holesky_constants.rs @@ -1,5 +1,8 @@ use alloy_primitives::{address, Address}; +/// Holesky rpc provider +pub const HOLESKY_RPC_PROVIDER: &str = "https://ethereum-holesky-rpc.publicnode.com"; + /// https://holesky.etherscan.io/address/0xA44151489861Fe9e3055d95adC98FbD462B948e7 pub const DELEGATION_MANAGER_ADDRESS: Address = address!("A44151489861Fe9e3055d95adC98FbD462B948e7"); @@ -61,7 +64,7 @@ pub const BEIGEN: Address = address!("275cCf9Be51f4a6C94aBa6114cdf2a4c45B9cb27") /// https://holesky.etherscan.io/address/0x43252609bff8a13dFe5e057097f2f45A24387a84 pub const EIGEN_STRATEGY: Address = address!("43252609bff8a13dFe5e057097f2f45A24387a84"); -/// Middlware contracts +// Middlware contracts /// https://holesky.etherscan.io/address/0x53012C69A189cfA2D9d29eb6F19B32e0A2EA3490 pub const REGISTRY_COORDINATOR: Address = address!("53012C69A189cfA2D9d29eb6F19B32e0A2EA3490");