revm_handler/
precompile_provider.rs1use 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 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 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address> + '_>;
29
30 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}