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