1#![cfg_attr(not(feature = "std"), no_std)]
2use aurora_engine_modexp::ModExpAlgorithm;
3use aurora_engine_sdk::env::Env;
4use aurora_engine_sdk::io::IO;
5use aurora_engine_sdk::promise::ReadOnlyPromiseHandler;
6use aurora_engine_types::{BTreeMap, BTreeSet, Box, account_id::AccountId, types::Address, vec};
7use aurora_evm::backend::Log;
8use aurora_evm::executor::{
9 self,
10 stack::{PrecompileFailure, PrecompileHandle},
11};
12
13pub use aurora_engine_types::types::EthGas;
14pub use aurora_evm::{Context, ExitError, ExitFatal, ExitSucceed};
15
16use crate::account_ids::{CurrentAccount, PredecessorAccount, predecessor_account};
17use crate::alt_bn256::{Bn256Add, Bn256Mul, Bn256Pair};
18use crate::blake2::Blake2F;
19use crate::hash::{RIPEMD160, SHA256};
20use crate::identity::Identity;
21use crate::modexp::ModExp;
22use crate::native::{ExitToEthereum, ExitToNear, exit_to_ethereum, exit_to_near};
23use crate::prelude::{H256, Vec};
24use crate::prepaid_gas::PrepaidGas;
25use crate::promise_result::PromiseResult;
26use crate::random::RandomSeed;
27use crate::secp256k1::ECRecover;
28use crate::secp256r1::Secp256r1;
29use crate::xcc::{CrossContractCall, cross_contract_call};
30
31pub mod account_ids;
32pub mod alt_bn256;
33pub mod blake2;
34pub mod bls12_381;
35pub mod hash;
36pub mod identity;
37pub mod modexp;
38pub mod native;
39mod prelude;
40pub mod prepaid_gas;
41pub mod promise_result;
42pub mod random;
43pub mod secp256k1;
44pub mod secp256r1;
45mod utils;
46pub mod xcc;
47
48#[derive(Debug, Default, PartialEq, Eq)]
49pub struct PrecompileOutput {
50 pub cost: EthGas,
51 pub output: Vec<u8>,
52 pub logs: Vec<Log>,
53}
54
55impl PrecompileOutput {
56 #[must_use]
57 pub const fn without_logs(cost: EthGas, output: Vec<u8>) -> Self {
58 Self {
59 cost,
60 output,
61 logs: Vec::new(),
62 }
63 }
64}
65
66pub type EvmPrecompileResult = Result<PrecompileOutput, ExitError>;
67
68pub trait Precompile {
70 fn required_gas(input: &[u8]) -> Result<EthGas, ExitError>
72 where
73 Self: Sized;
74
75 fn run(
77 &self,
78 input: &[u8],
79 target_gas: Option<EthGas>,
80 context: &Context,
81 is_static: bool,
82 ) -> EvmPrecompileResult;
83}
84
85pub trait HandleBasedPrecompile {
86 fn run_with_handle(
87 &self,
88 handle: &mut impl PrecompileHandle,
89 ) -> Result<PrecompileOutput, PrecompileFailure>;
90}
91
92pub trait HardFork {}
94
95pub struct Homestead;
97
98pub struct Byzantium;
100
101pub struct Istanbul;
103
104pub struct Berlin;
106
107pub struct Osaka;
109
110impl HardFork for Homestead {}
111
112impl HardFork for Byzantium {}
113
114impl HardFork for Istanbul {}
115
116impl HardFork for Berlin {}
117
118impl HardFork for Osaka {}
119
120pub struct Precompiles<'a, I, E, H> {
121 pub all_precompiles: BTreeMap<Address, AllPrecompiles<'a, I, E, H>>,
122 pub paused_precompiles: BTreeSet<Address>,
123}
124
125impl<I, E, H> Precompiles<'_, I, E, H> {
126 fn is_paused(&self, address: &Address) -> bool {
127 self.paused_precompiles.contains(address)
128 }
129}
130
131impl<I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> executor::stack::PrecompileSet
132 for Precompiles<'_, I, E, H>
133{
134 fn execute(
135 &self,
136 handle: &mut impl PrecompileHandle,
137 ) -> Option<Result<executor::stack::PrecompileOutput, PrecompileFailure>> {
138 let address = Address::new(handle.code_address());
139
140 if self.is_paused(&address) {
141 return Some(Err(PrecompileFailure::Fatal {
142 exit_status: ExitFatal::Other(prelude::Cow::Borrowed("ERR_PAUSED")),
143 }));
144 }
145
146 let result = match self.all_precompiles.get(&address)? {
147 AllPrecompiles::ExitToNear(p) => process_precompile(p, handle),
148 AllPrecompiles::ExitToEthereum(p) => process_precompile(p, handle),
149 AllPrecompiles::PredecessorAccount(p) => process_precompile(p, handle),
150 AllPrecompiles::PrepaidGas(p) => process_precompile(p, handle),
151 AllPrecompiles::PromiseResult(p) => process_precompile(p, handle),
152 AllPrecompiles::CrossContractCall(p) => process_handle_based_precompile(p, handle),
153 AllPrecompiles::Generic(p) => process_precompile(p.as_ref(), handle),
154 };
155
156 Some(result.and_then(|output| post_process(output, handle)))
157 }
158
159 fn is_precompile(&self, address: prelude::H160) -> bool {
160 self.all_precompiles.contains_key(&Address::new(address))
161 }
162}
163
164fn process_precompile(
165 p: &dyn Precompile,
166 handle: &impl PrecompileHandle,
167) -> Result<PrecompileOutput, PrecompileFailure> {
168 let input = handle.input();
169 let gas_limit = handle.gas_limit();
170 let context = handle.context();
171 let is_static = handle.is_static();
172
173 p.run(input, gas_limit.map(EthGas::new), context, is_static)
174 .map_err(|exit_status| PrecompileFailure::Error { exit_status })
175}
176
177fn process_handle_based_precompile(
178 p: &impl HandleBasedPrecompile,
179 handle: &mut impl PrecompileHandle,
180) -> Result<PrecompileOutput, PrecompileFailure> {
181 p.run_with_handle(handle)
182}
183
184fn post_process(
185 output: PrecompileOutput,
186 handle: &mut impl PrecompileHandle,
187) -> Result<executor::stack::PrecompileOutput, PrecompileFailure> {
188 handle.record_cost(output.cost.as_u64())?;
189 for log in output.logs {
190 handle.log(log.address, log.topics, log.data)?;
191 }
192 Ok(executor::stack::PrecompileOutput {
193 exit_status: ExitSucceed::Returned,
194 output: output.output,
195 })
196}
197
198pub struct PrecompileConstructorContext<'a, I, E, H, M> {
199 pub current_account_id: AccountId,
200 pub random_seed: H256,
201 pub io: I,
202 pub env: &'a E,
203 pub promise_handler: H,
204 pub mod_exp_algorithm: prelude::PhantomData<M>,
205}
206
207impl<'a, I: IO + Copy, E: Env, H: ReadOnlyPromiseHandler> Precompiles<'a, I, E, H> {
208 #[allow(dead_code)]
209 pub fn new_homestead<M: ModExpAlgorithm + 'static>(
210 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
211 ) -> Self {
212 let addresses = vec![
213 ECRecover::ADDRESS,
214 SHA256::ADDRESS,
215 RIPEMD160::ADDRESS,
216 RandomSeed::ADDRESS,
217 CurrentAccount::ADDRESS,
218 ];
219 let fun: Vec<Box<dyn Precompile>> = vec![
220 Box::new(ECRecover),
221 Box::new(SHA256),
222 Box::new(RIPEMD160),
223 Box::new(RandomSeed::new(ctx.random_seed)),
224 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
225 ];
226 let map = addresses
227 .into_iter()
228 .zip(fun)
229 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
230 .collect();
231 Self::with_generic_precompiles(map, ctx)
232 }
233
234 #[allow(dead_code)]
235 pub fn new_byzantium<M: ModExpAlgorithm + 'static>(
236 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
237 ) -> Self {
238 let addresses = vec![
239 ECRecover::ADDRESS,
240 SHA256::ADDRESS,
241 RIPEMD160::ADDRESS,
242 Identity::ADDRESS,
243 ModExp::<Byzantium, M>::ADDRESS,
244 Bn256Add::<Byzantium>::ADDRESS,
245 Bn256Mul::<Byzantium>::ADDRESS,
246 Bn256Pair::<Byzantium>::ADDRESS,
247 RandomSeed::ADDRESS,
248 CurrentAccount::ADDRESS,
249 ];
250 let fun: Vec<Box<dyn Precompile>> = vec![
251 Box::new(ECRecover),
252 Box::new(SHA256),
253 Box::new(RIPEMD160),
254 Box::new(Identity),
255 Box::new(ModExp::<Byzantium, M>::new()),
256 Box::new(Bn256Add::<Byzantium>::new()),
257 Box::new(Bn256Mul::<Byzantium>::new()),
258 Box::new(Bn256Pair::<Byzantium>::new()),
259 Box::new(RandomSeed::new(ctx.random_seed)),
260 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
261 ];
262 let map = addresses
263 .into_iter()
264 .zip(fun)
265 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
266 .collect();
267
268 Self::with_generic_precompiles(map, ctx)
269 }
270
271 pub fn new_istanbul<M: ModExpAlgorithm + 'static>(
272 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
273 ) -> Self {
274 let addresses = vec![
275 ECRecover::ADDRESS,
276 SHA256::ADDRESS,
277 RIPEMD160::ADDRESS,
278 Identity::ADDRESS,
279 ModExp::<Byzantium, M>::ADDRESS,
280 Bn256Add::<Istanbul>::ADDRESS,
281 Bn256Mul::<Istanbul>::ADDRESS,
282 Bn256Pair::<Istanbul>::ADDRESS,
283 Blake2F::ADDRESS,
284 RandomSeed::ADDRESS,
285 CurrentAccount::ADDRESS,
286 ];
287 let fun: Vec<Box<dyn Precompile>> = vec![
288 Box::new(ECRecover),
289 Box::new(SHA256),
290 Box::new(RIPEMD160),
291 Box::new(Identity),
292 Box::new(ModExp::<Byzantium, M>::new()),
293 Box::new(Bn256Add::<Istanbul>::new()),
294 Box::new(Bn256Mul::<Istanbul>::new()),
295 Box::new(Bn256Pair::<Istanbul>::new()),
296 Box::new(Blake2F),
297 Box::new(RandomSeed::new(ctx.random_seed)),
298 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
299 ];
300 let map = addresses
301 .into_iter()
302 .zip(fun)
303 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
304 .collect();
305
306 Self::with_generic_precompiles(map, ctx)
307 }
308
309 pub fn new_berlin<M: ModExpAlgorithm + 'static>(
310 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
311 ) -> Self {
312 let addresses = vec![
313 ECRecover::ADDRESS,
314 SHA256::ADDRESS,
315 RIPEMD160::ADDRESS,
316 Identity::ADDRESS,
317 ModExp::<Berlin, M>::ADDRESS,
318 Bn256Add::<Istanbul>::ADDRESS,
319 Bn256Mul::<Istanbul>::ADDRESS,
320 Bn256Pair::<Istanbul>::ADDRESS,
321 Blake2F::ADDRESS,
322 RandomSeed::ADDRESS,
323 CurrentAccount::ADDRESS,
324 ];
325 let fun: Vec<Box<dyn Precompile>> = vec![
326 Box::new(ECRecover),
327 Box::new(SHA256),
328 Box::new(RIPEMD160),
329 Box::new(Identity),
330 Box::new(ModExp::<Berlin, M>::new()),
331 Box::new(Bn256Add::<Istanbul>::new()),
332 Box::new(Bn256Mul::<Istanbul>::new()),
333 Box::new(Bn256Pair::<Istanbul>::new()),
334 Box::new(Blake2F),
335 Box::new(RandomSeed::new(ctx.random_seed)),
336 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
337 ];
338 let map = addresses
339 .into_iter()
340 .zip(fun)
341 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
342 .collect();
343
344 Self::with_generic_precompiles(map, ctx)
345 }
346
347 pub fn new_london<M: ModExpAlgorithm + 'static>(
348 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
349 ) -> Self {
350 Self::new_berlin(ctx)
352 }
353
354 pub fn new_prague<M: ModExpAlgorithm + 'static>(
358 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
359 ) -> Self {
360 let addresses = vec![
361 ECRecover::ADDRESS,
362 SHA256::ADDRESS,
363 RIPEMD160::ADDRESS,
364 Identity::ADDRESS,
365 ModExp::<Berlin, M>::ADDRESS,
366 Bn256Add::<Istanbul>::ADDRESS,
367 Bn256Mul::<Istanbul>::ADDRESS,
368 Bn256Pair::<Istanbul>::ADDRESS,
369 Blake2F::ADDRESS,
370 RandomSeed::ADDRESS,
371 CurrentAccount::ADDRESS,
372 bls12_381::BlsG1Add::ADDRESS,
373 bls12_381::BlsG1Msm::ADDRESS,
374 bls12_381::BlsG2Add::ADDRESS,
375 bls12_381::BlsG2Msm::ADDRESS,
376 bls12_381::BlsPairingCheck::ADDRESS,
377 bls12_381::BlsMapFpToG1::ADDRESS,
378 bls12_381::BlsMapFp2ToG2::ADDRESS,
379 ];
380 let fun: Vec<Box<dyn Precompile>> = vec![
381 Box::new(ECRecover),
382 Box::new(SHA256),
383 Box::new(RIPEMD160),
384 Box::new(Identity),
385 Box::new(ModExp::<Berlin, M>::new()),
386 Box::new(Bn256Add::<Istanbul>::new()),
387 Box::new(Bn256Mul::<Istanbul>::new()),
388 Box::new(Bn256Pair::<Istanbul>::new()),
389 Box::new(Blake2F),
390 Box::new(RandomSeed::new(ctx.random_seed)),
391 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
392 Box::new(bls12_381::BlsG1Add),
393 Box::new(bls12_381::BlsG1Msm),
394 Box::new(bls12_381::BlsG2Add),
395 Box::new(bls12_381::BlsG2Msm),
396 Box::new(bls12_381::BlsPairingCheck),
397 Box::new(bls12_381::BlsMapFpToG1),
398 Box::new(bls12_381::BlsMapFp2ToG2),
399 ];
400 let map = addresses
401 .into_iter()
402 .zip(fun)
403 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
404 .collect();
405
406 Self::with_generic_precompiles(map, ctx)
407 }
408
409 pub fn new_osaka<M: ModExpAlgorithm + 'static>(
410 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
411 ) -> Self {
412 let addresses = vec![
413 ECRecover::ADDRESS,
414 SHA256::ADDRESS,
415 RIPEMD160::ADDRESS,
416 Identity::ADDRESS,
417 ModExp::<Osaka, M>::ADDRESS,
418 Bn256Add::<Istanbul>::ADDRESS,
419 Bn256Mul::<Istanbul>::ADDRESS,
420 Bn256Pair::<Istanbul>::ADDRESS,
421 Blake2F::ADDRESS,
422 RandomSeed::ADDRESS,
423 CurrentAccount::ADDRESS,
424 bls12_381::BlsG1Add::ADDRESS,
425 bls12_381::BlsG1Msm::ADDRESS,
426 bls12_381::BlsG2Add::ADDRESS,
427 bls12_381::BlsG2Msm::ADDRESS,
428 bls12_381::BlsPairingCheck::ADDRESS,
429 bls12_381::BlsMapFpToG1::ADDRESS,
430 bls12_381::BlsMapFp2ToG2::ADDRESS,
431 Secp256r1::ADDRESS,
432 ];
433 let fun: Vec<Box<dyn Precompile>> = vec![
434 Box::new(ECRecover),
435 Box::new(SHA256),
436 Box::new(RIPEMD160),
437 Box::new(Identity),
438 Box::new(ModExp::<Osaka, M>::new()),
439 Box::new(Bn256Add::<Istanbul>::new()),
440 Box::new(Bn256Mul::<Istanbul>::new()),
441 Box::new(Bn256Pair::<Istanbul>::new()),
442 Box::new(Blake2F),
443 Box::new(RandomSeed::new(ctx.random_seed)),
444 Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
445 Box::new(bls12_381::BlsG1Add),
446 Box::new(bls12_381::BlsG1Msm),
447 Box::new(bls12_381::BlsG2Add),
448 Box::new(bls12_381::BlsG2Msm),
449 Box::new(bls12_381::BlsPairingCheck),
450 Box::new(bls12_381::BlsMapFpToG1),
451 Box::new(bls12_381::BlsMapFp2ToG2),
452 Box::new(Secp256r1),
453 ];
454 let map = addresses
455 .into_iter()
456 .zip(fun)
457 .map(|(a, f)| (a, AllPrecompiles::Generic(f)))
458 .collect();
459
460 Self::with_generic_precompiles(map, ctx)
461 }
462
463 fn with_generic_precompiles<M: ModExpAlgorithm + 'static>(
464 mut generic_precompiles: BTreeMap<Address, AllPrecompiles<'a, I, E, H>>,
465 ctx: PrecompileConstructorContext<'a, I, E, H, M>,
466 ) -> Self {
467 let near_exit = ExitToNear::new(ctx.current_account_id.clone(), ctx.io);
468 let ethereum_exit = ExitToEthereum::new(ctx.io);
469 let cross_contract_call = CrossContractCall::new(ctx.current_account_id, ctx.io);
470 let predecessor_account_id = PredecessorAccount::new(ctx.env);
471 let prepaid_gas = PrepaidGas::new(ctx.env);
472 let promise_results = PromiseResult::new(ctx.promise_handler);
473
474 generic_precompiles.insert(exit_to_near::ADDRESS, AllPrecompiles::ExitToNear(near_exit));
475 generic_precompiles.insert(
476 exit_to_ethereum::ADDRESS,
477 AllPrecompiles::ExitToEthereum(ethereum_exit),
478 );
479 generic_precompiles.insert(
480 cross_contract_call::ADDRESS,
481 AllPrecompiles::CrossContractCall(cross_contract_call),
482 );
483 generic_precompiles.insert(
484 predecessor_account::ADDRESS,
485 AllPrecompiles::PredecessorAccount(predecessor_account_id),
486 );
487 generic_precompiles.insert(
488 prepaid_gas::ADDRESS,
489 AllPrecompiles::PrepaidGas(prepaid_gas),
490 );
491 generic_precompiles.insert(
492 promise_result::ADDRESS,
493 AllPrecompiles::PromiseResult(promise_results),
494 );
495
496 Self {
497 all_precompiles: generic_precompiles,
498 paused_precompiles: BTreeSet::new(),
499 }
500 }
501}
502
503pub enum AllPrecompiles<'a, I, E, H> {
504 ExitToNear(ExitToNear<I>),
505 ExitToEthereum(ExitToEthereum<I>),
506 CrossContractCall(CrossContractCall<I>),
507 PredecessorAccount(PredecessorAccount<'a, E>),
508 PrepaidGas(PrepaidGas<'a, E>),
509 PromiseResult(PromiseResult<H>),
510 Generic(Box<dyn Precompile>),
511}
512
513const fn make_h256(x: u128, y: u128) -> H256 {
514 let x_bytes = x.to_be_bytes();
515 let y_bytes = y.to_be_bytes();
516 H256([
517 x_bytes[0],
518 x_bytes[1],
519 x_bytes[2],
520 x_bytes[3],
521 x_bytes[4],
522 x_bytes[5],
523 x_bytes[6],
524 x_bytes[7],
525 x_bytes[8],
526 x_bytes[9],
527 x_bytes[10],
528 x_bytes[11],
529 x_bytes[12],
530 x_bytes[13],
531 x_bytes[14],
532 x_bytes[15],
533 y_bytes[0],
534 y_bytes[1],
535 y_bytes[2],
536 y_bytes[3],
537 y_bytes[4],
538 y_bytes[5],
539 y_bytes[6],
540 y_bytes[7],
541 y_bytes[8],
542 y_bytes[9],
543 y_bytes[10],
544 y_bytes[11],
545 y_bytes[12],
546 y_bytes[13],
547 y_bytes[14],
548 y_bytes[15],
549 ])
550}
551
552#[cfg(test)]
553mod tests {
554 use crate::prelude::H160;
555 use crate::{Byzantium, Istanbul, prelude};
556 use prelude::types::Address;
557
558 #[test]
559 fn test_precompile_addresses() {
560 assert_eq!(super::secp256k1::ECRecover::ADDRESS, u8_to_address(1));
561 assert_eq!(super::hash::SHA256::ADDRESS, u8_to_address(2));
562 assert_eq!(super::hash::RIPEMD160::ADDRESS, u8_to_address(3));
563 assert_eq!(super::identity::Identity::ADDRESS, u8_to_address(4));
564 assert_eq!(super::ModExp::<Byzantium>::ADDRESS, u8_to_address(5));
565 assert_eq!(super::Bn256Add::<Istanbul>::ADDRESS, u8_to_address(6));
566 assert_eq!(super::Bn256Mul::<Istanbul>::ADDRESS, u8_to_address(7));
567 assert_eq!(super::Bn256Pair::<Istanbul>::ADDRESS, u8_to_address(8));
568 assert_eq!(super::blake2::Blake2F::ADDRESS, u8_to_address(9));
569 }
570
571 #[test]
572 #[allow(clippy::too_many_lines)]
573 fn test_paused_precompiles_throws_error() {
574 use crate::{
575 AllPrecompiles, Context, EvmPrecompileResult, ExitError, Precompile, PrecompileOutput,
576 Precompiles,
577 };
578 use aurora_engine_sdk::env::Fixed;
579 use aurora_engine_sdk::promise::Noop;
580 use aurora_engine_test_doubles::io::StoragePointer;
581 use aurora_engine_types::types::EthGas;
582 use aurora_evm::executor::stack::{PrecompileFailure, PrecompileHandle, PrecompileSet};
583 use aurora_evm::{ExitFatal, ExitReason, Transfer};
584
585 struct MockPrecompile;
586
587 impl Precompile for MockPrecompile {
588 fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError>
589 where
590 Self: Sized,
591 {
592 Ok(EthGas::new(0))
593 }
594
595 fn run(
596 &self,
597 _input: &[u8],
598 _target_gas: Option<EthGas>,
599 _context: &Context,
600 _is_static: bool,
601 ) -> EvmPrecompileResult {
602 Ok(PrecompileOutput::default())
603 }
604 }
605
606 struct MockPrecompileHandle {
607 code_address: H160,
608 }
609
610 impl MockPrecompileHandle {
611 pub const fn new(code_address: H160) -> Self {
612 Self { code_address }
613 }
614 }
615
616 impl PrecompileHandle for MockPrecompileHandle {
617 fn call(
618 &mut self,
619 _to: H160,
620 _transfer: Option<Transfer>,
621 _input: Vec<u8>,
622 _gas_limit: Option<u64>,
623 _is_static: bool,
624 _context: &Context,
625 ) -> (ExitReason, Vec<u8>) {
626 unimplemented!()
627 }
628
629 fn record_cost(&mut self, _cost: u64) -> Result<(), ExitError> {
630 unimplemented!()
631 }
632
633 fn record_external_cost(
634 &mut self,
635 _ref_time: Option<u64>,
636 _proof_size: Option<u64>,
637 _storage_growth: Option<u64>,
638 ) -> Result<(), ExitError> {
639 unimplemented!()
640 }
641
642 fn refund_external_cost(&mut self, _ref_time: Option<u64>, _proof_size: Option<u64>) {
643 unimplemented!()
644 }
645
646 fn remaining_gas(&self) -> u64 {
647 unimplemented!()
648 }
649
650 fn log(
651 &mut self,
652 _address: H160,
653 _topics: Vec<aurora_engine_types::H256>,
654 _data: Vec<u8>,
655 ) -> Result<(), ExitError> {
656 unimplemented!()
657 }
658
659 fn code_address(&self) -> H160 {
660 self.code_address
661 }
662
663 fn input(&self) -> &[u8] {
664 unimplemented!()
665 }
666
667 fn context(&self) -> &Context {
668 unimplemented!()
669 }
670
671 fn is_static(&self) -> bool {
672 unimplemented!()
673 }
674
675 fn gas_limit(&self) -> Option<u64> {
676 unimplemented!()
677 }
678 }
679
680 let precompile_address = Address::default();
681 let precompile: AllPrecompiles<StoragePointer, Fixed, Noop> =
682 AllPrecompiles::Generic(Box::new(MockPrecompile));
683
684 let precompiles: Precompiles<StoragePointer, Fixed, Noop> = Precompiles {
685 all_precompiles: {
686 let mut map = prelude::BTreeMap::new();
687 map.insert(precompile_address, precompile);
688 map
689 },
690 paused_precompiles: {
691 let mut set = prelude::BTreeSet::new();
692 set.insert(precompile_address);
693 set
694 },
695 };
696 let mut precompile_handle = MockPrecompileHandle::new(precompile_address.raw());
697
698 let result = precompiles
699 .execute(&mut precompile_handle)
700 .expect("result must contain error but is empty");
701 let actual_failure = result.expect_err("result must contain failure but is successful");
702 let expected_failure = PrecompileFailure::Fatal {
703 exit_status: ExitFatal::Other(prelude::Cow::Borrowed("ERR_PAUSED")),
704 };
705
706 assert_eq!(expected_failure, actual_failure);
707 }
708
709 const fn u8_to_address(x: u8) -> Address {
710 let mut bytes = [0u8; 20];
711 bytes[19] = x;
712 Address::new(H160(bytes))
713 }
714}