@@ -61,33 +61,48 @@ impl<E: ExecutionProvider<OpStack>> OpStackEvm<E> {
6161 let mut db = ProofDB :: new ( self . block_id , self . execution . clone ( ) ) ;
6262 _ = db. state . prefetch_state ( tx, validate_tx) . await ;
6363
64- // Pre-fetch all required state
65- loop {
66- if !db. state . needs_update ( ) {
67- break ;
64+ // Iterative execution with state fetching
65+ let mut iteration = 0 ;
66+ const MAX_ITERATIONS : u32 = 50 ; // Prevent infinite loops
67+
68+ let tx_res = loop {
69+ iteration += 1 ;
70+ if iteration > MAX_ITERATIONS {
71+ return Err ( EvmError :: Generic (
72+ "Maximum iterations reached while fetching state" . to_string ( ) ,
73+ ) ) ;
74+ }
75+
76+ // Update state first if needed
77+ if db. state . needs_update ( ) {
78+ debug ! (
79+ "evm cache miss (iteration {}): {:?}" ,
80+ iteration,
81+ db. state. access. as_ref( ) . unwrap( )
82+ ) ;
83+ db. state
84+ . update_state ( )
85+ . await
86+ . map_err ( |e| EvmError :: Generic ( e. to_string ( ) ) ) ?;
6887 }
69- debug ! ( "evm cache miss: {:?}" , db. state. access. as_ref( ) . unwrap( ) ) ;
70- db. state
71- . update_state ( )
72- . await
73- . map_err ( |e| EvmError :: Generic ( e. to_string ( ) ) ) ?;
74- }
7588
76- // Now execute synchronously with all state loaded
77- let context = self . get_context ( tx, self . block_id , validate_tx) . await ?;
89+ // Create EVM after any async operations
90+ let context = self . get_context ( tx, self . block_id , validate_tx) . await ?;
7891
79- // Execute in a scope to ensure EVM is dropped before any async operations
80- let ( result, accounts) = {
81- let mut evm = context. with_db ( db) . build_op ( ) ;
82- let res = evm. replay ( ) ;
83- let db = evm. 0 . db_mut ( ) ;
84- let accounts = mem:: take ( & mut db. state . accounts ) ;
85- ( res, accounts)
92+ // Execute in a scope to ensure EVM is dropped before any potential async operations
93+ let ( result, needs_update) = {
94+ let mut evm = context. with_db ( & mut db) . build_op ( ) ;
95+ let res = evm. replay ( ) ;
96+ let needs_update = evm. 0 . db_mut ( ) . state . needs_update ( ) ;
97+ ( res, needs_update)
98+ } ;
99+
100+ if result. is_ok ( ) || !needs_update {
101+ break result. map ( |res| ( res. result , mem:: take ( & mut db. state . accounts ) ) ) ;
102+ }
86103 } ;
87104
88- result
89- . map ( |r| ( r. result , accounts) )
90- . map_err ( |err| EvmError :: Generic ( format ! ( "generic: {err}" ) ) )
105+ tx_res. map_err ( |err| EvmError :: Generic ( format ! ( "generic: {err}" ) ) )
91106 }
92107
93108 async fn get_context (
0 commit comments