1use crate::precompiles::OpPrecompiles;
2use revm::{
3 context::{ContextSetters, Evm, EvmData},
4 context_interface::ContextTr,
5 handler::{
6 instructions::{EthInstructions, InstructionProvider},
7 EvmTr, PrecompileProvider,
8 },
9 inspector::{InspectorEvmTr, JournalExt},
10 interpreter::{interpreter::EthInterpreter, Interpreter, InterpreterAction, InterpreterTypes},
11 Inspector,
12};
13
14pub struct OpEvm<CTX, INSP, I = EthInstructions<EthInterpreter, CTX>, P = OpPrecompiles>(
15 pub Evm<CTX, INSP, I, P>,
16);
17
18impl<CTX: ContextTr, INSP> OpEvm<CTX, INSP, EthInstructions<EthInterpreter, CTX>, OpPrecompiles> {
19 pub fn new(ctx: CTX, inspector: INSP) -> Self {
20 Self(Evm {
21 data: EvmData { ctx, inspector },
22 instruction: EthInstructions::new_mainnet(),
23 precompiles: OpPrecompiles::default(),
24 })
25 }
26}
27
28impl<CTX, INSP, I, P> InspectorEvmTr for OpEvm<CTX, INSP, I, P>
29where
30 CTX: ContextTr<Journal: JournalExt> + ContextSetters,
31 I: InstructionProvider<
32 Context = CTX,
33 InterpreterTypes: InterpreterTypes<Output = InterpreterAction>,
34 >,
35 P: PrecompileProvider<CTX>,
36 INSP: Inspector<CTX, I::InterpreterTypes>,
37{
38 type Inspector = INSP;
39
40 fn inspector(&mut self) -> &mut Self::Inspector {
41 &mut self.0.data.inspector
42 }
43
44 fn ctx_inspector(&mut self) -> (&mut Self::Context, &mut Self::Inspector) {
45 (&mut self.0.data.ctx, &mut self.0.data.inspector)
46 }
47
48 fn run_inspect_interpreter(
49 &mut self,
50 interpreter: &mut Interpreter<
51 <Self::Instructions as InstructionProvider>::InterpreterTypes,
52 >,
53 ) -> <<Self::Instructions as InstructionProvider>::InterpreterTypes as InterpreterTypes>::Output
54 {
55 self.0.run_inspect_interpreter(interpreter)
56 }
57}
58
59impl<CTX, INSP, I, P> EvmTr for OpEvm<CTX, INSP, I, P>
60where
61 CTX: ContextTr,
62 I: InstructionProvider<
63 Context = CTX,
64 InterpreterTypes: InterpreterTypes<Output = InterpreterAction>,
65 >,
66 P: PrecompileProvider<CTX>,
67{
68 type Context = CTX;
69 type Instructions = I;
70 type Precompiles = P;
71
72 fn run_interpreter(
73 &mut self,
74 interpreter: &mut Interpreter<
75 <Self::Instructions as InstructionProvider>::InterpreterTypes,
76 >,
77 ) -> <<Self::Instructions as InstructionProvider>::InterpreterTypes as InterpreterTypes>::Output
78 {
79 let context = &mut self.0.data.ctx;
80 let instructions = &mut self.0.instruction;
81 interpreter.run_plain(instructions.instruction_table(), context)
82 }
83
84 fn ctx(&mut self) -> &mut Self::Context {
85 &mut self.0.data.ctx
86 }
87
88 fn ctx_ref(&self) -> &Self::Context {
89 &self.0.data.ctx
90 }
91
92 fn ctx_instructions(&mut self) -> (&mut Self::Context, &mut Self::Instructions) {
93 (&mut self.0.data.ctx, &mut self.0.instruction)
94 }
95
96 fn ctx_precompiles(&mut self) -> (&mut Self::Context, &mut Self::Precompiles) {
97 (&mut self.0.data.ctx, &mut self.0.precompiles)
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use crate::{
104 precompiles::bn128_pair::GRANITE_MAX_INPUT_SIZE,
105 transaction::deposit::DEPOSIT_TRANSACTION_TYPE, DefaultOp, L1BlockInfo, OpBuilder,
106 OpHaltReason, OpSpecId, OpTransaction,
107 };
108 use revm::{
109 bytecode::opcode,
110 context::{
111 result::{ExecutionResult, OutOfGasError},
112 BlockEnv, CfgEnv, TxEnv,
113 },
114 context_interface::result::HaltReason,
115 database::{BenchmarkDB, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE, BENCH_TARGET},
116 interpreter::gas::{calculate_initial_tx_gas, InitialAndFloorGas},
117 precompile::{bls12_381_const, bls12_381_utils, bn128, secp256r1, u64_to_address},
118 primitives::{Address, Bytes, TxKind, U256},
119 state::Bytecode,
120 Context, ExecuteEvm, Journal,
121 };
122
123 #[test]
124 fn test_deposit_tx() {
125 let ctx = Context::op()
126 .modify_tx_chained(|tx| {
127 tx.enveloped_tx = None;
128 tx.deposit.mint = Some(100);
129 tx.base.tx_type = DEPOSIT_TRANSACTION_TYPE;
130 })
131 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::HOLOCENE);
132
133 let mut evm = ctx.build_op();
134
135 let output = evm.replay().unwrap();
136
137 assert_eq!(
139 output
140 .state
141 .get(&Address::default())
142 .map(|a| a.info.balance),
143 Some(U256::from(100))
144 );
145 }
146
147 #[test]
148 fn test_halted_deposit_tx() {
149 let ctx = Context::op()
150 .modify_tx_chained(|tx| {
151 tx.enveloped_tx = None;
152 tx.deposit.mint = Some(100);
153 tx.base.tx_type = DEPOSIT_TRANSACTION_TYPE;
154 tx.base.caller = BENCH_CALLER;
155 tx.base.kind = TxKind::Call(BENCH_TARGET);
156 })
157 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::HOLOCENE)
158 .with_db(BenchmarkDB::new_bytecode(Bytecode::new_legacy(
159 [opcode::POP].into(),
160 )));
161
162 let mut evm = ctx.build_op();
164
165 let output = evm.replay().unwrap();
166
167 assert_eq!(
169 output.result,
170 ExecutionResult::Halt {
171 reason: OpHaltReason::FailedDeposit,
172 gas_used: 30_000_000
173 }
174 );
175 assert_eq!(
176 output.state.get(&BENCH_CALLER).map(|a| a.info.balance),
177 Some(U256::from(100) + BENCH_CALLER_BALANCE)
178 );
179 }
180
181 fn p256verify_test_tx() -> Context<
182 BlockEnv,
183 OpTransaction<TxEnv>,
184 CfgEnv<OpSpecId>,
185 EmptyDB,
186 Journal<EmptyDB>,
187 L1BlockInfo,
188 > {
189 const SPEC_ID: OpSpecId = OpSpecId::FJORD;
190
191 let InitialAndFloorGas { initial_gas, .. } =
192 calculate_initial_tx_gas(SPEC_ID.into(), &[], false, 0, 0, 0);
193
194 Context::op()
195 .modify_tx_chained(|tx| {
196 tx.base.kind = TxKind::Call(u64_to_address(secp256r1::P256VERIFY_ADDRESS));
197 tx.base.gas_limit = initial_gas + secp256r1::P256VERIFY_BASE_GAS_FEE;
198 })
199 .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID)
200 }
201
202 #[test]
203 fn test_tx_call_p256verify() {
204 let ctx = p256verify_test_tx();
205
206 let mut evm = ctx.build_op();
207 let output = evm.replay().unwrap();
208
209 assert!(output.result.is_success());
211 }
212
213 #[test]
214 fn test_halted_tx_call_p256verify() {
215 let ctx = p256verify_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
216
217 let mut evm = ctx.build_op();
218 let output = evm.replay().unwrap();
219
220 assert!(matches!(
222 output.result,
223 ExecutionResult::Halt {
224 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
225 ..
226 }
227 ));
228 }
229
230 fn bn128_pair_test_tx(
231 spec: OpSpecId,
232 ) -> Context<
233 BlockEnv,
234 OpTransaction<TxEnv>,
235 CfgEnv<OpSpecId>,
236 EmptyDB,
237 Journal<EmptyDB>,
238 L1BlockInfo,
239 > {
240 let input = Bytes::from([1; GRANITE_MAX_INPUT_SIZE + 2]);
241 let InitialAndFloorGas { initial_gas, .. } =
242 calculate_initial_tx_gas(spec.into(), &input[..], false, 0, 0, 0);
243
244 Context::op()
245 .modify_tx_chained(|tx| {
246 tx.base.kind = TxKind::Call(bn128::pair::ADDRESS);
247 tx.base.data = input;
248 tx.base.gas_limit = initial_gas;
249 })
250 .modify_cfg_chained(|cfg| cfg.spec = spec)
251 }
252
253 #[test]
254 fn test_halted_tx_call_bn128_pair_fjord() {
255 let ctx = bn128_pair_test_tx(OpSpecId::FJORD);
256
257 let mut evm = ctx.build_op();
258 let output = evm.replay().unwrap();
259
260 assert!(matches!(
262 output.result,
263 ExecutionResult::Halt {
264 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
265 ..
266 }
267 ));
268 }
269
270 #[test]
271 fn test_halted_tx_call_bn128_pair_granite() {
272 let ctx = bn128_pair_test_tx(OpSpecId::GRANITE);
273
274 let mut evm = ctx.build_op();
275 let output = evm.replay().unwrap();
276
277 assert!(matches!(
279 output.result,
280 ExecutionResult::Halt {
281 reason: OpHaltReason::Base(HaltReason::PrecompileError),
282 ..
283 }
284 ));
285 }
286
287 #[test]
288 fn test_halted_tx_call_bls12_381_g1_add_out_of_gas() {
289 let ctx = Context::op()
290 .modify_tx_chained(|tx| {
291 tx.base.kind = TxKind::Call(bls12_381_const::G1_ADD_ADDRESS);
292 tx.base.gas_limit = 21_000 + bls12_381_const::G1_ADD_BASE_GAS_FEE - 1;
293 })
294 .modify_chain_chained(|l1_block| {
295 l1_block.operator_fee_constant = Some(U256::ZERO);
296 l1_block.operator_fee_scalar = Some(U256::ZERO)
297 })
298 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS);
299
300 let mut evm = ctx.build_op();
301
302 let output = evm.replay().unwrap();
303
304 assert!(matches!(
306 output.result,
307 ExecutionResult::Halt {
308 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
309 ..
310 }
311 ));
312 }
313
314 #[test]
315 fn test_halted_tx_call_bls12_381_g1_add_input_wrong_size() {
316 let ctx = Context::op()
317 .modify_tx_chained(|tx| {
318 tx.base.kind = TxKind::Call(bls12_381_const::G1_ADD_ADDRESS);
319 tx.base.gas_limit = 21_000 + bls12_381_const::G1_ADD_BASE_GAS_FEE;
320 })
321 .modify_chain_chained(|l1_block| {
322 l1_block.operator_fee_constant = Some(U256::ZERO);
323 l1_block.operator_fee_scalar = Some(U256::ZERO)
324 })
325 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS);
326
327 let mut evm = ctx.build_op();
328 let output = evm.replay().unwrap();
329
330 assert!(matches!(
332 output.result,
333 ExecutionResult::Halt {
334 reason: OpHaltReason::Base(HaltReason::PrecompileError),
335 ..
336 }
337 ));
338 }
339
340 fn g1_msm_test_tx() -> Context<
341 BlockEnv,
342 OpTransaction<TxEnv>,
343 CfgEnv<OpSpecId>,
344 EmptyDB,
345 Journal<EmptyDB>,
346 L1BlockInfo,
347 > {
348 const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS;
349
350 let input = Bytes::from([1; bls12_381_const::G1_MSM_INPUT_LENGTH]);
351 let InitialAndFloorGas { initial_gas, .. } =
352 calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0);
353 let gs1_msm_gas = bls12_381_utils::msm_required_gas(
354 1,
355 &bls12_381_const::DISCOUNT_TABLE_G1_MSM,
356 bls12_381_const::G1_MSM_BASE_GAS_FEE,
357 );
358
359 Context::op()
360 .modify_tx_chained(|tx| {
361 tx.base.kind = TxKind::Call(bls12_381_const::G1_MSM_ADDRESS);
362 tx.base.data = input;
363 tx.base.gas_limit = initial_gas + gs1_msm_gas;
364 })
365 .modify_chain_chained(|l1_block| {
366 l1_block.operator_fee_constant = Some(U256::ZERO);
367 l1_block.operator_fee_scalar = Some(U256::ZERO)
368 })
369 .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID)
370 }
371
372 #[test]
373 fn test_halted_tx_call_bls12_381_g1_msm_input_wrong_size() {
374 let ctx = g1_msm_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..));
375
376 let mut evm = ctx.build_op();
377 let output = evm.replay().unwrap();
378
379 assert!(matches!(
381 output.result,
382 ExecutionResult::Halt {
383 reason: OpHaltReason::Base(HaltReason::PrecompileError),
384 ..
385 }
386 ));
387 }
388
389 #[test]
390 fn test_halted_tx_call_bls12_381_g1_msm_out_of_gas() {
391 let ctx = g1_msm_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
392
393 let mut evm = ctx.build_op();
394 let output = evm.replay().unwrap();
395
396 assert!(matches!(
398 output.result,
399 ExecutionResult::Halt {
400 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
401 ..
402 }
403 ));
404 }
405
406 #[test]
407 fn test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout() {
408 let ctx = g1_msm_test_tx();
409
410 let mut evm = ctx.build_op();
411 let output = evm.replay().unwrap();
412
413 assert!(matches!(
415 output.result,
416 ExecutionResult::Halt {
417 reason: OpHaltReason::Base(HaltReason::PrecompileError),
418 ..
419 }
420 ));
421 }
422
423 #[test]
424 fn test_halted_tx_call_bls12_381_g2_add_out_of_gas() {
425 let ctx = Context::op()
426 .modify_tx_chained(|tx| {
427 tx.base.kind = TxKind::Call(bls12_381_const::G2_ADD_ADDRESS);
428 tx.base.gas_limit = 21_000 + bls12_381_const::G2_ADD_BASE_GAS_FEE - 1;
429 })
430 .modify_chain_chained(|l1_block| {
431 l1_block.operator_fee_constant = Some(U256::ZERO);
432 l1_block.operator_fee_scalar = Some(U256::ZERO)
433 })
434 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS);
435
436 let mut evm = ctx.build_op();
437
438 let output = evm.replay().unwrap();
439
440 assert!(matches!(
442 output.result,
443 ExecutionResult::Halt {
444 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
445 ..
446 }
447 ));
448 }
449
450 #[test]
451 fn test_halted_tx_call_bls12_381_g2_add_input_wrong_size() {
452 let ctx = Context::op()
453 .modify_tx_chained(|tx| {
454 tx.base.kind = TxKind::Call(bls12_381_const::G2_ADD_ADDRESS);
455 tx.base.gas_limit = 21_000 + bls12_381_const::G2_ADD_BASE_GAS_FEE;
456 })
457 .modify_chain_chained(|l1_block| {
458 l1_block.operator_fee_constant = Some(U256::ZERO);
459 l1_block.operator_fee_scalar = Some(U256::ZERO)
460 })
461 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS);
462
463 let mut evm = ctx.build_op();
464
465 let output = evm.replay().unwrap();
466
467 assert!(matches!(
469 output.result,
470 ExecutionResult::Halt {
471 reason: OpHaltReason::Base(HaltReason::PrecompileError),
472 ..
473 }
474 ));
475 }
476
477 fn g2_msm_test_tx() -> Context<
478 BlockEnv,
479 OpTransaction<TxEnv>,
480 CfgEnv<OpSpecId>,
481 EmptyDB,
482 Journal<EmptyDB>,
483 L1BlockInfo,
484 > {
485 const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS;
486
487 let input = Bytes::from([1; bls12_381_const::G2_MSM_INPUT_LENGTH]);
488 let InitialAndFloorGas { initial_gas, .. } =
489 calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0);
490 let gs2_msm_gas = bls12_381_utils::msm_required_gas(
491 1,
492 &bls12_381_const::DISCOUNT_TABLE_G2_MSM,
493 bls12_381_const::G2_MSM_BASE_GAS_FEE,
494 );
495
496 Context::op()
497 .modify_tx_chained(|tx| {
498 tx.base.kind = TxKind::Call(bls12_381_const::G2_MSM_ADDRESS);
499 tx.base.data = input;
500 tx.base.gas_limit = initial_gas + gs2_msm_gas;
501 })
502 .modify_chain_chained(|l1_block| {
503 l1_block.operator_fee_constant = Some(U256::ZERO);
504 l1_block.operator_fee_scalar = Some(U256::ZERO)
505 })
506 .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID)
507 }
508
509 #[test]
510 fn test_halted_tx_call_bls12_381_g2_msm_input_wrong_size() {
511 let ctx = g2_msm_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..));
512
513 let mut evm = ctx.build_op();
514 let output = evm.replay().unwrap();
515
516 assert!(matches!(
518 output.result,
519 ExecutionResult::Halt {
520 reason: OpHaltReason::Base(HaltReason::PrecompileError),
521 ..
522 }
523 ));
524 }
525
526 #[test]
527 fn test_halted_tx_call_bls12_381_g2_msm_out_of_gas() {
528 let ctx = g2_msm_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
529
530 let mut evm = ctx.build_op();
531 let output = evm.replay().unwrap();
532
533 assert!(matches!(
535 output.result,
536 ExecutionResult::Halt {
537 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
538 ..
539 }
540 ));
541 }
542
543 #[test]
544 fn test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout() {
545 let ctx = g2_msm_test_tx();
546
547 let mut evm = ctx.build_op();
548 let output = evm.replay().unwrap();
549
550 assert!(matches!(
552 output.result,
553 ExecutionResult::Halt {
554 reason: OpHaltReason::Base(HaltReason::PrecompileError),
555 ..
556 }
557 ));
558 }
559
560 fn bl12_381_pairing_test_tx() -> Context<
561 BlockEnv,
562 OpTransaction<TxEnv>,
563 CfgEnv<OpSpecId>,
564 EmptyDB,
565 Journal<EmptyDB>,
566 L1BlockInfo,
567 > {
568 const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS;
569
570 let input = Bytes::from([1; bls12_381_const::PAIRING_INPUT_LENGTH]);
571 let InitialAndFloorGas { initial_gas, .. } =
572 calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0);
573
574 let pairing_gas: u64 =
575 bls12_381_const::PAIRING_MULTIPLIER_BASE + bls12_381_const::PAIRING_OFFSET_BASE;
576
577 Context::op()
578 .modify_tx_chained(|tx| {
579 tx.base.kind = TxKind::Call(bls12_381_const::PAIRING_ADDRESS);
580 tx.base.data = input;
581 tx.base.gas_limit = initial_gas + pairing_gas;
582 })
583 .modify_chain_chained(|l1_block| {
584 l1_block.operator_fee_constant = Some(U256::ZERO);
585 l1_block.operator_fee_scalar = Some(U256::ZERO)
586 })
587 .modify_cfg_chained(|cfg| cfg.spec = OpSpecId::ISTHMUS)
588 }
589
590 #[test]
591 fn test_halted_tx_call_bls12_381_pairing_input_wrong_size() {
592 let ctx = bl12_381_pairing_test_tx()
593 .modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..));
594
595 let mut evm = ctx.build_op();
596 let output = evm.replay().unwrap();
597
598 assert!(matches!(
600 output.result,
601 ExecutionResult::Halt {
602 reason: OpHaltReason::Base(HaltReason::PrecompileError),
603 ..
604 }
605 ));
606 }
607
608 #[test]
609 fn test_halted_tx_call_bls12_381_pairing_out_of_gas() {
610 let ctx = bl12_381_pairing_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
611
612 let mut evm = ctx.build_op();
613 let output = evm.replay().unwrap();
614
615 assert!(matches!(
617 output.result,
618 ExecutionResult::Halt {
619 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
620 ..
621 }
622 ));
623 }
624
625 #[test]
626 fn test_tx_call_bls12_381_pairing_wrong_input_layout() {
627 let ctx = bl12_381_pairing_test_tx();
628
629 let mut evm = ctx.build_op();
630 let output = evm.replay().unwrap();
631
632 assert!(matches!(
634 output.result,
635 ExecutionResult::Halt {
636 reason: OpHaltReason::Base(HaltReason::PrecompileError),
637 ..
638 }
639 ));
640 }
641
642 fn fp_to_g1_test_tx() -> Context<
643 BlockEnv,
644 OpTransaction<TxEnv>,
645 CfgEnv<OpSpecId>,
646 EmptyDB,
647 Journal<EmptyDB>,
648 L1BlockInfo,
649 > {
650 const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS;
651
652 let input = Bytes::from([1; bls12_381_const::PADDED_FP_LENGTH]);
653 let InitialAndFloorGas { initial_gas, .. } =
654 calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0);
655
656 Context::op()
657 .modify_tx_chained(|tx| {
658 tx.base.kind = TxKind::Call(bls12_381_const::MAP_FP_TO_G1_ADDRESS);
659 tx.base.data = input;
660 tx.base.gas_limit = initial_gas + bls12_381_const::MAP_FP_TO_G1_BASE_GAS_FEE;
661 })
662 .modify_chain_chained(|l1_block| {
663 l1_block.operator_fee_constant = Some(U256::ZERO);
664 l1_block.operator_fee_scalar = Some(U256::ZERO)
665 })
666 .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID)
667 }
668
669 #[test]
670 fn test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas() {
671 let ctx = fp_to_g1_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
672
673 let mut evm = ctx.build_op();
674 let output = evm.replay().unwrap();
675
676 assert!(matches!(
678 output.result,
679 ExecutionResult::Halt {
680 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
681 ..
682 }
683 ));
684 }
685
686 #[test]
687 fn test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size() {
688 let ctx = fp_to_g1_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..));
689
690 let mut evm = ctx.build_op();
691 let output = evm.replay().unwrap();
692
693 assert!(matches!(
695 output.result,
696 ExecutionResult::Halt {
697 reason: OpHaltReason::Base(HaltReason::PrecompileError),
698 ..
699 }
700 ));
701 }
702
703 fn fp2_to_g2_test_tx() -> Context<
704 BlockEnv,
705 OpTransaction<TxEnv>,
706 CfgEnv<OpSpecId>,
707 EmptyDB,
708 Journal<EmptyDB>,
709 L1BlockInfo,
710 > {
711 const SPEC_ID: OpSpecId = OpSpecId::ISTHMUS;
712
713 let input = Bytes::from([1; bls12_381_const::PADDED_FP2_LENGTH]);
714 let InitialAndFloorGas { initial_gas, .. } =
715 calculate_initial_tx_gas(SPEC_ID.into(), &input[..], false, 0, 0, 0);
716
717 Context::op()
718 .modify_tx_chained(|tx| {
719 tx.base.kind = TxKind::Call(bls12_381_const::MAP_FP2_TO_G2_ADDRESS);
720 tx.base.data = input;
721 tx.base.gas_limit = initial_gas + bls12_381_const::MAP_FP2_TO_G2_BASE_GAS_FEE;
722 })
723 .modify_chain_chained(|l1_block| {
724 l1_block.operator_fee_constant = Some(U256::ZERO);
725 l1_block.operator_fee_scalar = Some(U256::ZERO)
726 })
727 .modify_cfg_chained(|cfg| cfg.spec = SPEC_ID)
728 }
729
730 #[test]
731 fn test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas() {
732 let ctx = fp2_to_g2_test_tx().modify_tx_chained(|tx| tx.base.gas_limit -= 1);
733
734 let mut evm = ctx.build_op();
735 let output = evm.replay().unwrap();
736
737 assert!(matches!(
739 output.result,
740 ExecutionResult::Halt {
741 reason: OpHaltReason::Base(HaltReason::OutOfGas(OutOfGasError::Precompile)),
742 ..
743 }
744 ));
745 }
746
747 #[test]
748 fn test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size() {
749 let ctx =
750 fp2_to_g2_test_tx().modify_tx_chained(|tx| tx.base.data = tx.base.data.slice(1..));
751
752 let mut evm = ctx.build_op();
753 let output = evm.replay().unwrap();
754
755 assert!(matches!(
757 output.result,
758 ExecutionResult::Halt {
759 reason: OpHaltReason::Base(HaltReason::PrecompileError),
760 ..
761 }
762 ));
763 }
764}