@@ -113,15 +113,15 @@ use op_alloy_consensus::DEPOSIT_TX_TYPE_ID;
113
113
use op_revm:: {
114
114
OpContext , OpHaltReason , OpTransaction , transaction:: deposit:: DepositTransactionParts ,
115
115
} ;
116
- use parking_lot:: { Mutex , RwLock } ;
116
+ use parking_lot:: { Mutex , RwLock , RwLockUpgradableReadGuard } ;
117
117
use revm:: {
118
118
DatabaseCommit , Inspector ,
119
119
context:: { Block as RevmBlock , BlockEnv , Cfg , TxEnv } ,
120
120
context_interface:: {
121
121
block:: BlobExcessGasAndPrice ,
122
122
result:: { ExecutionResult , Output , ResultAndState } ,
123
123
} ,
124
- database:: { CacheDB , WrapDatabaseRef } ,
124
+ database:: { CacheDB , DbAccount , WrapDatabaseRef } ,
125
125
interpreter:: InstructionResult ,
126
126
precompile:: { PrecompileSpecId , Precompiles } ,
127
127
primitives:: { KECCAK_EMPTY , hardfork:: SpecId } ,
@@ -2465,19 +2465,16 @@ impl Backend {
2465
2465
. block_by_number ( BlockNumber :: Number ( block_number) )
2466
2466
. await ?
2467
2467
. map ( |block| ( block. header . hash , block) )
2468
- && let Some ( state) = self . states . write ( ) . get ( & block_hash)
2469
2468
{
2470
- let block = BlockEnv {
2471
- number : U256 :: from ( block_number) ,
2472
- beneficiary : block. header . beneficiary ,
2473
- timestamp : U256 :: from ( block. header . timestamp ) ,
2474
- difficulty : block. header . difficulty ,
2475
- prevrandao : block. header . mix_hash ,
2476
- basefee : block. header . base_fee_per_gas . unwrap_or_default ( ) ,
2477
- gas_limit : block. header . gas_limit ,
2478
- ..Default :: default ( )
2479
- } ;
2480
- return Ok ( f ( Box :: new ( state) , block) ) ;
2469
+ let read_guard = self . states . upgradable_read ( ) ;
2470
+ if let Some ( state_db) = read_guard. get_state ( & block_hash) {
2471
+ return Ok ( get_block_env ( state_db, block_number, block, f) ) ;
2472
+ } else {
2473
+ let mut write_guard = RwLockUpgradableReadGuard :: upgrade ( read_guard) ;
2474
+ if let Some ( state) = write_guard. get_on_disk_state ( & block_hash) {
2475
+ return Ok ( get_block_env ( state, block_number, block, f) ) ;
2476
+ }
2477
+ }
2481
2478
}
2482
2479
2483
2480
warn ! ( target: "backend" , "Not historic state found for block={}" , block_number) ;
@@ -2716,57 +2713,67 @@ impl Backend {
2716
2713
} )
2717
2714
. collect ( ) ;
2718
2715
2719
- let mut states = self . states . write ( ) ;
2720
- let parent_state =
2721
- states. get ( & block. header . parent_hash ) . ok_or ( BlockchainError :: BlockNotFound ) ?;
2722
- let mut cache_db = CacheDB :: new ( Box :: new ( parent_state) ) ;
2716
+ let trace = |parent_state : & StateDb | -> Result < T , BlockchainError > {
2717
+ let mut cache_db = CacheDB :: new ( Box :: new ( parent_state) ) ;
2723
2718
2724
- // configure the blockenv for the block of the transaction
2725
- let mut env = self . env . read ( ) . clone ( ) ;
2719
+ // configure the blockenv for the block of the transaction
2720
+ let mut env = self . env . read ( ) . clone ( ) ;
2726
2721
2727
- env. evm_env . block_env = BlockEnv {
2728
- number : U256 :: from ( block. header . number ) ,
2729
- beneficiary : block. header . beneficiary ,
2730
- timestamp : U256 :: from ( block. header . timestamp ) ,
2731
- difficulty : block. header . difficulty ,
2732
- prevrandao : Some ( block. header . mix_hash ) ,
2733
- basefee : block. header . base_fee_per_gas . unwrap_or_default ( ) ,
2734
- gas_limit : block. header . gas_limit ,
2735
- ..Default :: default ( )
2736
- } ;
2722
+ env. evm_env . block_env = BlockEnv {
2723
+ number : U256 :: from ( block. header . number ) ,
2724
+ beneficiary : block. header . beneficiary ,
2725
+ timestamp : U256 :: from ( block. header . timestamp ) ,
2726
+ difficulty : block. header . difficulty ,
2727
+ prevrandao : Some ( block. header . mix_hash ) ,
2728
+ basefee : block. header . base_fee_per_gas . unwrap_or_default ( ) ,
2729
+ gas_limit : block. header . gas_limit ,
2730
+ ..Default :: default ( )
2731
+ } ;
2737
2732
2738
- let executor = TransactionExecutor {
2739
- db : & mut cache_db,
2740
- validator : self ,
2741
- pending : pool_txs. into_iter ( ) ,
2742
- block_env : env. evm_env . block_env . clone ( ) ,
2743
- cfg_env : env. evm_env . cfg_env . clone ( ) ,
2744
- parent_hash : block. header . parent_hash ,
2745
- gas_used : 0 ,
2746
- blob_gas_used : 0 ,
2747
- enable_steps_tracing : self . enable_steps_tracing ,
2748
- print_logs : self . print_logs ,
2749
- print_traces : self . print_traces ,
2750
- call_trace_decoder : self . call_trace_decoder . clone ( ) ,
2751
- precompile_factory : self . precompile_factory . clone ( ) ,
2752
- networks : self . env . read ( ) . networks ,
2753
- blob_params : self . blob_params ( ) ,
2754
- cheats : self . cheats ( ) . clone ( ) ,
2755
- } ;
2733
+ let executor = TransactionExecutor {
2734
+ db : & mut cache_db,
2735
+ validator : self ,
2736
+ pending : pool_txs. into_iter ( ) ,
2737
+ block_env : env. evm_env . block_env . clone ( ) ,
2738
+ cfg_env : env. evm_env . cfg_env . clone ( ) ,
2739
+ parent_hash : block. header . parent_hash ,
2740
+ gas_used : 0 ,
2741
+ blob_gas_used : 0 ,
2742
+ enable_steps_tracing : self . enable_steps_tracing ,
2743
+ print_logs : self . print_logs ,
2744
+ print_traces : self . print_traces ,
2745
+ call_trace_decoder : self . call_trace_decoder . clone ( ) ,
2746
+ precompile_factory : self . precompile_factory . clone ( ) ,
2747
+ networks : self . env . read ( ) . networks ,
2748
+ blob_params : self . blob_params ( ) ,
2749
+ cheats : self . cheats ( ) . clone ( ) ,
2750
+ } ;
2756
2751
2757
- let _ = executor. execute ( ) ;
2752
+ let _ = executor. execute ( ) ;
2758
2753
2759
- let target_tx = block. transactions [ index] . clone ( ) ;
2760
- let target_tx = PendingTransaction :: from_maybe_impersonated ( target_tx) ?;
2761
- let tx_env = target_tx. to_revm_tx_env ( ) ;
2754
+ let target_tx = block. transactions [ index] . clone ( ) ;
2755
+ let target_tx = PendingTransaction :: from_maybe_impersonated ( target_tx) ?;
2756
+ let tx_env = target_tx. to_revm_tx_env ( ) ;
2762
2757
2763
- let mut evm = self . new_evm_with_inspector_ref ( & cache_db, & env, & mut inspector) ;
2758
+ let mut evm = self . new_evm_with_inspector_ref ( & cache_db, & env, & mut inspector) ;
2764
2759
2765
- let result = evm
2766
- . transact ( tx_env. clone ( ) )
2767
- . map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
2760
+ let result = evm
2761
+ . transact ( tx_env. clone ( ) )
2762
+ . map_err ( |err| BlockchainError :: Message ( err. to_string ( ) ) ) ?;
2763
+
2764
+ Ok ( f ( result, cache_db, inspector, tx_env. base , env) )
2765
+ } ;
2768
2766
2769
- Ok ( f ( result, cache_db, inspector, tx_env. base , env) )
2767
+ let read_guard = self . states . upgradable_read ( ) ;
2768
+ if let Some ( state) = read_guard. get_state ( & block. header . parent_hash ) {
2769
+ trace ( state)
2770
+ } else {
2771
+ let mut write_guard = RwLockUpgradableReadGuard :: upgrade ( read_guard) ;
2772
+ let state = write_guard
2773
+ . get_on_disk_state ( & block. header . parent_hash )
2774
+ . ok_or ( BlockchainError :: BlockNotFound ) ?;
2775
+ trace ( state)
2776
+ }
2770
2777
}
2771
2778
2772
2779
/// Traces the transaction with the js tracer
@@ -3451,12 +3458,22 @@ impl Backend {
3451
3458
pub async fn rollback ( & self , common_block : Block ) -> Result < ( ) , BlockchainError > {
3452
3459
// Get the database at the common block
3453
3460
let common_state = {
3454
- let mut state = self . states . write ( ) ;
3455
- let state_db = state
3456
- . get ( & common_block. header . hash_slow ( ) )
3457
- . ok_or ( BlockchainError :: DataUnavailable ) ?;
3458
- let db_full = state_db. maybe_as_full_db ( ) . ok_or ( BlockchainError :: DataUnavailable ) ?;
3459
- db_full. clone ( )
3461
+ let return_state_or_throw_err =
3462
+ |db : Option < & StateDb > | -> Result < HashMap < Address , DbAccount > , BlockchainError > {
3463
+ let state_db = db. ok_or ( BlockchainError :: DataUnavailable ) ?;
3464
+ let db_full =
3465
+ state_db. maybe_as_full_db ( ) . ok_or ( BlockchainError :: DataUnavailable ) ?;
3466
+ Ok ( db_full. clone ( ) )
3467
+ } ;
3468
+
3469
+ let hash = & common_block. header . hash_slow ( ) ;
3470
+ let read_guard = self . states . upgradable_read ( ) ;
3471
+ if let Some ( db) = read_guard. get_state ( hash) {
3472
+ return_state_or_throw_err ( Some ( db) ) ?
3473
+ } else {
3474
+ let mut write_guard = RwLockUpgradableReadGuard :: upgrade ( read_guard) ;
3475
+ return_state_or_throw_err ( write_guard. get_on_disk_state ( hash) ) ?
3476
+ }
3460
3477
} ;
3461
3478
3462
3479
{
@@ -3491,6 +3508,23 @@ impl Backend {
3491
3508
}
3492
3509
}
3493
3510
3511
+ fn get_block_env < F , T > ( state : & StateDb , block_number : u64 , block : AnyRpcBlock , f : F ) -> T
3512
+ where
3513
+ F : FnOnce ( Box < dyn MaybeFullDatabase + ' _ > , BlockEnv ) -> T ,
3514
+ {
3515
+ let block = BlockEnv {
3516
+ number : U256 :: from ( block_number) ,
3517
+ beneficiary : block. header . beneficiary ,
3518
+ timestamp : U256 :: from ( block. header . timestamp ) ,
3519
+ difficulty : block. header . difficulty ,
3520
+ prevrandao : block. header . mix_hash ,
3521
+ basefee : block. header . base_fee_per_gas . unwrap_or_default ( ) ,
3522
+ gas_limit : block. header . gas_limit ,
3523
+ ..Default :: default ( )
3524
+ } ;
3525
+ f ( Box :: new ( state) , block)
3526
+ }
3527
+
3494
3528
/// Get max nonce from transaction pool by address.
3495
3529
fn get_pool_transactions_nonce (
3496
3530
pool_transactions : & [ Arc < PoolTransaction > ] ,
0 commit comments