diff --git a/Cargo.lock b/Cargo.lock index b56a492c96..0a447534b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3071,7 +3071,7 @@ dependencies = [ [[package]] name = "fortuna" -version = "8.2.1" +version = "8.2.2" dependencies = [ "anyhow", "axum 0.6.20", diff --git a/apps/fortuna/Cargo.toml b/apps/fortuna/Cargo.toml index 0e61c0e7e1..f21ee9918d 100644 --- a/apps/fortuna/Cargo.toml +++ b/apps/fortuna/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fortuna" -version = "8.2.1" +version = "8.2.2" edition = "2021" [lib] diff --git a/apps/fortuna/src/eth_utils/utils.rs b/apps/fortuna/src/eth_utils/utils.rs index 7fe5d7ac22..04e6c89b73 100644 --- a/apps/fortuna/src/eth_utils/utils.rs +++ b/apps/fortuna/src/eth_utils/utils.rs @@ -196,7 +196,7 @@ pub async fn submit_tx_with_backoff( #[allow(clippy::large_enum_variant)] pub enum SubmitTxError { - GasUsageEstimateError(ContractError), + GasUsageEstimateError(TypedTransaction, ContractError), GasLimitExceeded { estimate: U256, limit: U256 }, GasPriceEstimateError(::Error), SubmissionError(TypedTransaction, ::Error), @@ -211,8 +211,8 @@ where { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - SubmitTxError::GasUsageEstimateError(e) => { - write!(f, "Error estimating gas for reveal: {e:?}") + SubmitTxError::GasUsageEstimateError(tx, e) => { + write!(f, "Error estimating gas for reveal: Tx:{tx:?}, Error:{e:?}") } SubmitTxError::GasLimitExceeded { estimate, limit } => write!( f, @@ -247,7 +247,16 @@ pub async fn submit_tx( // A value of 100 submits the tx with the same fee as the estimate. fee_estimate_multiplier_pct: u64, ) -> Result>> { + // Estimate the gas *before* filling the transaction. Filling the transaction increments the nonce of the + // provider. If we can't send the transaction (because the gas estimation fails), then the nonce will be + // out of sync with the one on-chain, causing subsequent transactions to fail. + let gas: U256 = call.estimate_gas().await.map_err(|e| { + backoff::Error::transient(SubmitTxError::GasUsageEstimateError(call.tx.clone(), e)) + })?; + let mut transaction = call.tx.clone(); + // Setting the gas here avoids a redundant call to estimate_gas within the Provider's fill_transaction method. + transaction.set_gas(gas); // manually fill the tx with the gas price info, so we can log the details in case of error client @@ -258,6 +267,7 @@ pub async fn submit_tx( if let Some(e) = e.as_error_response() { if let Some(e) = e.as_revert_data() { return backoff::Error::transient(SubmitTxError::GasUsageEstimateError( + transaction.clone(), ContractError::Revert(e.clone()), )); } diff --git a/apps/fortuna/src/keeper/process_event.rs b/apps/fortuna/src/keeper/process_event.rs index 7a91253be7..87d2a33ec6 100644 --- a/apps/fortuna/src/keeper/process_event.rs +++ b/apps/fortuna/src/keeper/process_event.rs @@ -137,15 +137,17 @@ pub async fn process_event_with_backoff( ); let error_mapper = |num_retries, e| { if let backoff::Error::Transient { - err: SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert)), + err: SubmitTxError::GasUsageEstimateError(tx, ContractError::Revert(revert)), .. } = &e { if let Ok(PythRandomErrorsErrors::NoSuchRequest(_)) = PythRandomErrorsErrors::decode(revert) { - let err = - SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert.clone())); + let err = SubmitTxError::GasUsageEstimateError( + tx.clone(), + ContractError::Revert(revert.clone()), + ); // Slow down the retries if the request is not found. // This probably means that the request is already fulfilled via another process. // After 5 retries, we return the error permanently. @@ -255,13 +257,13 @@ pub async fn process_event_with_backoff( .inc(); // Do not display the internal error, it might include RPC details. let reason = match e { - SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert)) => { + SubmitTxError::GasUsageEstimateError(_, ContractError::Revert(revert)) => { format!("Reverted: {revert}") } SubmitTxError::GasLimitExceeded { limit, estimate } => { format!("Gas limit exceeded: limit = {limit}, estimate = {estimate}") } - SubmitTxError::GasUsageEstimateError(_) => { + SubmitTxError::GasUsageEstimateError(_, _) => { "Unable to estimate gas usage".to_string() } SubmitTxError::GasPriceEstimateError(_) => {