revm_handler/
precompile_provider.rs1use auto_impl::auto_impl;
2use context::{Cfg, LocalContextTr};
3use context_interface::{ContextTr, JournalTr};
4use interpreter::{CallInput, CallInputs, Gas, InstructionResult, InterpreterResult};
5use precompile::{PrecompileError, PrecompileSpecId, Precompiles};
6use primitives::{hardfork::SpecId, Address, Bytes};
7use std::{
8 boxed::Box,
9 string::{String, ToString},
10};
11
12#[auto_impl(&mut, Box)]
14pub trait PrecompileProvider<CTX: ContextTr> {
15 type Output;
17
18 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool;
22
23 fn run(
25 &mut self,
26 context: &mut CTX,
27 inputs: &CallInputs,
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 new(spec: SpecId) -> Self {
49 Self {
50 precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
51 spec,
52 }
53 }
54
55 pub fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
57 Box::new(self.precompiles.addresses().cloned())
58 }
59
60 pub fn contains(&self, address: &Address) -> bool {
62 self.precompiles.contains(address)
63 }
64}
65
66impl Clone for EthPrecompiles {
67 fn clone(&self) -> Self {
68 Self {
69 precompiles: self.precompiles,
70 spec: self.spec,
71 }
72 }
73}
74
75impl Default for EthPrecompiles {
76 fn default() -> Self {
77 let spec = SpecId::default();
78 Self {
79 precompiles: Precompiles::new(PrecompileSpecId::from_spec_id(spec)),
80 spec,
81 }
82 }
83}
84
85impl<CTX: ContextTr> PrecompileProvider<CTX> for EthPrecompiles {
86 type Output = InterpreterResult;
87
88 fn set_spec(&mut self, spec: <CTX::Cfg as Cfg>::Spec) -> bool {
89 let spec = spec.into();
90 if spec == self.spec {
92 return false;
93 }
94 self.precompiles = Precompiles::new(PrecompileSpecId::from_spec_id(spec));
95 self.spec = spec;
96 true
97 }
98
99 fn run(
100 &mut self,
101 context: &mut CTX,
102 inputs: &CallInputs,
103 ) -> Result<Option<InterpreterResult>, String> {
104 let Some(precompile) = self.precompiles.get(&inputs.bytecode_address) else {
105 return Ok(None);
106 };
107
108 let mut result = InterpreterResult {
109 result: InstructionResult::Return,
110 gas: Gas::new(inputs.gas_limit),
111 output: Bytes::new(),
112 };
113
114 let exec_result = {
115 let r;
116 let input_bytes = match &inputs.input {
117 CallInput::SharedBuffer(range) => {
118 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
119 r = slice;
120 r.as_ref()
121 } else {
122 &[]
123 }
124 }
125 CallInput::Bytes(bytes) => bytes.0.iter().as_slice(),
126 };
127 precompile.execute(input_bytes, inputs.gas_limit)
128 };
129
130 match exec_result {
131 Ok(output) => {
132 result.gas.record_refund(output.gas_refunded);
133 let underflow = result.gas.record_cost(output.gas_used);
134 assert!(underflow, "Gas underflow is not possible");
135 result.result = if output.reverted {
136 InstructionResult::Revert
137 } else {
138 InstructionResult::Return
139 };
140 result.output = output.bytes;
141 }
142 Err(PrecompileError::Fatal(e)) => return Err(e),
143 Err(e) => {
144 result.result = if e.is_oog() {
145 InstructionResult::PrecompileOOG
146 } else {
147 InstructionResult::PrecompileError
148 };
149 if !e.is_oog() && context.journal().depth() == 1 {
153 context
154 .local_mut()
155 .set_precompile_error_context(e.to_string());
156 }
157 }
158 }
159 Ok(Some(result))
160 }
161
162 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
163 Self::warm_addresses(self)
164 }
165
166 fn contains(&self, address: &Address) -> bool {
167 Self::contains(self, address)
168 }
169}