@@ -5,7 +5,7 @@ use foundry_evm_core::{
55 constants:: { CHEATCODE_ADDRESS , HARDHAT_CONSOLE_ADDRESS } ,
66} ;
77use revm:: {
8- bytecode:: opcode:: { EXTCODESIZE , REVERT } ,
8+ bytecode:: opcode,
99 context:: { ContextTr , JournalTr } ,
1010 inspector:: JournalExt ,
1111 interpreter:: {
@@ -101,7 +101,7 @@ impl RevertDiagnostic {
101101 }
102102
103103 /// Injects the revert diagnostic into the debug traces. Should only be called after a revert.
104- fn handle_revert_diagnostic ( & self , interp : & mut Interpreter ) {
104+ fn broadcast_diagnostic ( & self , interp : & mut Interpreter ) {
105105 if let Some ( reason) = self . reason ( ) {
106106 interp. control . instruction_result = InstructionResult :: Revert ;
107107 interp. control . next_action = InterpreterAction :: Return {
@@ -113,6 +113,79 @@ impl RevertDiagnostic {
113113 } ;
114114 }
115115 }
116+
117+ /// When a `REVERT` opcode with zero data size occurs:
118+ /// - if `non_contract_call` was set at the current depth, `broadcast_diagnostic` is called.
119+ /// Otherwise, it is cleared.
120+ /// - if `non_contract_size_check` was set at the current depth, `broadcast_diagnostic` is
121+ /// called. Otherwise, it is cleared.
122+ #[ cold]
123+ fn handle_revert < CTX , D > ( & mut self , interp : & mut Interpreter , ctx : & mut CTX )
124+ where
125+ D : Database < Error = DatabaseError > ,
126+ CTX : ContextTr < Db = D > ,
127+ CTX :: Journal : JournalExt ,
128+ {
129+ // REVERT (offset, size)
130+ if let Ok ( size) = interp. stack . peek ( 1 ) {
131+ if size. is_zero ( ) {
132+ // Check empty revert with same depth as a non-contract call
133+ if let Some ( ( _, _, depth) ) = self . non_contract_call {
134+ if ctx. journal_ref ( ) . depth ( ) == depth {
135+ self . broadcast_diagnostic ( interp) ;
136+ } else {
137+ self . non_contract_call = None ;
138+ }
139+ return ;
140+ }
141+
142+ // Check empty revert with same depth as a non-contract size check
143+ if let Some ( ( _, depth) ) = self . non_contract_size_check {
144+ if depth == ctx. journal_ref ( ) . depth ( ) {
145+ self . broadcast_diagnostic ( interp) ;
146+ } else {
147+ self . non_contract_size_check = None ;
148+ }
149+ }
150+ }
151+ }
152+ }
153+
154+ /// When an `EXTCODESIZE` opcode occurs:
155+ /// - Optimistically caches the target address and current depth in `non_contract_size_check`,
156+ /// pending later validation.
157+ #[ cold]
158+ fn handle_extcodesize < CTX , D > ( & mut self , interp : & mut Interpreter , ctx : & mut CTX )
159+ where
160+ D : Database < Error = DatabaseError > ,
161+ CTX : ContextTr < Db = D > ,
162+ CTX :: Journal : JournalExt ,
163+ {
164+ // EXTCODESIZE (address)
165+ if let Ok ( word) = interp. stack . peek ( 0 ) {
166+ let addr = Address :: from_word ( word. into ( ) ) ;
167+ if IGNORE . contains ( & addr) || ctx. journal_ref ( ) . precompile_addresses ( ) . contains ( & addr) {
168+ return ;
169+ }
170+
171+ // Optimistically cache --> validated and cleared (if necessary) at `fn
172+ // step_end()`
173+ self . non_contract_size_check = Some ( ( addr, ctx. journal_ref ( ) . depth ( ) ) ) ;
174+ self . is_extcodesize_step = true ;
175+ }
176+ }
177+
178+ /// Tracks `EXTCODESIZE` output. If the bytecode size is NOT 0, clears the cache.
179+ #[ cold]
180+ fn handle_extcodesize_output ( & mut self , interp : & mut Interpreter ) {
181+ if let Ok ( size) = interp. stack . peek ( 0 ) {
182+ if size != U256 :: ZERO {
183+ self . non_contract_size_check = None ;
184+ }
185+ }
186+
187+ self . is_extcodesize_step = false ;
188+ }
116189}
117190
118191impl < CTX , D > Inspector < CTX , EthInterpreter > for RevertDiagnostic
@@ -139,69 +212,17 @@ where
139212 }
140213
141214 /// Handles `REVERT` and `EXTCODESIZE` opcodes for diagnostics.
142- ///
143- /// When a `REVERT` opcode with zero data size occurs:
144- /// - if `non_contract_call` was set at the current depth, `handle_revert_diagnostic` is
145- /// called. Otherwise, it is cleared.
146- /// - if `non_contract_call` was set at the current depth, `handle_revert_diagnostic` is
147- /// called. Otherwise, it is cleared.
148- ///
149- /// When an `EXTCODESIZE` opcode occurs:
150- /// - Optimistically caches the target address and current depth in `non_contract_size_check`,
151- /// pending later validation.
152215 fn step ( & mut self , interp : & mut Interpreter , ctx : & mut CTX ) {
153- // REVERT (offset, size)
154- if REVERT == interp. bytecode . opcode ( ) {
155- if let Ok ( size) = interp. stack . peek ( 1 ) {
156- if size. is_zero ( ) {
157- // Check empty revert with same depth as a non-contract call
158- if let Some ( ( _, _, depth) ) = self . non_contract_call {
159- if ctx. journal_ref ( ) . depth ( ) == depth {
160- self . handle_revert_diagnostic ( interp) ;
161- } else {
162- self . non_contract_call = None ;
163- }
164- return ;
165- }
166-
167- // Check empty revert with same depth as a non-contract size check
168- if let Some ( ( _, depth) ) = self . non_contract_size_check {
169- if depth == ctx. journal_ref ( ) . depth ( ) {
170- self . handle_revert_diagnostic ( interp) ;
171- } else {
172- self . non_contract_size_check = None ;
173- }
174- }
175- }
176- }
177- }
178- // EXTCODESIZE (address)
179- else if EXTCODESIZE == interp. bytecode . opcode ( ) {
180- if let Ok ( word) = interp. stack . peek ( 0 ) {
181- let addr = Address :: from_word ( word. into ( ) ) ;
182- if IGNORE . contains ( & addr) ||
183- ctx. journal_ref ( ) . precompile_addresses ( ) . contains ( & addr)
184- {
185- return ;
186- }
187-
188- // Optimistically cache --> validated and cleared (if necessary) at `fn step_end()`
189- self . non_contract_size_check = Some ( ( addr, ctx. journal_ref ( ) . depth ( ) ) ) ;
190- self . is_extcodesize_step = true ;
191- }
216+ match interp. bytecode . opcode ( ) {
217+ opcode:: REVERT => self . handle_revert ( interp, ctx) ,
218+ opcode:: EXTCODESIZE => self . handle_extcodesize ( interp, ctx) ,
219+ _ => { }
192220 }
193221 }
194222
195- /// Tracks `EXTCODESIZE` output. If the bytecode size is 0, clears the cache.
196223 fn step_end ( & mut self , interp : & mut Interpreter , _ctx : & mut CTX ) {
197224 if self . is_extcodesize_step {
198- if let Ok ( size) = interp. stack . peek ( 0 ) {
199- if size != U256 :: ZERO {
200- self . non_contract_size_check = None ;
201- }
202- }
203-
204- self . is_extcodesize_step = false ;
225+ self . handle_extcodesize_output ( interp) ;
205226 }
206227 }
207228}
0 commit comments