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