Skip to content

Commit dc992b0

Browse files
committed
submit tx with retry
1 parent c32abc7 commit dc992b0

File tree

3 files changed

+58
-37
lines changed

3 files changed

+58
-37
lines changed

apps/fortuna/src/eth_utils/nonce_manager.rs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// Copied from: https://github.com/gakonst/ethers-rs/blob/34ed9e372e66235aed7074bc3f5c14922b139242/ethers-middleware/src/nonce_manager.rs
33

44
use {
5+
super::legacy_tx_middleware::LegacyTxMiddleware,
56
axum::async_trait,
7+
ethers::prelude::GasOracle,
68
ethers::{
9+
middleware::gas_oracle::GasOracleMiddleware,
710
providers::{Middleware, MiddlewareError, PendingTransaction},
811
types::{transaction::eip2718::TypedTransaction, *},
912
},
@@ -72,15 +75,6 @@ where
7275
Ok(nonce)
7376
} // guard dropped here
7477

75-
/// Resets the initialized flag so the next usage of the manager will reinitialize the nonce
76-
/// based on the chain state.
77-
/// This is useful when the RPC does not return an error if the transaction is submitted with
78-
/// an incorrect nonce.
79-
/// This is the only new method compared to the original NonceManagerMiddleware.
80-
pub fn reset(&self) {
81-
self.initialized.store(false, Ordering::SeqCst);
82-
}
83-
8478
async fn get_transaction_count_with_manager(
8579
&self,
8680
block: Option<BlockId>,
@@ -100,6 +94,33 @@ where
10094
}
10195
}
10296

97+
pub trait NonceManaged {
98+
fn reset(&self);
99+
}
100+
101+
impl<M: Middleware> NonceManaged for NonceManagerMiddleware<M> {
102+
/// Resets the initialized flag so the next usage of the manager will reinitialize the nonce
103+
/// based on the chain state.
104+
/// This is useful when the RPC does not return an error if the transaction is submitted with
105+
/// an incorrect nonce.
106+
/// This is the only new method compared to the original NonceManagerMiddleware.
107+
fn reset(&self) {
108+
self.initialized.store(false, Ordering::SeqCst);
109+
}
110+
}
111+
112+
impl<M: NonceManaged + Middleware, G: GasOracle> NonceManaged for GasOracleMiddleware<M, G> {
113+
fn reset(&self) {
114+
self.inner().reset();
115+
}
116+
}
117+
118+
impl<T: NonceManaged + Middleware> NonceManaged for LegacyTxMiddleware<T> {
119+
fn reset(&self) {
120+
self.inner().reset();
121+
}
122+
}
123+
103124
#[derive(Error, Debug)]
104125
/// Thrown when an error happens at the Nonce Manager
105126
pub enum NonceManagerError<M: Middleware> {

apps/fortuna/src/eth_utils/utils.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
use {
2+
crate::config::EscalationPolicyConfig,
3+
crate::eth_utils::nonce_manager::NonceManaged,
24
anyhow::{anyhow, Result},
3-
ethers::{contract::ContractCall, middleware::Middleware},
4-
ethers::types::U256,
5+
backoff::ExponentialBackoff,
56
ethers::types::TransactionReceipt,
7+
ethers::types::U256,
8+
ethers::{contract::ContractCall, middleware::Middleware},
9+
std::sync::atomic::AtomicU64,
610
std::sync::Arc,
7-
tracing,
8-
std::sync::atomic::AtomicU64,
9-
crate::config::EscalationPolicyConfig,
1011
tokio::time::{timeout, Duration},
11-
backoff::ExponentialBackoff,
12+
tracing,
1213
};
1314

1415
const TX_CONFIRMATION_TIMEOUT_SECS: u64 = 30;
@@ -81,7 +82,7 @@ pub async fn estimate_tx_cost<T: Middleware + 'static>(
8182
Ok(gas_price * gas_used)
8283
}
8384

84-
pub async fn submit_tx_with_backoff<T: Middleware + 'static>(
85+
pub async fn submit_tx_with_backoff<T: Middleware + NonceManaged + 'static>(
8586
middleware: Arc<T>,
8687
call: ContractCall<T, ()>,
8788
gas_limit: U256,
@@ -110,7 +111,8 @@ pub async fn submit_tx_with_backoff<T: Middleware + 'static>(
110111
gas_limit,
111112
gas_multiplier_pct,
112113
fee_multiplier_pct,
113-
).await
114+
)
115+
.await
114116
},
115117
|e, dur| {
116118
let retry_number = num_retries.load(std::sync::atomic::Ordering::Relaxed);
@@ -125,11 +127,11 @@ pub async fn submit_tx_with_backoff<T: Middleware + 'static>(
125127
)
126128
.await;
127129

