revm_handler/
precompile_provider.rs

1use auto_impl::auto_impl;
2use context::Cfg;
3use context_interface::ContextTr;
4use interpreter::{Gas, InstructionResult, InterpreterResult};
5use precompile::PrecompileError;
6use precompile::{PrecompileSpecId, Precompiles};
7use primitives::{Address, Bytes};
8use specification::hardfork::SpecId;
9use std::boxed::Box;
10
11#[auto_impl(&mut, Box)]
12pub trait PrecompileProvider {
13    type Context: ContextTr;
14    type Output;
15
16    fn set_spec(&mut self, spec: <<Self::Context as ContextTr>::Cfg as Cfg>::Spec);
17
18    /// Run the precompile.
19    fn run(
20        &mut self,
21        context: &mut Self::Context,
22        address: &Address,
23        bytes: &Bytes,
24        gas_limit: u64,
25    ) -> Result<Option<Self::Output>, PrecompileError>;
26
27    /// Get the warm addresses.
28    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address> + '_>;
29
30    /// Check if the address is a precompile.
31    fn contains(&self, address: &Address) -> bool;
32}
33
34pub struct EthPrecompiles<CTX> {
35    pub precompiles: &'static Precompiles,
36    pub _phantom: core::marker::PhantomData<CTX>,
37}
38
39impl<CTX> Clone for EthPrecompiles<CTX> {
40    fn clone(&self) -> Self {
41        Self {
42            precompiles: self.precompiles,
43            _phantom: core::marker::PhantomData,
44        }
45    }
46}
47
48impl<CTX> Default for EthPrecompiles<CTX> {
49    fn default() -> Self {
50        Self {
51            precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(SpecId::LATEST)),
52            _phantom: core::marker::PhantomData,
53        }
54    }
55}
56
57impl<CTX> PrecompileProvider for EthPrecompiles<CTX>
58where
59    CTX: ContextTr,
60{
61    type Context = CTX;
62    type Output = InterpreterResult;
63    fn set_spec(&mut self, spec: <<Self::Context as ContextTr>::Cfg as Cfg>::Spec) {
64        self.precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec.into()));
65    }
66
67    fn run(
68        &mut self,
69        _context: &mut Self::Context,
70        address: &Address,
71        bytes: &Bytes,
72        gas_limit: u64,
73    ) -> Result<Option<InterpreterResult>, PrecompileError> {
74        let Some(precompile) = self.precompiles.get(address) else {
75            return Ok(None);
76        };
77
78        let mut result = InterpreterResult {
79            result: InstructionResult::Return,
80            gas: Gas::new(gas_limit),
81            output: Bytes::new(),
82        };
83
84        match (*precompile)(bytes, gas_limit) {
85            Ok(output) => {
86                let underflow = result.gas.record_cost(output.gas_used);
87                assert!(underflow, "Gas underflow is not possible");
88                result.result = InstructionResult::Return;
89                result.output = output.bytes;
90            }
91            Err(e) => {
92                if let PrecompileError::Fatal(_) = e {
93                    return Err(e);
94                }
95                result.result = if e.is_oog() {
96                    InstructionResult::PrecompileOOG
97                } else {
98                    InstructionResult::PrecompileError
99                };
100            }
101        }
102        Ok(Some(result))
103    }
104
105    fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
106        Box::new(self.precompiles.addresses().cloned())
107    }
108
109    fn contains(&self, address: &Address) -> bool {
110        self.precompiles.contains(address)
111    }
112}