@@ -7,18 +7,19 @@ use std::{
77} ;
88
99use alloy_consensus:: {
10- Header , TxReceipt ,
10+ Eip658Value , Header , TxReceipt ,
1111 transaction:: { Recovered , SignerRecoverable , TransactionMeta } ,
1212} ;
1313use alloy_eips:: BlockNumberOrTag ;
14+ use alloy_op_evm:: block:: receipt_builder:: OpReceiptBuilder ;
1415use alloy_primitives:: { B256 , BlockNumber , Bytes , Sealable , map:: foldhash:: HashMap } ;
1516use alloy_rpc_types:: { TransactionTrait , Withdrawal } ;
1617use alloy_rpc_types_engine:: { ExecutionPayloadV1 , ExecutionPayloadV2 , ExecutionPayloadV3 } ;
1718use alloy_rpc_types_eth:: state:: StateOverride ;
1819use arc_swap:: ArcSwapOption ;
1920use base_flashtypes:: Flashblock ;
2021use eyre:: eyre;
21- use op_alloy_consensus:: OpTxEnvelope ;
22+ use op_alloy_consensus:: { OpDepositReceipt , OpTxEnvelope } ;
2223use op_alloy_network:: TransactionResponse ;
2324use op_alloy_rpc_types:: Transaction ;
2425use reth:: {
@@ -29,11 +30,11 @@ use reth::{
2930 db:: CacheDB ,
3031 } ,
3132} ;
32- use reth_evm:: { ConfigureEvm , Evm } ;
33+ use reth_evm:: { ConfigureEvm , Evm , eth :: receipt_builder :: ReceiptBuilderCtx } ;
3334use reth_optimism_chainspec:: OpHardforks ;
3435use reth_optimism_evm:: { OpEvmConfig , OpNextBlockEnvAttributes } ;
3536use reth_optimism_primitives:: { DepositReceipt , OpBlock , OpPrimitives } ;
36- use reth_optimism_rpc:: OpReceiptBuilder ;
37+ use reth_optimism_rpc:: OpReceiptBuilder as OpRpcReceiptBuilder ;
3738use reth_primitives:: RecoveredBlock ;
3839use reth_rpc_convert:: transaction:: ConvertReceiptInput ;
3940use tokio:: sync:: { Mutex , broadcast:: Sender , mpsc:: UnboundedReceiver } ;
@@ -333,7 +334,9 @@ where
333334 . iter ( )
334335 . map ( |flashblock| flashblock. metadata . receipts . clone ( ) )
335336 . fold ( HashMap :: default ( ) , |mut acc, receipts| {
336- acc. extend ( receipts) ;
337+ if let Some ( receipts) = receipts {
338+ acc. extend ( receipts) ;
339+ }
337340 acc
338341 } ) ;
339342
@@ -390,7 +393,7 @@ where
390393 let evm_env = evm_config. next_evm_env ( & last_block_header, & block_env_attributes) ?;
391394 let mut evm = evm_config. evm_with_env ( db, evm_env) ;
392395
393- let mut gas_used = 0 ;
396+ let mut cumulative_gas_used : u64 = 0 ;
394397 let mut next_log_index = 0 ;
395398
396399 for ( idx, transaction) in block. body . transactions . iter ( ) . enumerate ( ) {
@@ -407,16 +410,15 @@ where
407410 pending_blocks_builder. with_transaction_sender ( tx_hash, sender) ;
408411 pending_blocks_builder. increment_nonce ( sender) ;
409412
410- let receipt = receipt_by_hash
411- . get ( & tx_hash)
412- . cloned ( )
413- . ok_or ( eyre ! ( "missing receipt for {:?}" , tx_hash) ) ?;
413+ let receipt = receipt_by_hash. get ( & tx_hash) . cloned ( ) ;
414414
415415 let recovered_transaction = Recovered :: new_unchecked ( transaction. clone ( ) , sender) ;
416416 let envelope = recovered_transaction. clone ( ) . convert :: < OpTxEnvelope > ( ) ;
417417
418418 // Build Transaction
419- let ( deposit_receipt_version, deposit_nonce) = if transaction. is_deposit ( ) {
419+ let ( deposit_receipt_version, deposit_nonce) = if transaction. is_deposit ( )
420+ && let Some ( receipt) = & receipt
421+ {
420422 let deposit_receipt = receipt
421423 . as_deposit_receipt ( )
422424 . ok_or ( eyre ! ( "deposit transaction, non deposit receipt" ) ) ?;
@@ -451,54 +453,32 @@ where
451453 } ;
452454
453455 pending_blocks_builder. with_transaction ( rpc_txn) ;
456+ let mut should_execute_transaction = true ;
454457
455458 // Receipt Generation
456- let op_receipt = prev_pending_blocks
457- . as_ref ( )
458- . and_then ( |pending_blocks| pending_blocks. get_receipt ( tx_hash) )
459- . unwrap_or_else ( || {
460- let meta = TransactionMeta {
461- tx_hash,
462- index : idx as u64 ,
463- block_hash : header. hash ( ) ,
464- block_number : block. number ,
465- base_fee : block. base_fee_per_gas ,
466- excess_blob_gas : block. excess_blob_gas ,
467- timestamp : block. timestamp ,
468- } ;
469-
470- let input: ConvertReceiptInput < ' _ , OpPrimitives > = ConvertReceiptInput {
471- receipt : receipt. clone ( ) ,
472- tx : Recovered :: new_unchecked ( transaction, sender) ,
473- gas_used : receipt. cumulative_gas_used ( ) - gas_used,
474- next_log_index,
475- meta,
476- } ;
477-
478- OpReceiptBuilder :: new (
479- self . client . chain_spec ( ) . as_ref ( ) ,
480- input,
481- & mut l1_block_info,
482- )
483- . unwrap ( )
484- . build ( )
485- } ) ;
486-
487- pending_blocks_builder. with_receipt ( tx_hash, op_receipt) ;
488- gas_used = receipt. cumulative_gas_used ( ) ;
489- next_log_index += receipt. logs ( ) . len ( ) ;
459+ let saved_receipt = {
460+ let receipt = prev_pending_blocks. as_ref ( ) . and_then ( |p| p. get_receipt ( tx_hash) ) ;
461+
462+ if let Some ( receipt) = receipt {
463+ pending_blocks_builder. with_receipt ( tx_hash, receipt) ;
464+ true
465+ } else {
466+ false
467+ }
468+ } ;
490469
491- let mut should_execute_transaction = true ;
492- if let Some ( state) =
493- prev_pending_blocks. as_ref ( ) . and_then ( |p| p. get_transaction_state ( & tx_hash) )
470+ if saved_receipt
471+ && let Some ( state) =
472+ prev_pending_blocks. as_ref ( ) . and_then ( |p| p. get_transaction_state ( & tx_hash) )
494473 {
495474 pending_blocks_builder. with_transaction_state ( tx_hash, state) ;
496475 should_execute_transaction = false ;
497476 }
498477
499478 if should_execute_transaction {
500- match evm. transact ( recovered_transaction) {
501- Ok ( ResultAndState { state, .. } ) => {
479+ match evm. transact ( recovered_transaction. clone ( ) ) {
480+ Ok ( ResultAndState { state, result } ) => {
481+ let gas_used = result. gas_used ( ) ;
502482 for ( addr, acc) in & state {
503483 let existing_override = state_overrides. entry ( * addr) . or_default ( ) ;
504484 existing_override. balance = Some ( acc. info . balance ) ;
@@ -514,6 +494,77 @@ where
514494
515495 existing. extend ( changed_slots) ;
516496 }
497+
498+ cumulative_gas_used = cumulative_gas_used
499+ . checked_add ( gas_used)
500+ . ok_or ( eyre ! ( "cumulative gas used overflow" ) ) ?;
501+
502+ let receipt_builder =
503+ evm_config. block_executor_factory ( ) . receipt_builder ( ) ;
504+
505+ let is_canyon_active = self
506+ . client
507+ . chain_spec ( )
508+ . is_canyon_active_at_timestamp ( block. timestamp ) ;
509+ let receipt = match receipt_builder. build_receipt ( ReceiptBuilderCtx {
510+ tx : & recovered_transaction,
511+ evm : & evm,
512+ result,
513+ state : & state,
514+ cumulative_gas_used,
515+ } ) {
516+ Ok ( receipt) => receipt,
517+ Err ( ctx) => {
518+ let receipt = alloy_consensus:: Receipt {
519+ // Success flag was added in `EIP-658: Embedding transaction status code
520+ // in receipts`.
521+ status : Eip658Value :: Eip658 ( ctx. result . is_success ( ) ) ,
522+ cumulative_gas_used : ctx. cumulative_gas_used ,
523+ logs : ctx. result . into_logs ( ) ,
524+ } ;
525+
526+ receipt_builder. build_deposit_receipt ( OpDepositReceipt {
527+ inner : receipt,
528+ deposit_nonce,
529+ // The deposit receipt version was introduced in Canyon to indicate an
530+ // update to how receipt hashes should be computed
531+ // when set. The state transition process ensures
532+ // this is only set for post-Canyon deposit
533+ // transactions.
534+ deposit_receipt_version : is_canyon_active. then_some ( 1 ) ,
535+ } )
536+ }
537+ } ;
538+
539+ let meta = TransactionMeta {
540+ tx_hash,
541+ index : idx as u64 ,
542+ block_hash : header. hash ( ) ,
543+ block_number : block. number ,
544+ base_fee : block. base_fee_per_gas ,
545+ excess_blob_gas : block. excess_blob_gas ,
546+ timestamp : block. timestamp ,
547+ } ;
548+
549+ let input: ConvertReceiptInput < ' _ , OpPrimitives > =
550+ ConvertReceiptInput {
551+ receipt : receipt. clone ( ) ,
552+ tx : Recovered :: new_unchecked ( transaction, sender) ,
553+ gas_used,
554+ next_log_index,
555+ meta,
556+ } ;
557+
558+ let op_receipt = OpRpcReceiptBuilder :: new (
559+ self . client . chain_spec ( ) . as_ref ( ) ,
560+ input,
561+ & mut l1_block_info,
562+ )
563+ . unwrap ( )
564+ . build ( ) ;
565+ next_log_index = next_log_index + receipt. logs ( ) . len ( ) ;
566+
567+ pending_blocks_builder. with_receipt ( tx_hash, op_receipt) ;
517568 pending_blocks_builder. with_transaction_state ( tx_hash, state. clone ( ) ) ;
518569 evm. db_mut ( ) . commit ( state) ;
519570 }
0 commit comments