revm_handler/
precompile_provider.rs1use auto_impl::auto_impl;
2use context::{Cfg, LocalContextTr};
3use context_interface::ContextTr;
4use interpreter::{CallInput, 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)]
13pub trait PrecompileProvider<CTX: ContextTr> {
14 type Output;
16
17 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool;
21
22 fn run(
24 &mut self,
25 context: &mut CTX,
26 address: &Address,
27 inputs: &InputsImpl,
28 is_static: bool,
29 gas_limit: u64,
30 ) -> Result<Option<Self::Output>, String>;
31
32 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>>;
34
35 fn contains(&self, address: &Address) -> bool;
37}
38
39#[derive(Debug)]
41pub struct EthPrecompiles {
42 pub precompiles: &'static Precompiles,
44 pub spec: SpecId,
46}
47
48impl EthPrecompiles {
49 pub fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
51 Box::new(self.precompiles.addresses().cloned())
52 }
53
54 pub fn contains(&self, address: &Address) -> bool {
56 self.precompiles.contains(address)
57 }
58}
59
60impl Clone for EthPrecompiles {
61 fn clone(&self) -> Self {
62 Self {
63 precompiles: self.precompiles,
64 spec: self.spec,
65 }
66 }
67}
68
69impl Default for EthPrecompiles {
70 fn default() -> Self {
71 let spec = SpecId::default();
72 Self {
73 precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
74 spec,
75 }
76 }
77}
78
79impl<CTX: ContextTr> PrecompileProvider<CTX> for EthPrecompiles {
80 type Output = InterpreterResult;
81
82 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool {
83 let spec = spec.into();
84 if spec == self.spec {
86 return false;
87 }
88 self.precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec));
89 self.spec = spec;
90 true
91 }
92
93 fn run(
94 &mut self,
95 context: &mut CTX,
96 address: &Address,
97 inputs: &InputsImpl,
98 _is_static: bool,
99 gas_limit: u64,
100 ) -> Result<Option<InterpreterResult>, String> {
101 let Some(precompile) = self.precompiles.get(address) else {
102 return Ok(None);
103 };
104 let mut result = InterpreterResult {
105 result: InstructionResult::Return,
106 gas: Gas::new(gas_limit),
107 output: Bytes::new(),
108 };
109
110 let r;
111 let input_bytes = match &inputs.input {
112 CallInput::SharedBuffer(range) => {
113 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
114 r = slice;
115 r.as_ref()
116 } else {
117 &[]
118 }
119 }
120 CallInput::Bytes(bytes) => bytes.0.iter().as_slice(),
121 };
122
123 match (*precompile)(input_bytes, gas_limit) {
124 Ok(output) => {
125 let underflow = result.gas.record_cost(output.gas_used);
126 assert!(underflow, "Gas underflow is not possible");
127 result.result = InstructionResult::Return;
128 result.output = output.bytes;
129 }
130 Err(PrecompileError::Fatal(e)) => return Err(e),
131 Err(e) => {
132 result.result = if e.is_oog() {
133 InstructionResult::PrecompileOOG
134 } else {
135 InstructionResult::PrecompileError
136 };
137 }
138 }
139 Ok(Some(result))
140 }
141
142 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
143 self.warm_addresses()
144 }
145
146 fn contains(&self, address: &Address) -> bool {
147 self.contains(address)
148 }
149}