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 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 inputs: &CallInputs,
95 ) -> Result<Option<InterpreterResult>, String> {
96 let Some(precompile) = self.precompiles.get(&inputs.bytecode_address) else {
97 return Ok(None);
98 };
99
100 let mut result = InterpreterResult {
101 result: InstructionResult::Return,
102 gas: Gas::new(inputs.gas_limit),
103 output: Bytes::new(),
104 };
105
106 let exec_result = {
107 let r;
108 let input_bytes = match &inputs.input {
109 CallInput::SharedBuffer(range) => {
110 if let Some(slice) = context.local().shared_memory_buffer_slice(range.clone()) {
111 r = slice;
112 r.as_ref()
113 } else {
114 &[]
115 }
116 }
117 CallInput::Bytes(bytes) => bytes.0.iter().as_slice(),
118 };
119 precompile.execute(input_bytes, inputs.gas_limit)
120 };
121
122 match exec_result {
123 Ok(output) => {
124 result.gas.record_refund(output.gas_refunded);
125 let underflow = result.gas.record_cost(output.gas_used);
126 assert!(underflow, "Gas underflow is not possible");
127 result.result = if output.reverted {
128 InstructionResult::Revert
129 } else {
130 InstructionResult::Return
131 };
132 result.output = output.bytes;
133 }
134 Err(PrecompileError::Fatal(e)) => return Err(e),
135 Err(e) => {
136 result.result = if e.is_oog() {
137 InstructionResult::PrecompileOOG
138 } else {
139 InstructionResult::PrecompileError
140 };
141 if !e.is_oog() && context.journal().depth() == 1 {
145 context
146 .local_mut()
147 .set_precompile_error_context(e.to_string());
148 }
149 }
150 }
151 Ok(Some(result))
152 }
153
154 fn warm_addresses(&self) -> Box<impl Iterator<Item = Address>> {
155 Self::warm_addresses(self)
156 }
157
158 fn contains(&self, address: &Address) -> bool {
159 Self::contains(self, address)
160 }
161}