diff --git a/relayer/src/chain/cosmos.rs b/relayer/src/chain/cosmos.rs index f52a5a4349..8b1c1ce313 100644 --- a/relayer/src/chain/cosmos.rs +++ b/relayer/src/chain/cosmos.rs @@ -85,11 +85,18 @@ const DEFAULT_MAX_MSG_NUM: usize = 30; const DEFAULT_MAX_TX_SIZE: usize = 2 * 1048576; // 2 MBytes const DEFAULT_GAS_FEE_AMOUNT: u64 = 1000; -const MAX_RETRIES: usize = 30; - // default gas adjustment percentage const DEFAULT_GAS_ADJUSTMENT: u64 = 10; +mod retry_strategy { + use crate::util::retry::Fixed; + use std::time::Duration; + + pub fn wait_for_block_commits() -> impl Iterator { + Fixed::from_millis(300).take(10) + } +} + pub struct CosmosSdkChain { config: ChainConfig, rpc_client: HttpClient, @@ -426,60 +433,59 @@ impl CosmosSdkChain { /// with the transaction hashes to get the list of IbcEvents included in those transactions. pub fn wait_for_block_commits( &self, - tx_sync_results: &mut Vec, - ) -> Result<(), Error> { - // events_per_tx[i] collects the events generated by the transaction from tx_sync_results[i] - let mut counter = 0; - - // TODO - exp backoff is not good here, if anything we want to speed up the retries towards the end range - while counter < MAX_RETRIES { - thread::sleep(Duration::from_millis(200)); + mut tx_sync_results: Vec, + ) -> Result, Error> { + use crate::util::retry::{retry_with_index, RetryResult}; - counter += 1; + // Wait a little bit initially + thread::sleep(Duration::from_millis(200)); + let result = retry_with_index(retry_strategy::wait_for_block_commits(), |index| { if all_tx_results_found(&tx_sync_results) { trace!( "retrieved {} tx results after {} tries", tx_sync_results.len(), - counter + index ); // All transactions confirmed - return Ok(()); + return RetryResult::Ok(()); } for TxSyncResult { response, events } in tx_sync_results.iter_mut() { + // If this transaction was not committed yet, let's figure out + // whether it was because it failed or because it hasn't been committed yet. if empty_event_present(&events) { - // try to resolve transaction hash - let events_per_tx = if response.code.value() != 0 { - vec![IbcEvent::ChainError(format!( + // If the transaction failed, replace the events with an error, + // so that we don't attempt to resolve the transaction later on. + if response.code.value() != 0 { + *events = vec![IbcEvent::ChainError(format!( "code {:?}, log {}", response.code, response.log - ))] + ))]; + + // Otherwise, try to resolve transaction hash to the corresponding events. } else if let Ok(events_per_tx) = self.query_txs(QueryTxRequest::Transaction(QueryTxHash(response.hash))) { - if events_per_tx.is_empty() { - events.clone() - } else { - events_per_tx + // If we get events back, progress was made, so we replace the events + // with the new ones. in both cases we will check in the next iteration + // whether or not the transaction was fully committed. + if !events_per_tx.is_empty() { + *events = events_per_tx; } - } else { - events.clone() - }; - - *events = events_per_tx; + } } } - thread::sleep(Duration::from_millis(300)); - } + RetryResult::Retry(index) + }); - if all_tx_results_found(&tx_sync_results) { + match result { // All transactions confirmed - Ok(()) - } else { - Err(Kind::TxNoConfirmation.into()) + Ok(()) => Ok(tx_sync_results), + // Did not find confirmation + Err(_) => Err(Kind::TxNoConfirmation.into()), } } } @@ -608,12 +614,14 @@ impl Chain for CosmosSdkChain { }); } - self.wait_for_block_commits(&mut tx_sync_results)?; + let tx_sync_results = self.wait_for_block_commits(tx_sync_results)?; + let events = tx_sync_results .into_iter() .map(|el| el.events) .flatten() .collect(); + Ok(events) }