1
1
use alloy_primitives:: { Address , U256 } ;
2
2
use alloy_sol_types:: SolValue ;
3
3
use foundry_evm_core:: {
4
- backend:: DatabaseExt ,
4
+ backend:: DatabaseError ,
5
5
constants:: { CHEATCODE_ADDRESS , HARDHAT_CONSOLE_ADDRESS } ,
6
6
} ;
7
7
use revm:: {
8
+ bytecode:: opcode:: { EXTCODESIZE , REVERT } ,
9
+ context:: { Cfg , ContextTr , JournalTr } ,
10
+ inspector:: JournalExt ,
8
11
interpreter:: {
9
- opcode:: { EXTCODESIZE , REVERT } ,
10
- CallInputs , CallOutcome , CallScheme , InstructionResult , Interpreter , InterpreterAction ,
11
- InterpreterResult ,
12
+ interpreter:: EthInterpreter , interpreter_types:: Jumps , CallInputs , CallOutcome , CallScheme ,
13
+ InstructionResult , Interpreter , InterpreterAction , InterpreterResult ,
12
14
} ,
13
15
precompile:: { PrecompileSpecId , Precompiles } ,
14
- primitives:: SpecId ,
15
- Database , EvmContext , Inspector ,
16
+ primitives:: hardfork :: SpecId ,
17
+ Database , Inspector ,
16
18
} ;
17
19
use std:: fmt;
18
20
@@ -62,9 +64,9 @@ impl fmt::Display for DetailedRevertReason {
62
64
#[ derive( Clone , Debug , Default ) ]
63
65
pub struct RevertDiagnostic {
64
66
/// Tracks calls with calldata that target an address without executable code.
65
- pub non_contract_call : Option < ( Address , CallScheme , u64 ) > ,
67
+ pub non_contract_call : Option < ( Address , CallScheme , usize ) > ,
66
68
/// Tracks EXTCODESIZE checks that target an address without executable code.
67
- pub non_contract_size_check : Option < ( Address , u64 ) > ,
69
+ pub non_contract_size_check : Option < ( Address , usize ) > ,
68
70
/// Whether the step opcode is EXTCODESIZE or not.
69
71
pub is_extcodesize_step : bool ,
70
72
}
@@ -109,31 +111,36 @@ impl RevertDiagnostic {
109
111
/// Injects the revert diagnostic into the debug traces. Should only be called after a revert.
110
112
fn handle_revert_diagnostic ( & self , interp : & mut Interpreter ) {
111
113
if let Some ( reason) = self . reason ( ) {
112
- interp. instruction_result = InstructionResult :: Revert ;
113
- interp. next_action = InterpreterAction :: Return {
114
+ interp. control . instruction_result = InstructionResult :: Revert ;
115
+ interp. control . next_action = InterpreterAction :: Return {
114
116
result : InterpreterResult {
115
117
output : reason. to_string ( ) . abi_encode ( ) . into ( ) ,
116
- gas : interp. gas ,
118
+ gas : interp. control . gas ,
117
119
result : InstructionResult :: Revert ,
118
120
} ,
119
121
} ;
120
122
}
121
123
}
122
124
}
123
125
124
- impl < DB : Database + DatabaseExt > Inspector < DB > for RevertDiagnostic {
126
+ impl < CTX , D > Inspector < CTX , EthInterpreter > for RevertDiagnostic
127
+ where
128
+ D : Database < Error = DatabaseError > ,
129
+ CTX : ContextTr < Db = D > ,
130
+ CTX :: Journal : JournalExt ,
131
+ {
125
132
/// Tracks the first call with non-zero calldata that targets a non-contract address. Excludes
126
133
/// precompiles and test addresses.
127
- fn call ( & mut self , ctx : & mut EvmContext < DB > , inputs : & mut CallInputs ) -> Option < CallOutcome > {
134
+ fn call ( & mut self , ctx : & mut CTX , inputs : & mut CallInputs ) -> Option < CallOutcome > {
128
135
let target = self . code_target_address ( inputs) ;
129
136
130
- if IGNORE . contains ( & target) || self . is_precompile ( ctx. spec_id ( ) , target) {
137
+ if IGNORE . contains ( & target) || self . is_precompile ( ctx. cfg ( ) . spec ( ) . into ( ) , target) {
131
138
return None ;
132
139
}
133
140
134
- if let Ok ( state) = ctx. code ( target) {
141
+ if let Ok ( state) = ctx. journal ( ) . code ( target) {
135
142
if state. is_empty ( ) && !inputs. input . is_empty ( ) {
136
- self . non_contract_call = Some ( ( target, inputs. scheme , ctx. journaled_state . depth ( ) ) ) ;
143
+ self . non_contract_call = Some ( ( target, inputs. scheme , ctx. journal ( ) . depth ( ) ) ) ;
137
144
}
138
145
}
139
146
None
@@ -150,14 +157,14 @@ impl<DB: Database + DatabaseExt> Inspector<DB> for RevertDiagnostic {
150
157
/// When an `EXTCODESIZE` opcode occurs:
151
158
/// - Optimistically caches the target address and current depth in `non_contract_size_check`,
152
159
/// pending later validation.
153
- fn step ( & mut self , interp : & mut Interpreter , ctx : & mut EvmContext < DB > ) {
160
+ fn step ( & mut self , interp : & mut Interpreter , ctx : & mut CTX ) {
154
161
// REVERT (offset, size)
155
- if REVERT == interp. current_opcode ( ) {
156
- if let Ok ( size) = interp. stack ( ) . peek ( 1 ) {
162
+ if REVERT == interp. bytecode . opcode ( ) {
163
+ if let Ok ( size) = interp. stack . peek ( 1 ) {
157
164
if size == U256 :: ZERO {
158
165
// Check empty revert with same depth as a non-contract call
159
166
if let Some ( ( _, _, depth) ) = self . non_contract_call {
160
- if ctx. journaled_state . depth ( ) == depth {
167
+ if ctx. journal ( ) . depth ( ) == depth {
161
168
self . handle_revert_diagnostic ( interp) ;
162
169
} else {
163
170
self . non_contract_call = None ;
@@ -167,7 +174,7 @@ impl<DB: Database + DatabaseExt> Inspector<DB> for RevertDiagnostic {
167
174
168
175
// Check empty revert with same depth as a non-contract size check
169
176
if let Some ( ( _, depth) ) = self . non_contract_size_check {
170
- if depth == ctx. journaled_state . depth ( ) {
177
+ if depth == ctx. journal ( ) . depth ( ) {
171
178
self . handle_revert_diagnostic ( interp) ;
172
179
} else {
173
180
self . non_contract_size_check = None ;
@@ -177,24 +184,24 @@ impl<DB: Database + DatabaseExt> Inspector<DB> for RevertDiagnostic {
177
184
}
178
185
}
179
186
// EXTCODESIZE (address)
180
- else if EXTCODESIZE == interp. current_opcode ( ) {
181
- if let Ok ( word) = interp. stack ( ) . peek ( 0 ) {
187
+ else if EXTCODESIZE == interp. bytecode . opcode ( ) {
188
+ if let Ok ( word) = interp. stack . peek ( 0 ) {
182
189
let addr = Address :: from_word ( word. into ( ) ) ;
183
- if IGNORE . contains ( & addr) || self . is_precompile ( ctx. spec_id ( ) , addr) {
190
+ if IGNORE . contains ( & addr) || self . is_precompile ( ctx. cfg ( ) . spec ( ) . into ( ) , addr) {
184
191
return ;
185
192
}
186
193
187
194
// Optimistically cache --> validated and cleared (if necessary) at `fn step_end()`
188
- self . non_contract_size_check = Some ( ( addr, ctx. journaled_state . depth ( ) ) ) ;
195
+ self . non_contract_size_check = Some ( ( addr, ctx. journal ( ) . depth ( ) ) ) ;
189
196
self . is_extcodesize_step = true ;
190
197
}
191
198
}
192
199
}
193
200
194
201
/// Tracks `EXTCODESIZE` output. If the bytecode size is 0, clears the cache.
195
- fn step_end ( & mut self , interp : & mut Interpreter , _ctx : & mut EvmContext < DB > ) {
202
+ fn step_end ( & mut self , interp : & mut Interpreter , _ctx : & mut CTX ) {
196
203
if self . is_extcodesize_step {
197
- if let Ok ( size) = interp. stack ( ) . peek ( 0 ) {
204
+ if let Ok ( size) = interp. stack . peek ( 0 ) {
198
205
if size != U256 :: ZERO {
199
206
self . non_contract_size_check = None ;
200
207
}
0 commit comments