Skip to content

Commit f13901f

Browse files
chee-chyuanclaude
andcommitted
fix(engine): flush post-finalization receipts to receipt-root task
`receipt_tx` was dropped immediately after `execute_transactions` returned, before `executor.finish()` ran. Any receipts appended during finalization (e.g. system transaction receipts on BSC) were never sent to the background receipt-root task, causing it to see fewer receipts than expected and silently fail to compute the root. Fix by carrying `last_sent_len` out of `execute_transactions`, running `finish()` first, then flushing any remaining receipts before dropping the sender — matching the pattern in the upstream develop branch. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 30bfb2b commit f13901f

2 files changed

Lines changed: 14 additions & 4 deletions

File tree

Cargo.lock

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

crates/engine/tree/src/tree/payload_validator.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1284,14 +1284,13 @@ where
12841284
let execution_start = Instant::now();
12851285

12861286
// Execute all transactions and finalize
1287-
let (executor, senders) = self.execute_transactions(
1287+
let (executor, senders, last_sent_len) = self.execute_transactions(
12881288
executor,
12891289
transaction_count,
12901290
handle.iter_transactions(),
12911291
&receipt_tx,
12921292
&executed_tx_index,
12931293
)?;
1294-
drop(receipt_tx);
12951294

12961295
// Finish execution and get the result
12971296
let post_exec_start = Instant::now();
@@ -1300,6 +1299,16 @@ where
13001299
.map(|(evm, result)| (evm.into_db(), result))?;
13011300
self.metrics.record_post_execution(post_exec_start.elapsed());
13021301

1302+
// Some receipts may be appended during post-execution finalization rather than during the
1303+
// main transaction loop (e.g., system transactions). Ensure the background receipt-root
1304+
// task sees the full receipt set before the channel closes.
1305+
if result.receipts.len() > last_sent_len {
1306+
for (tx_index, receipt) in result.receipts.iter().enumerate().skip(last_sent_len) {
1307+
let _ = receipt_tx.send(IndexedReceipt::new(tx_index, receipt.clone()));
1308+
}
1309+
}
1310+
drop(receipt_tx);
1311+
13031312
// Merge transitions into bundle state
13041313
debug_span!(target: "engine::tree", "merge_transitions")
13051314
.in_scope(|| db.merge_transitions(BundleRetention::Reverts));
@@ -1330,7 +1339,7 @@ where
13301339
transactions: impl Iterator<Item = Result<Tx, Err>>,
13311340
receipt_tx: &crossbeam_channel::Sender<IndexedReceipt<N::Receipt>>,
13321341
executed_tx_index: &AtomicUsize,
1333-
) -> Result<(E, Vec<Address>), BlockExecutionError>
1342+
) -> Result<(E, Vec<Address>, usize), BlockExecutionError>
13341343
where
13351344
E: BlockExecutor<Receipt = N::Receipt>,
13361345
Tx: alloy_evm::block::ExecutableTx<E> + alloy_evm::RecoveredTx<InnerTx>,
@@ -1392,7 +1401,7 @@ where
13921401
}
13931402
drop(exec_span);
13941403

1395-
Ok((executor, senders))
1404+
Ok((executor, senders, last_sent_len))
13961405
}
13971406

13981407
/// Compute state root for the given hashed post state in parallel.

0 commit comments

Comments
 (0)