From 1f78e241eb0476f4dc4689349bf0c2ff4081f1e6 Mon Sep 17 00:00:00 2001 From: Maciej Skrzypkowski Date: Fri, 20 Sep 2024 16:56:13 +0200 Subject: [PATCH] Better error handling for the registration (#134) --- Node/src/ethereum_l1/execution_layer.rs | 73 ++++++++++++++-------- Node/src/ethereum_l1/mod.rs | 1 + Node/src/ethereum_l1/registration.rs | 80 +++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 25 deletions(-) create mode 100644 Node/src/ethereum_l1/registration.rs diff --git a/Node/src/ethereum_l1/execution_layer.rs b/Node/src/ethereum_l1/execution_layer.rs index bf34a27..14e16d4 100644 --- a/Node/src/ethereum_l1/execution_layer.rs +++ b/Node/src/ethereum_l1/execution_layer.rs @@ -290,31 +290,44 @@ impl ExecutionLayer { } pub async fn register_preconfer(&self) -> Result<(), Error> { + tracing::debug!("Registering preconfer"); let strategy_manager = StrategyManager::new( self.contract_addresses.eigen_layer.strategy_manager, &self.provider_ws, ); let one_eth = U256::from(1000000000000000000u64); - let tx_hash = strategy_manager + match strategy_manager .depositIntoStrategy(Address::ZERO, Address::ZERO, one_eth) .value(one_eth) .send() - .await? - .watch() - .await?; - tracing::debug!("Deposited into strategy: {tx_hash}"); + .await + { + Ok(receipt) => { + let tx_hash = receipt.watch().await?; + tracing::info!("Deposited into strategy: {tx_hash}"); + } + Err(err) => { + tracing::error!("Depositing into strategy failed: {}", err); + } + } let slasher = Slasher::new( self.contract_addresses.eigen_layer.slasher, &self.provider_ws, ); - let tx_hash = slasher + match slasher .optIntoSlashing(self.contract_addresses.avs.service_manager) .send() - .await? - .watch() - .await?; - tracing::debug!("Opted into slashing: {tx_hash}"); + .await + { + Ok(receipt) => { + let tx_hash = receipt.watch().await?; + tracing::info!("Opted into slashing: {tx_hash}"); + } + Err(err) => { + tracing::error!("Opting into slashing failed: {}", err); + } + } let salt = Self::create_random_salt(); let expiration_timestamp = @@ -340,13 +353,18 @@ impl ExecutionLayer { self.contract_addresses.avs.preconf_registry, &self.provider_ws, ); - let tx_hash = preconf_registry - .registerPreconfer(signature_with_salt_and_expiry) - .send() - .await? - .watch() - .await?; - tracing::debug!("Registered preconfirming: {tx_hash}"); + let tx = preconf_registry.registerPreconfer(signature_with_salt_and_expiry); + + match tx.send().await { + Ok(receipt) => { + let tx_hash = receipt.watch().await?; + tracing::info!("Preconfer registered: {:?}", tx_hash); + } + Err(err) => { + let err = super::registration::decode_register_preconfer_error(&err.to_string())?; + return Err(anyhow::anyhow!("Registering preconfer failed: {}", err)); + } + } Ok(()) } @@ -630,13 +648,18 @@ impl ExecutionLayer { self.contract_addresses.avs.preconf_registry, &self.provider_ws, ); - let tx_hash = preconf_registry - .addValidators(params) - .send() - .await? - .watch() - .await?; - tracing::debug!("Add validator to preconfer: {tx_hash}"); + let tx = preconf_registry.addValidators(params); + + match tx.send().await { + Ok(receipt) => { + let tx_hash = receipt.watch().await?; + tracing::info!("Add validator to preconfer successful: {:?}", tx_hash); + } + Err(err) => { + let err = super::registration::decode_add_validator_error(&err.to_string())?; + return Err(anyhow::anyhow!("Adding validator failed: {}", err)); + } + } Ok(()) } @@ -674,7 +697,7 @@ impl ExecutionLayer { } } Err(e) => { - tracing::error!("Error receiving log: {:?}", e); + tracing::error!("Error receiving log: {}", e); } } } diff --git a/Node/src/ethereum_l1/mod.rs b/Node/src/ethereum_l1/mod.rs index 3eb4fc0..13f548a 100644 --- a/Node/src/ethereum_l1/mod.rs +++ b/Node/src/ethereum_l1/mod.rs @@ -3,6 +3,7 @@ pub mod consensus_layer; mod el_with_cl_tests; pub mod execution_layer; pub mod merkle_proofs; +mod registration; pub mod slot_clock; mod ws_provider; diff --git a/Node/src/ethereum_l1/registration.rs b/Node/src/ethereum_l1/registration.rs new file mode 100644 index 0000000..d1838f4 --- /dev/null +++ b/Node/src/ethereum_l1/registration.rs @@ -0,0 +1,80 @@ +use anyhow::Error; + +const PRECONF_NOT_REGISTERED: &[u8] = b"PreconferNotRegistered()"; +const VALIDATOR_ALREADY_ACTIVE: &[u8] = b"ValidatorAlreadyActive()"; + +// the error is e.g. "Reverted ;l_$" +// second part is first 4 bytes of keccak encoded +// error string +pub fn decode_add_validator_error(error: &str) -> Result { + let error_bytes = error.as_bytes(); + if error_bytes.len() < 13 { + return Err(anyhow::anyhow!( + "Error string is too short for addValidator error" + )); + } + let error_selector = &error_bytes[error_bytes.len() - 4..]; + + let preconf_not_registered_selector: [u8; 4] = first_4_bytes_of_keccak(PRECONF_NOT_REGISTERED)?; + let validator_already_active_selector: [u8; 4] = + first_4_bytes_of_keccak(VALIDATOR_ALREADY_ACTIVE)?; + + if error_selector == preconf_not_registered_selector { + return Ok("Preconfer not registered".to_string()); + } + if error_selector == validator_already_active_selector { + return Ok("Validator already active".to_string()); + } + Err(anyhow::anyhow!( + "decode_add_validator_error: Unknown error: {}", + error + )) +} + +fn first_4_bytes_of_keccak(input: &[u8]) -> Result<[u8; 4], Error> { + Ok(crate::utils::bytes_tools::hash_bytes_with_keccak(input)[..4].try_into()?) +} + +const PRECONF_ALREADY_REGISTERED: &[u8] = b"PreconferAlreadyRegistered()"; + +pub fn decode_register_preconfer_error(error: &str) -> Result { + let error_bytes = error.as_bytes(); + if error_bytes.len() < 13 { + return Err(anyhow::anyhow!( + "Error string is too short for addValidator error" + )); + } + let error_selector = &error_bytes[error_bytes.len() - 4..]; + let preconf_already_registered_selector: [u8; 4] = + first_4_bytes_of_keccak(PRECONF_ALREADY_REGISTERED)?; + + if error_selector == preconf_already_registered_selector { + return Ok("Preconfer already registered".to_string()); + } + + Err(anyhow::anyhow!( + "decode_register_preconfer_error: Unknown error: {}", + error + )) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_check_add_validator_error() { + let preconf_not_registered_error = "Reverted ;l_$"; + let result = decode_add_validator_error(&preconf_not_registered_error); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), "Preconfer not registered"); + } + + #[test] + fn test_check_register_preconfer_error() { + let preconf_already_registered_error = "Reverted þaM"; + let result = decode_register_preconfer_error(&preconf_already_registered_error); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), "Preconfer already registered"); + } +}