revm_handler/
precompile_provider.rs1use auto_impl::auto_impl;
2use context::Cfg;
3use context_interface::ContextTr;
4use interpreter::{Gas, InputsImpl, InstructionResult, InterpreterResult};
5use precompile::PrecompileError;
6use precompile::{PrecompileSpecId, Precompiles};
7use primitives::{hardfork::SpecId, Address, Bytes};
8use std::boxed::Box;
9use std::string::String;
10
11#[auto_impl(&mut, Box)]
12pub trait PrecompileProvider<CTX: ContextTr> {
13 type Output;
14
15 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool;
19
20 fn run(
22 &mut self,
23 context: &mut CTX,
24 address: &Address,
25 inputs: &InputsImpl,
26 is_static: bool,
27 gas_limit: u64,
28 ) -> Result<Option<Self::Output>, String>;
29
30 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>>;
32
33 fn contains(&self, address: &Address) -> bool;
35}
36
37#[derive(Debug)]
39pub struct EthPrecompiles {
40 pub precompiles: &'static Precompiles,
42 pub spec: SpecId,
44}
45
46impl EthPrecompiles {
47 pub fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
49 Box::new(self.precompiles.addresses().cloned())
50 }
51
52 pub fn contains(&self, address: &Address) -> bool {
54 self.precompiles.contains(address)
55 }
56}
57
58impl Clone for EthPrecompiles {
59 fn clone(&self) -> Self {
60 Self {
61 precompiles: self.precompiles,
62 spec: self.spec,
63 }
64 }
65}
66
67impl Default for EthPrecompiles {
68 fn default() -> Self {
69 let spec = SpecId::default();
70 Self {
71 precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
72 spec,
73 }
74 }
75}
76
77impl<CTX: ContextTr> PrecompileProvider<CTX> for EthPrecompiles {
78 type Output = InterpreterResult;
79
80 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool {
81 let spec = spec.into();
82 if spec == self.spec {
84 return false;
85 }
86 self.precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec));
87 self.spec = spec;
88 true
89 }
90
91 fn run(
92 &mut self,
93 _context: &mut CTX,
94 address: &Address,
95 inputs: &InputsImpl,
96 _is_static: bool,
97 gas_limit: u64,
98 ) -> Result<Option<InterpreterResult>, String> {
99 let Some(precompile) = self.precompiles.get(address) else {
100 return Ok(None);
101 };
102
103 let mut result = InterpreterResult {
104 result: InstructionResult::Return,
105 gas: Gas::new(gas_limit),
106 output: Bytes::new(),
107 };
108
109 match (*precompile)(&inputs.input, gas_limit) {
110 Ok(output) => {
111 let underflow = result.gas.record_cost(output.gas_used);
112 assert!(underflow, "Gas underflow is not possible");
113 result.result = InstructionResult::Return;
114 result.output = output.bytes;
115 }
116 Err(PrecompileError::Fatal(e)) => return Err(e),
117 Err(e) => {
118 result.result = if e.is_oog() {
119 InstructionResult::PrecompileOOG
120 } else {
121 InstructionResult::PrecompileError
122 };
123 }
124 }
125 Ok(Some(result))
126 }
127
128 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
129 self.warm_addresses()
130 }
131
132 fn contains(&self, address: &Address) -> bool {
133 self.contains(address)
134 }
135}