128-
let duration = start_time.elapsed();
130+
let duration = start_time.elapsed();
129131
let num_retries = num_retries.load(std::sync::atomic::Ordering::Relaxed);
130132

131133
Ok(SubmitTxResult {
132-
num_retries: num_retries,
134+
num_retries,
133135
gas_multiplier: escalation_policy.get_gas_multiplier_pct(num_retries),
134136
fee_multiplier: escalation_policy.get_fee_multiplier_pct(num_retries),
135137
duration,
@@ -141,16 +143,15 @@ pub async fn submit_tx_with_backoff<T: Middleware + 'static>(
141143
/// submits the transaction if the gas estimate is below the gas limit.
142144
/// It will return a permanent or transient error depending on the error type and whether
143145
/// retry is possible or not.
144-
pub async fn submit_tx<T: Middleware + 'static>(
146+
pub async fn submit_tx<T: Middleware + NonceManaged + 'static>(
145147
client: Arc<T>,
146148
call: &ContractCall<T, ()>,
147149
gas_limit: U256,
148150
// A value of 100 submits the tx with the same gas/fee as the estimate.
149151
gas_estimate_multiplier_pct: u64,
150152
fee_estimate_multiplier_pct: u64,
151153
) -> Result<TransactionReceipt, backoff::Error<anyhow::Error>> {
152-
153-
let gas_estimate_res = call.estimate_gas().await;
154+
let gas_estimate_res = call.estimate_gas().await;
154155

155156
let gas_estimate = gas_estimate_res.map_err(|e| {
156157
// we consider the error transient even if it is a contract revert since
@@ -173,7 +174,7 @@ pub async fn submit_tx<T: Middleware + 'static>(
173174
// the padded gas estimate doesn't exceed the maximum amount of gas we are willing to use.
174175
let gas_estimate = gas_estimate.saturating_mul(gas_estimate_multiplier_pct.into()) / 100;
175176

176-
let call = call.gas(gas_estimate);
177+
let call = call.clone().gas(gas_estimate);
177178

178179
let mut transaction = call.tx.clone();
179180

@@ -207,8 +208,7 @@ pub async fn submit_tx<T: Middleware + 'static>(
207208
})?;
208209

209210
let reset_nonce = || {
210-
let nonce_manager = client.inner().inner();
211-
nonce_manager.reset();
211+
client.reset();
212212
};
213213

214214
let pending_receipt = timeout(

apps/fortuna/src/keeper/process_event.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,21 @@ pub async fn process_event_with_backoff(
4242
.reveal(event.sequence_number)
4343
.map_err(|e| anyhow!("Error revealing: {:?}", e))?;
4444

45-
let contract_call = contract
46-
.reveal_with_callback(
47-
event.provider_address,
48-
event.sequence_number,
49-
event.user_random_number,
50-
provider_revelation,
51-
);
45+
let contract_call = contract.reveal_with_callback(
46+
event.provider_address,
47+
event.sequence_number,
48+
event.user_random_number,
49+
provider_revelation,
50+
);
5251

5352
let success = submit_tx_with_backoff(
5453
contract.client(),
5554
contract_call,
5655
gas_limit,
5756
escalation_policy,
58-
).await;
59-
57+
)
58+
.await;
59+
6060
metrics
6161
.requests_processed
6262
.get_or_create(&account_label)
@@ -96,12 +96,12 @@ pub async fn process_event_with_backoff(
9696
if let Some(gas_used) = receipt.gas_used {
9797
let gas_used_float = gas_used.as_u128() as f64 / 1e18;
9898
metrics
99-
.total_gas_spent
99+
.total_gas_spent
100100
.get_or_create(&account_label)
101101
.inc_by(gas_used_float);
102-
102+
103103
if let Some(gas_price) = receipt.effective_gas_price {
104-
let gas_fee = (gas_used * gas_price).as_u128() as f64 / 1e18;
104+
let gas_fee = (gas_used * gas_price).as_u128() as f64 / 1e18;
105105
metrics
106106
.total_gas_fee_spent
107107
.get_or_create(&account_label)

0 commit comments

Comments
 (0)