@@ -32,24 +32,37 @@ pub fn inject_precompiles<DB, I>(
32
32
33
33
#[ cfg( test) ]
34
34
mod tests {
35
+ use std:: convert:: Infallible ;
36
+
35
37
use alloy_evm:: { eth:: EthEvmContext , precompiles:: PrecompilesMap , EthEvm , Evm , EvmEnv } ;
36
38
use alloy_op_evm:: OpEvm ;
37
39
use alloy_primitives:: { address, Address , Bytes , TxKind } ;
38
40
use foundry_evm_core:: either_evm:: EitherEvm ;
39
41
use itertools:: Itertools ;
40
- use op_revm:: { precompiles:: OpPrecompiles , L1BlockInfo , OpContext , OpTransaction } ;
42
+ use op_revm:: { precompiles:: OpPrecompiles , L1BlockInfo , OpContext , OpSpecId , OpTransaction } ;
41
43
use revm:: {
42
- context:: { Evm as RevmEvm , JournalTr , LocalContext , TxEnv } ,
43
- database:: EmptyDB ,
44
+ context:: { CfgEnv , Evm as RevmEvm , JournalTr , LocalContext , TxEnv } ,
45
+ database:: { EmptyDB , EmptyDBTyped } ,
44
46
handler:: { instructions:: EthInstructions , EthPrecompiles } ,
45
47
inspector:: NoOpInspector ,
46
48
interpreter:: interpreter:: EthInterpreter ,
47
- precompile:: { PrecompileOutput , PrecompileResult , PrecompileWithAddress } ,
49
+ precompile:: {
50
+ PrecompileOutput , PrecompileResult , PrecompileSpecId , PrecompileWithAddress ,
51
+ Precompiles ,
52
+ } ,
53
+ primitives:: hardfork:: SpecId ,
48
54
Journal ,
49
55
} ;
50
56
51
57
use crate :: { inject_precompiles, PrecompileFactory } ;
52
58
59
+ // A precompile activated in the `Prague` spec.
60
+ const ETH_PRAGUE_PRECOMPILE : Address = address ! ( "0x0000000000000000000000000000000000000011" ) ;
61
+
62
+ // A precompile activated in the `Fjord` spec.
63
+ const OP_FROJD_PRECOMPILE : Address = address ! ( "0x0000000000000000000000000000000000000100" ) ;
64
+
65
+ // A custom precompile address and payload for testing.
53
66
const PRECOMPILE_ADDR : Address = address ! ( "0x0000000000000000000000000000000000000071" ) ;
54
67
const PAYLOAD : & [ u8 ] = & [ 0xde , 0xad , 0xbe , 0xef ] ;
55
68
@@ -71,10 +84,13 @@ mod tests {
71
84
Ok ( PrecompileOutput { bytes : Bytes :: copy_from_slice ( input) , gas_used : 0 } )
72
85
}
73
86
74
- #[ test]
75
- fn build_eth_evm_with_extra_precompiles ( ) {
87
+ /// Creates a new EVM instance with the custom precompile factory.
88
+ fn create_eth_evm (
89
+ spec : SpecId ,
90
+ ) -> ( foundry_evm:: Env , EitherEvm < EmptyDBTyped < Infallible > , NoOpInspector , PrecompilesMap > )
91
+ {
76
92
let eth_env = foundry_evm:: Env {
77
- evm_env : EvmEnv { block_env : Default :: default ( ) , cfg_env : Default :: default ( ) } ,
93
+ evm_env : EvmEnv { block_env : Default :: default ( ) , cfg_env : CfgEnv :: new_with_spec ( spec ) } ,
78
94
tx : TxEnv {
79
95
kind : TxKind :: Call ( PRECOMPILE_ADDR ) ,
80
96
data : PAYLOAD . into ( ) ,
@@ -92,35 +108,34 @@ mod tests {
92
108
error : Ok ( ( ) ) ,
93
109
} ;
94
110
95
- let mut evm = EitherEvm :: Eth ( EthEvm :: new (
111
+ let eth_precompiles = EthPrecompiles {
112
+ precompiles : Precompiles :: new ( PrecompileSpecId :: from_spec_id ( spec) ) ,
113
+ spec,
114
+ }
115
+ . precompiles ;
116
+ let eth_evm = EitherEvm :: Eth ( EthEvm :: new (
96
117
RevmEvm :: new_with_inspector (
97
118
eth_evm_context,
98
119
NoOpInspector ,
99
120
EthInstructions :: < EthInterpreter , EthEvmContext < EmptyDB > > :: default ( ) ,
100
- PrecompilesMap :: from_static ( EthPrecompiles :: default ( ) . precompiles ) ,
121
+ PrecompilesMap :: from_static ( eth_precompiles ) ,
101
122
) ,
102
123
true ,
103
124
) ) ;
104
125
105
- assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
106
-
107
- inject_precompiles ( & mut evm, CustomPrecompileFactory . precompiles ( ) ) ;
108
-
109
- assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
110
-
111
- let result = match & mut evm {
112
- EitherEvm :: Eth ( eth_evm) => eth_evm. transact ( eth_env. tx ) . unwrap ( ) ,
113
- _ => unreachable ! ( ) ,
114
- } ;
115
-
116
- assert ! ( result. result. is_success( ) ) ;
117
- assert_eq ! ( result. result. output( ) , Some ( & PAYLOAD . into( ) ) ) ;
126
+ ( eth_env, eth_evm)
118
127
}
119
128
120
- #[ test]
121
- fn build_op_evm_with_extra_precompiles ( ) {
129
+ /// Creates a new OP EVM instance with the custom precompile factory.
130
+ fn create_op_evm (
131
+ spec : SpecId ,
132
+ op_spec : OpSpecId ,
133
+ ) -> (
134
+ crate :: eth:: backend:: env:: Env ,
135
+ EitherEvm < EmptyDBTyped < Infallible > , NoOpInspector , PrecompilesMap > ,
136
+ ) {
122
137
let op_env = crate :: eth:: backend:: env:: Env {
123
- evm_env : EvmEnv { block_env : Default :: default ( ) , cfg_env : Default :: default ( ) } ,
138
+ evm_env : EvmEnv { block_env : Default :: default ( ) , cfg_env : CfgEnv :: new_with_spec ( spec ) } ,
124
139
tx : OpTransaction :: < TxEnv > {
125
140
base : TxEnv {
126
141
kind : TxKind :: Call ( PRECOMPILE_ADDR ) ,
@@ -132,6 +147,7 @@ mod tests {
132
147
is_optimism : true ,
133
148
} ;
134
149
150
+ let op_cfg = op_env. evm_env . cfg_env . clone ( ) . with_spec ( op_spec) ;
135
151
let op_evm_context = OpContext {
136
152
journaled_state : {
137
153
let mut journal = Journal :: new ( EmptyDB :: default ( ) ) ;
@@ -140,31 +156,119 @@ mod tests {
140
156
journal
141
157
} ,
142
158
block : op_env. evm_env . block_env . clone ( ) ,
143
- cfg : op_env . evm_env . cfg_env . clone ( ) . with_spec ( op_revm :: OpSpecId :: BEDROCK ) ,
159
+ cfg : op_cfg . clone ( ) ,
144
160
tx : op_env. tx . clone ( ) ,
145
161
chain : L1BlockInfo :: default ( ) ,
146
162
local : LocalContext :: default ( ) ,
147
163
error : Ok ( ( ) ) ,
148
164
} ;
149
165
150
- let mut evm = EitherEvm :: Op ( OpEvm :: new (
166
+ let op_precompiles = OpPrecompiles :: new_with_spec ( op_cfg. spec ) . precompiles ( ) ;
167
+ let op_evm = EitherEvm :: Op ( OpEvm :: new (
151
168
op_revm:: OpEvm ( RevmEvm :: new_with_inspector (
152
169
op_evm_context,
153
170
NoOpInspector ,
154
171
EthInstructions :: < EthInterpreter , OpContext < EmptyDB > > :: default ( ) ,
155
- PrecompilesMap :: from_static ( OpPrecompiles :: default ( ) . precompiles ( ) ) ,
172
+ PrecompilesMap :: from_static ( op_precompiles ) ,
156
173
) ) ,
157
174
true ,
158
175
) ) ;
159
176
177
+ ( op_env, op_evm)
178
+ }
179
+
180
+ #[ test]
181
+ fn build_eth_evm_with_extra_precompiles_default_spec ( ) {
182
+ let ( env, mut evm) = create_eth_evm ( SpecId :: default ( ) ) ;
183
+
184
+ // Check that the Prague precompile IS present when using the default spec.
185
+ assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & ETH_PRAGUE_PRECOMPILE ) ) ;
186
+
187
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
188
+
189
+ inject_precompiles ( & mut evm, CustomPrecompileFactory . precompiles ( ) ) ;
190
+
191
+ assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
192
+
193
+ let result = match & mut evm {
194
+ EitherEvm :: Eth ( eth_evm) => eth_evm. transact ( env. tx ) . unwrap ( ) ,
195
+ _ => unreachable ! ( ) ,
196
+ } ;
197
+
198
+ assert ! ( result. result. is_success( ) ) ;
199
+ assert_eq ! ( result. result. output( ) , Some ( & PAYLOAD . into( ) ) ) ;
200
+ }
201
+
202
+ #[ test]
203
+ fn build_eth_evm_with_extra_precompiles_london_spec ( ) {
204
+ let ( env, mut evm) = create_eth_evm ( SpecId :: LONDON ) ;
205
+
206
+ // Check that the Prague precompile IS NOT present when using the London spec.
207
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & ETH_PRAGUE_PRECOMPILE ) ) ;
208
+
209
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
210
+
211
+ inject_precompiles ( & mut evm, CustomPrecompileFactory . precompiles ( ) ) ;
212
+
213
+ assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
214
+
215
+ let result = match & mut evm {
216
+ EitherEvm :: Eth ( eth_evm) => eth_evm. transact ( env. tx ) . unwrap ( ) ,
217
+ _ => unreachable ! ( ) ,
218
+ } ;
219
+
220
+ assert ! ( result. result. is_success( ) ) ;
221
+ assert_eq ! ( result. result. output( ) , Some ( & PAYLOAD . into( ) ) ) ;
222
+ }
223
+
224
+ #[ test]
225
+ fn build_op_evm_with_extra_precompiles_default_spec ( ) {
226
+ let ( env, mut evm) = create_op_evm (
227
+ SpecId :: default ( ) ,
228
+ // TODO: OpSpecId::ISTHMUS is not yet supported, fails with: `Missing operator fee
229
+ // scalar for isthmus L1 Block`.
230
+ OpSpecId :: HOLOCENE ,
231
+ ) ;
232
+
233
+ // Check that the Fjord precompile IS present when using the default spec.
234
+ assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & OP_FROJD_PRECOMPILE ) ) ;
235
+
236
+ // Check that the Prague precompile is NOT present when using the default spec.
237
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & ETH_PRAGUE_PRECOMPILE ) ) ;
238
+
239
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
240
+
241
+ inject_precompiles ( & mut evm, CustomPrecompileFactory . precompiles ( ) ) ;
242
+
243
+ assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
244
+
245
+ let result = match & mut evm {
246
+ EitherEvm :: Op ( op_evm) => op_evm. transact ( env. tx ) . unwrap ( ) ,
247
+ _ => unreachable ! ( ) ,
248
+ } ;
249
+
250
+ assert ! ( result. result. is_success( ) ) ;
251
+ assert_eq ! ( result. result. output( ) , Some ( & PAYLOAD . into( ) ) ) ;
252
+ }
253
+
254
+ #[ test]
255
+ fn build_op_evm_with_extra_precompiles_bedrock_spec ( ) {
256
+ let ( env, mut evm) = create_op_evm ( SpecId :: default ( ) , OpSpecId :: BEDROCK ) ;
257
+
258
+ // Check that the Fjord precompile IS NOT present when using the `OpSpecId::BEDROCK` spec.
259
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & OP_FROJD_PRECOMPILE ) ) ;
260
+
261
+ // Check that the Prague precompile IS NOT present when using the `OpSpecId::BEDROCK` spec.
262
+ assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & ETH_PRAGUE_PRECOMPILE ) ) ;
263
+
160
264
assert ! ( !evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
161
265
162
266
inject_precompiles ( & mut evm, CustomPrecompileFactory . precompiles ( ) ) ;
163
267
164
268
assert ! ( evm. precompiles_mut( ) . addresses( ) . contains( & PRECOMPILE_ADDR ) ) ;
165
269
166
270
let result = match & mut evm {
167
- EitherEvm :: Op ( op_evm) => op_evm. transact ( op_env . tx ) . unwrap ( ) ,
271
+ EitherEvm :: Op ( op_evm) => op_evm. transact ( env . tx ) . unwrap ( ) ,
168
272
_ => unreachable ! ( ) ,
169
273
} ;
170
274
0 commit comments