Skip to content

Commit 951f189

Browse files
committed
Retry getting transaction receipt
1 parent 0513a4b commit 951f189

File tree

4 files changed

+83
-15
lines changed

4 files changed

+83
-15
lines changed

Cargo.lock

Lines changed: 7 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/config/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! The global configuration used accross all revive differential testing crates.
1+
//! The global configuration used across all revive differential testing crates.
22
33
use std::{
44
fmt::Display,

crates/node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ rust-version.workspace = true
1212
anyhow = { workspace = true }
1313
alloy = { workspace = true }
1414
tracing = { workspace = true }
15+
tokio = { workspace = true }
1516

1617
revive-dt-node-interaction = { workspace = true }
1718
revive-dt-config = { workspace = true }

crates/node/src/geth.rs

Lines changed: 74 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,17 +159,82 @@ impl EthereumNode for Instance {
159159
let connection_string = self.connection_string();
160160
let wallet = self.wallet.clone();
161161

162-
tracing::debug!("Submitting transaction: {transaction:#?}");
163-
164162
execute_transaction(Box::pin(async move {
165-
Ok(ProviderBuilder::new()
163+
let outer_span = tracing::debug_span!("Submitting transaction", ?transaction,);
164+
let _outer_guard = outer_span.enter();
165+
166+
let provider = ProviderBuilder::new()
166167
.wallet(wallet)
167168
.connect(&connection_string)
168-
.await?
169-
.send_transaction(transaction)
170-
.await?
171-
.get_receipt()
172-
.await?)
169+
.await?;
170+
171+
let pending_transaction = provider.send_transaction(transaction).await?;
172+
let transaction_hash = pending_transaction.tx_hash();
173+
174+
let span = tracing::info_span!("Awaiting transaction receipt", ?transaction_hash);
175+
let _guard = span.enter();
176+
177+
// The following is a fix for the "transaction indexing is in progress" error that we
178+
// used to get. You can find more information on this in the following GH issue in geth
179+
// https://github.com/ethereum/go-ethereum/issues/28877. To summarize what's going on,
180+
// before we can get the receipt of the transaction it needs to have been indexed by the
181+
// node's indexer. Just because the transaction has been confirmed it doesn't mean that
182+
// it has been indexed. When we call alloy's `get_receipt` it checks if the transaction
183+
// was confirmed. If it has been, then it will call `eth_getTransactionReceipt` method
184+
// which _might_ return the above error if the tx has not yet been indexed yet. So, we
185+
// need to implement a retry mechanism for the receipt to keep retrying to get it until
186+
// it eventually works, but we only do that if the error we get back is the "transaction
187+
// indexing is in progress" error or if the receipt is None.
188+
//
189+
// At the moment we do not allow for the 60 seconds to be modified and we take it as
190+
// being an implementation detail that's invisible to anything outside of this module.
191+
//
192+
// We allow a total of 60 retries for getting the receipt with one second between each
193+
// retry and the next which means that we allow for a total of 60 seconds of waiting
194+
// before we consider that we're unable to get the transaction receipt.
195+
let mut retries = 0;
196+
loop {
197+
match provider.get_transaction_receipt(*transaction_hash).await {
198+
Ok(Some(receipt)) => {
199+
tracing::info!("Obtained the transaction receipt");
200+
break Ok(receipt);
201+
}
202+
Ok(None) => {
203+
if retries == 60 {
204+
tracing::error!(
205+
"Polled for transaction receipt for 60 seconds but failed to get it"
206+
);
207+
break Err(anyhow::anyhow!("Failed to get the transaction receipt"));
208+
} else {
209+
tracing::trace!(
210+
retries,
211+
"Sleeping for 1 second and trying to get the receipt again"
212+
);
213+
retries += 1;
214+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
215+
continue;
216+
}
217+
}
218+
Err(error) => {
219+
let error_string = error.to_string();
220+
if error_string.contains("transaction indexing is in progress") {
221+
if retries == 60 {
222+
break Err(error.into());
223+
} else {
224+
tracing::trace!(
225+
retries,
226+
"Sleeping for 1 second and trying to get the receipt again"
227+
);
228+
retries += 1;
229+
tokio::time::sleep(std::time::Duration::from_secs(1)).await;
230+
continue;
231+
}
232+
} else {
233+
break Err(error.into());
234+
}
235+
}
236+
}
237+
}
173238
}))
174239
}
175240

@@ -270,6 +335,7 @@ impl Node for Instance {
270335

271336
impl Drop for Instance {
272337
fn drop(&mut self) {
338+
tracing::info!(id = self.id, "Dropping node");
273339
if let Some(child) = self.handle.as_mut() {
274340
let _ = child.kill();
275341
}

0 commit comments

Comments
 (0)