aurora_engine_precompiles/
lib.rs

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