Skip to content

Commit af5d5f8

Browse files
authored
fix(fortuna): Fix nonce increment issues on high usage chains (#2868)
1 parent 2e063c0 commit af5d5f8

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/fortuna/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fortuna"
3-
version = "8.2.1"
3+
version = "8.2.2"
44
edition = "2021"
55

66
[lib]

apps/fortuna/src/eth_utils/utils.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ pub async fn submit_tx_with_backoff<T: Middleware + NonceManaged + 'static>(
196196

197197
#[allow(clippy::large_enum_variant)]
198198
pub enum SubmitTxError<T: Middleware + NonceManaged + 'static> {
199-
GasUsageEstimateError(ContractError<T>),
199+
GasUsageEstimateError(TypedTransaction, ContractError<T>),
200200
GasLimitExceeded { estimate: U256, limit: U256 },
201201
GasPriceEstimateError(<T as Middleware>::Error),
202202
SubmissionError(TypedTransaction, <T as Middleware>::Error),
@@ -211,8 +211,8 @@ where
211211
{
212212
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213213
match self {
214-
SubmitTxError::GasUsageEstimateError(e) => {
215-
write!(f, "Error estimating gas for reveal: {e:?}")
214+
SubmitTxError::GasUsageEstimateError(tx, e) => {
215+
write!(f, "Error estimating gas for reveal: Tx:{tx:?}, Error:{e:?}")
216216
}
217217
SubmitTxError::GasLimitExceeded { estimate, limit } => write!(
218218
f,
@@ -247,7 +247,16 @@ pub async fn submit_tx<T: Middleware + NonceManaged + 'static>(
247247
// A value of 100 submits the tx with the same fee as the estimate.
248248
fee_estimate_multiplier_pct: u64,
249249
) -> Result<TransactionReceipt, backoff::Error<SubmitTxError<T>>> {
250+
// Estimate the gas *before* filling the transaction. Filling the transaction increments the nonce of the
251+
// provider. If we can't send the transaction (because the gas estimation fails), then the nonce will be
252+
// out of sync with the one on-chain, causing subsequent transactions to fail.
253+
let gas: U256 = call.estimate_gas().await.map_err(|e| {
254+
backoff::Error::transient(SubmitTxError::GasUsageEstimateError(call.tx.clone(), e))
255+
})?;
256+
250257
let mut transaction = call.tx.clone();
258+
// Setting the gas here avoids a redundant call to estimate_gas within the Provider's fill_transaction method.
259+
transaction.set_gas(gas);
251260

252261
// manually fill the tx with the gas price info, so we can log the details in case of error
253262
client
@@ -258,6 +267,7 @@ pub async fn submit_tx<T: Middleware + NonceManaged + 'static>(
258267
if let Some(e) = e.as_error_response() {
259268
if let Some(e) = e.as_revert_data() {
260269
return backoff::Error::transient(SubmitTxError::GasUsageEstimateError(
270+
transaction.clone(),
261271
ContractError::Revert(e.clone()),
262272
));
263273
}

apps/fortuna/src/keeper/process_event.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,17 @@ pub async fn process_event_with_backoff(
137137
);
138138
let error_mapper = |num_retries, e| {
139139
if let backoff::Error::Transient {
140-
err: SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert)),
140+
err: SubmitTxError::GasUsageEstimateError(tx, ContractError::Revert(revert)),
141141
..
142142
} = &e
143143
{
144144
if let Ok(PythRandomErrorsErrors::NoSuchRequest(_)) =
145145
PythRandomErrorsErrors::decode(revert)
146146
{
147-
let err =
148-
SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert.clone()));
147+
let err = SubmitTxError::GasUsageEstimateError(
148+
tx.clone(),
149+
ContractError::Revert(revert.clone()),
150+
);
149151
// Slow down the retries if the request is not found.
150152
// This probably means that the request is already fulfilled via another process.
151153
// After 5 retries, we return the error permanently.
@@ -255,13 +257,13 @@ pub async fn process_event_with_backoff(
255257
.inc();
256258
// Do not display the internal error, it might include RPC details.
257259
let reason = match e {
258-
SubmitTxError::GasUsageEstimateError(ContractError::Revert(revert)) => {
260+
SubmitTxError::GasUsageEstimateError(_, ContractError::Revert(revert)) => {
259261
format!("Reverted: {revert}")
260262
}
261263
SubmitTxError::GasLimitExceeded { limit, estimate } => {
262264
format!("Gas limit exceeded: limit = {limit}, estimate = {estimate}")
263265
}
264-
SubmitTxError::GasUsageEstimateError(_) => {
266+
SubmitTxError::GasUsageEstimateError(_, _) => {
265267
"Unable to estimate gas usage".to_string()
266268
}
267269
SubmitTxError::GasPriceEstimateError(_) => {

0 commit comments

Comments
 (0)