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
105 let mut result = InterpreterResult {
106 result: InstructionResult::Return,
107 gas: Gas::new(gas_limit),
108 output: Bytes::new(),
109 };
110
111 let r;
112 let input_bytes = match &inputs.input {
113 CallInput::SharedBuffer(range) => {
114 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
115 r = slice;
116 r.as_ref()
117 } else {
118 &[]
119 }
120 }
121 CallInput::Bytes(bytes) => bytes.0.iter().as_slice(),
122 };
123
124 match (*precompile)(input_bytes, gas_limit) {
125 Ok(output) => {
126 let underflow = result.gas.record_cost(output.gas_used);
127 assert!(underflow, "Gas underflow is not possible");
128 result.result = if output.reverted {
129 InstructionResult::Revert
130 } else {
131 InstructionResult::Return
132 };
133 result.output = output.bytes;
134 }
135 Err(PrecompileError::Fatal(e)) => return Err(e),
136 Err(e) => {
137 result.result = if e.is_oog() {
138 InstructionResult::PrecompileOOG
139 } else {
140 InstructionResult::PrecompileError
141 };
142 }
143 }
144 Ok(Some(result))
145 }
146
147 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
148 self.warm_addresses()
149 }
150
151 fn contains(&self, address: &Address) -> bool {
152 self.contains(address)
153 }
154}