-
Notifications
You must be signed in to change notification settings - Fork 2k
fix: handle empty receipt when transactions are discarded by RPCs #10457
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 2 commits
9232f69
5ba3cdd
cc10e7f
e30313a
ae67499
31a148f
0b13ba1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -207,20 +207,30 @@ impl ScriptProgress { | |
let mut tasks = futures::stream::iter(futs).buffer_unordered(10); | ||
|
||
let mut errors: Vec<String> = vec![]; | ||
let mut discarded_transactions = false; | ||
|
||
while let Some((tx_hash, result)) = tasks.next().await { | ||
match result { | ||
Err(err) => { | ||
errors.push(format!("Failure on receiving a receipt for {tx_hash:?}:\n{err}")); | ||
|
||
seq_progress.inner.write().finish_tx_spinner(tx_hash); | ||
// Check if the error is about an empty receipt | ||
if err.to_string().contains("Received an empty receipt") { | ||
discarded_transactions = true; | ||
// Special handling for empty receipts - we'll mark these for retrying | ||
deployment_sequence.remove_pending(tx_hash); | ||
let msg = format!("Transaction {tx_hash:?} was discarded by RPC. It will be retried when using --resume."); | ||
seq_progress.inner.write().finish_tx_spinner_with_msg(tx_hash, &msg)?; | ||
} else { | ||
errors.push(format!("Failure on receiving a receipt for {tx_hash:?}:\n{err}")); | ||
seq_progress.inner.write().finish_tx_spinner(tx_hash); | ||
} | ||
} | ||
Ok(TxStatus::Dropped) => { | ||
// We want to remove it from pending so it will be re-broadcast. | ||
deployment_sequence.remove_pending(tx_hash); | ||
errors.push(format!("Transaction dropped from the mempool: {tx_hash:?}")); | ||
|
||
seq_progress.inner.write().finish_tx_spinner(tx_hash); | ||
discarded_transactions = true; | ||
|
||
let msg = format!("Transaction {tx_hash:?} dropped from the mempool. It will be retried when using --resume."); | ||
seq_progress.inner.write().finish_tx_spinner_with_msg(tx_hash, &msg)?; | ||
} | ||
Ok(TxStatus::Success(receipt)) => { | ||
trace!(tx_hash=?tx_hash, "received tx receipt"); | ||
|
@@ -249,11 +259,17 @@ impl ScriptProgress { | |
// print any errors | ||
if !errors.is_empty() { | ||
let mut error_msg = errors.join("\n"); | ||
if !deployment_sequence.pending.is_empty() { | ||
error_msg += "\n\n Add `--resume` to your command to try and continue broadcasting | ||
the transactions." | ||
|
||
// Add information about using --resume if necessary | ||
if !deployment_sequence.pending.is_empty() || discarded_transactions { | ||
error_msg += "\n\n Add `--resume` to your command to try and continue broadcasting "; | ||
error_msg += "the transactions. This will attempt to resend transactions that were discarded by the RPC."; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd prefer a single raw string here r#""# |
||
} | ||
|
||
eyre::bail!(error_msg); | ||
} else if discarded_transactions { | ||
// If we have discarded transactions but no errors, still inform the user | ||
sh_warn!("Some transactions were discarded by the RPC node. Use `--resume` to retry these transactions.")?; | ||
} | ||
|
||
Ok(()) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -37,7 +37,27 @@ pub async fn check_tx_status( | |
.get_receipt() | ||
.await | ||
{ | ||
Ok(receipt) => Ok(receipt.into()), | ||
Ok(receipt) => { | ||
// Check if the receipt has valid block information | ||
if receipt.block_number.is_none() || receipt.block_hash.is_none() || receipt.transaction_index.is_none() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. receipt usually should only return mined transactions, but I can see that some networks might behave that way. since these are mostly faster L2s, I wonder if the better approach here would be, just retry a few times here? |
||
// Receipt is empty, possibly due to RPC discarding the transaction | ||
match provider.get_transaction_by_hash(hash).await { | ||
Ok(_) => { | ||
// Transaction is still known to the node, so we should wait | ||
Err(RetryError::Continue(eyre!( | ||
"Received an empty receipt for {hash}, but transaction is still known to the node, waiting for full receipt" | ||
))) | ||
} | ||
Err(_) => { | ||
// Transaction is not known to the node, mark it as dropped | ||
Ok(TxStatus::Dropped) | ||
} | ||
} | ||
} else { | ||
// Receipt has valid block information, proceed normally | ||
Ok(receipt.into()) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd like to lift this up, like
|
||
} | ||
} | ||
Err(e) => match provider.get_transaction_by_hash(hash).await { | ||
Ok(_) => match e { | ||
PendingTransactionError::TxWatcher(WatchTxError::Timeout) => { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this isn't quite empty, but pending, can we update the wording here?