diff --git a/rust/agents/validator/src/validator.rs b/rust/agents/validator/src/validator.rs index 5244d226a0..a7a22bc32d 100644 --- a/rust/agents/validator/src/validator.rs +++ b/rust/agents/validator/src/validator.rs @@ -13,8 +13,9 @@ use hyperlane_base::{ MessageContractSync, }; use hyperlane_core::{ - accumulator::incremental::IncrementalMerkle, Announcement, HyperlaneChain, HyperlaneContract, - HyperlaneDomain, HyperlaneSigner, HyperlaneSignerExt, Mailbox, ValidatorAnnounce, H256, U256, + accumulator::incremental::IncrementalMerkle, Announcement, ChainResult, HyperlaneChain, + HyperlaneContract, HyperlaneDomain, HyperlaneSigner, HyperlaneSignerExt, Mailbox, TxOutcome, + ValidatorAnnounce, H256, U256, }; use hyperlane_ethereum::{SingletonSigner, SingletonSignerHandle}; @@ -204,6 +205,27 @@ impl Validator { tasks } + fn log_on_announce_failure(result: ChainResult) { + match result { + Ok(outcome) => { + if !outcome.executed { + error!( + hash=?outcome.txid, + gas_used=?outcome.gas_used, + gas_price=?outcome.gas_price, + "Transaction attempting to announce validator reverted. Make sure you have enough ETH in your account to pay for gas." + ); + } + } + Err(err) => { + error!( + ?err, + "Failed to announce validator. Make sure you have enough ETH in your account to pay for gas." + ); + } + } + } + async fn announce(&self) -> Result<()> { // Sign and post the validator announcement let announcement = Announcement { @@ -238,7 +260,8 @@ impl Validator { let balance_delta = self .validator_announce .announce_tokens_needed(signed_announcement.clone()) - .await?; + .await + .unwrap_or_default(); if balance_delta > U256::zero() { warn!( tokens_needed=%balance_delta, @@ -247,16 +270,11 @@ impl Validator { ); sleep(self.interval).await; } else { - let outcome = self + let result = self .validator_announce .announce(signed_announcement.clone(), None) - .await?; - if !outcome.executed { - error!( - hash=?outcome.txid, - "Transaction attempting to announce validator reverted" - ); - } + .await; + Self::log_on_announce_failure(result); } } } diff --git a/rust/chains/hyperlane-ethereum/src/validator_announce.rs b/rust/chains/hyperlane-ethereum/src/validator_announce.rs index 5c28cd29fd..3b50d93372 100644 --- a/rust/chains/hyperlane-ethereum/src/validator_announce.rs +++ b/rust/chains/hyperlane-ethereum/src/validator_announce.rs @@ -5,7 +5,7 @@ use std::collections::HashMap; use std::sync::Arc; use async_trait::async_trait; -use ethers::providers::{Middleware, ProviderError}; +use ethers::providers::Middleware; use ethers_contract::builders::ContractCall; use hyperlane_core::{ @@ -13,6 +13,7 @@ use hyperlane_core::{ HyperlaneDomain, HyperlaneProvider, SignedType, TxOutcome, ValidatorAnnounce, H160, H256, U256, }; use tracing::instrument; +use tracing::log::trace; use crate::contracts::i_validator_announce::{ IValidatorAnnounce as EthereumValidatorAnnounceInternal, IVALIDATORANNOUNCE_ABI, @@ -132,21 +133,29 @@ where Ok(storage_locations) } - async fn announce_tokens_needed( - &self, - announcement: SignedType, - ) -> ChainResult { + #[instrument(ret, skip(self))] + async fn announce_tokens_needed(&self, announcement: SignedType) -> Option { let validator = announcement.value.validator; - let contract_call = self.announce_contract_call(announcement, None).await?; - if let Ok(balance) = self.provider.get_balance(validator, None).await { - if let Some(cost) = contract_call.tx.max_cost() { - Ok(cost.saturating_sub(balance)) - } else { - Err(ProviderError::CustomError("Unable to get announce max cost".into()).into()) - } - } else { - Err(ProviderError::CustomError("Unable to query balance".into()).into()) - } + let Ok(contract_call) = self + .announce_contract_call(announcement, None) + .await + else { + trace!("Unable to get announce contract call"); + return None; + }; + + let Ok(balance) = self.provider.get_balance(validator, None).await + else { + trace!("Unable to query balance"); + return None; + }; + + let Some(max_cost) = contract_call.tx.max_cost() + else { + trace!("Unable to get announce max cost"); + return None; + }; + Some(max_cost.saturating_sub(balance)) } #[instrument(err, ret, skip(self))] diff --git a/rust/hyperlane-core/src/traits/validator_announce.rs b/rust/hyperlane-core/src/traits/validator_announce.rs index 7859e06241..3ee4b4b35f 100644 --- a/rust/hyperlane-core/src/traits/validator_announce.rs +++ b/rust/hyperlane-core/src/traits/validator_announce.rs @@ -24,9 +24,6 @@ pub trait ValidatorAnnounce: HyperlaneContract + Send + Sync + Debug { ) -> ChainResult; /// Returns the number of additional tokens needed to pay for the announce - /// transaction. - async fn announce_tokens_needed( - &self, - announcement: SignedType, - ) -> ChainResult; + /// transaction. Return `None` if the needed tokens canno tbe determined. + async fn announce_tokens_needed(&self, announcement: SignedType) -> Option; } diff --git a/rust/hyperlane-test/src/mocks/validator_announce.rs b/rust/hyperlane-test/src/mocks/validator_announce.rs index 7a55701b26..ab78a0a27f 100644 --- a/rust/hyperlane-test/src/mocks/validator_announce.rs +++ b/rust/hyperlane-test/src/mocks/validator_announce.rs @@ -22,7 +22,7 @@ mock! { fn _announce_tokens_needed( &self, announcement: SignedType, - ) -> ChainResult; + ) -> Option; } } @@ -64,10 +64,7 @@ impl ValidatorAnnounce for MockValidatorAnnounceContract { ) -> ChainResult { self._announce(announcement, tx_gas_limit) } - async fn announce_tokens_needed( - &self, - announcement: SignedType, - ) -> ChainResult { + async fn announce_tokens_needed(&self, announcement: SignedType) -> Option { self._announce_tokens_needed(announcement) } }