revm_optimism/handler/
precompiles.rs

1use crate::OpSpecId;
2use once_cell::race::OnceBox;
3use precompile::{secp256r1, PrecompileError, Precompiles};
4use revm::{
5    context::Cfg,
6    context_interface::ContextTr,
7    handler::{EthPrecompiles, PrecompileProvider},
8    interpreter::InterpreterResult,
9};
10use std::boxed::Box;
11
12pub struct OpPrecompileProvider<CTX> {
13    precompile_provider: EthPrecompiles<CTX>,
14}
15
16impl<CTX> Clone for OpPrecompileProvider<CTX> {
17    fn clone(&self) -> Self {
18        Self {
19            precompile_provider: self.precompile_provider.clone(),
20        }
21    }
22}
23
24impl<CTX> OpPrecompileProvider<CTX> {
25    pub fn new(precompiles: &'static Precompiles) -> Self {
26        Self {
27            precompile_provider: EthPrecompiles {
28                precompiles,
29                _phantom: core::marker::PhantomData,
30            },
31        }
32    }
33
34    #[inline]
35    pub fn new_with_spec(spec: OpSpecId) -> Self {
36        match spec {
37            spec @ (OpSpecId::BEDROCK
38            | OpSpecId::REGOLITH
39            | OpSpecId::CANYON
40            | OpSpecId::ECOTONE) => Self::new(Precompiles::new(spec.into_eth_spec().into())),
41            OpSpecId::FJORD => Self::new(fjord()),
42            OpSpecId::GRANITE | OpSpecId::HOLOCENE => Self::new(granite()),
43            OpSpecId::ISTHMUS | OpSpecId::INTEROP => Self::new(isthumus()),
44        }
45    }
46}
47
48/// Returns precompiles for Fjor spec.
49pub fn fjord() -> &'static Precompiles {
50    static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
51    INSTANCE.get_or_init(|| {
52        let mut precompiles = Precompiles::cancun().clone();
53        // EIP-7212: secp256r1 P256verify
54        precompiles.extend([crate::bn128::pair::GRANITE]);
55        Box::new(precompiles)
56    })
57}
58
59/// Returns precompiles for Granite spec.
60pub fn granite() -> &'static Precompiles {
61    static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
62    INSTANCE.get_or_init(|| {
63        let mut precompiles = Precompiles::cancun().clone();
64        // Restrict bn256Pairing input size
65        precompiles.extend([secp256r1::P256VERIFY]);
66        Box::new(precompiles)
67    })
68}
69
70/// Returns precompiles for isthumus spec.
71pub fn isthumus() -> &'static Precompiles {
72    static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
73    INSTANCE.get_or_init(|| {
74        let precompiles = granite().clone();
75        // Prague bls12 precompiles
76        // Don't include BLS12-381 precompiles in no_std builds.
77        #[cfg(feature = "blst")]
78        let precompiles = {
79            let mut precompiles = precompiles;
80            precompiles.extend(precompile::bls12_381::precompiles());
81            precompiles
82        };
83        Box::new(precompiles)
84    })
85}
86
87impl<CTX> PrecompileProvider for OpPrecompileProvider<CTX>
88where
89    CTX: ContextTr<Cfg: Cfg<Spec = OpSpecId>>,
90{
91    type Context = CTX;
92    type Output = InterpreterResult;
93
94    #[inline]
95    fn set_spec(&mut self, spec: <<Self::Context as ContextTr>::Cfg as Cfg>::Spec) {
96        *self = Self::new_with_spec(spec);
97    }
98
99    #[inline]
100    fn run(
101        &mut self,
102        context: &mut Self::Context,
103        address: &precompile::Address,
104        bytes: &precompile::Bytes,
105        gas_limit: u64,
106    ) -> Result<Option<Self::Output>, PrecompileError> {
107        self.precompile_provider
108            .run(context, address, bytes, gas_limit)
109    }
110
111    #[inline]
112    fn warm_addresses(&self) -> Box<impl Iterator<Item = precompile::Address> + '_> {
113        self.precompile_provider.warm_addresses()
114    }
115
116    #[inline]
117    fn contains(&self, address: &precompile::Address) -> bool {
118        self.precompile_provider.contains(address)
119    }
120}
121
122impl<CTX> Default for OpPrecompileProvider<CTX> {
123    fn default() -> Self {
124        Self::new_with_spec(OpSpecId::ISTHMUS)
125    }
126}