1use crate::{Bytes, Env};
2use core::fmt::{self};
3use dyn_clone::DynClone;
4use std::{boxed::Box, string::String, sync::Arc};
5
6pub type PrecompileResult = Result<PrecompileOutput, PrecompileErrors>;
10
11#[derive(Clone, Debug, PartialEq, Eq, Hash)]
13pub struct PrecompileOutput {
14 pub gas_used: u64,
16 pub bytes: Bytes,
18}
19
20impl PrecompileOutput {
21 pub fn new(gas_used: u64, bytes: Bytes) -> Self {
23 Self { gas_used, bytes }
24 }
25}
26
27pub type StandardPrecompileFn = fn(&Bytes, u64) -> PrecompileResult;
28pub type EnvPrecompileFn = fn(&Bytes, u64, env: &Env) -> PrecompileResult;
29
30pub trait StatefulPrecompile: Sync + Send {
33 fn call(&self, bytes: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult;
34}
35
36pub trait StatefulPrecompileMut: DynClone + Send + Sync {
39 fn call_mut(&mut self, bytes: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult;
40}
41
42dyn_clone::clone_trait_object!(StatefulPrecompileMut);
43
44pub type StatefulPrecompileArc = Arc<dyn StatefulPrecompile>;
46
47pub type StatefulPrecompileBox = Box<dyn StatefulPrecompileMut>;
49
50#[derive(Clone)]
52pub enum Precompile {
53 Standard(StandardPrecompileFn),
55 Env(EnvPrecompileFn),
57 Stateful(StatefulPrecompileArc),
60 StatefulMut(StatefulPrecompileBox),
63}
64
65impl From<StandardPrecompileFn> for Precompile {
66 fn from(p: StandardPrecompileFn) -> Self {
67 Precompile::Standard(p)
68 }
69}
70
71impl From<EnvPrecompileFn> for Precompile {
72 fn from(p: EnvPrecompileFn) -> Self {
73 Precompile::Env(p)
74 }
75}
76
77impl From<StatefulPrecompileArc> for Precompile {
78 fn from(p: StatefulPrecompileArc) -> Self {
79 Precompile::Stateful(p)
80 }
81}
82
83impl From<StatefulPrecompileBox> for Precompile {
84 fn from(p: StatefulPrecompileBox) -> Self {
85 Precompile::StatefulMut(p)
86 }
87}
88
89impl fmt::Debug for Precompile {
90 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91 match self {
92 Precompile::Standard(_) => f.write_str("Standard"),
93 Precompile::Env(_) => f.write_str("Env"),
94 Precompile::Stateful(_) => f.write_str("Stateful"),
95 Precompile::StatefulMut(_) => f.write_str("StatefulMut"),
96 }
97 }
98}
99
100impl Precompile {
101 pub fn new_stateful<P: StatefulPrecompile + 'static>(p: P) -> Self {
103 Self::Stateful(Arc::new(p))
104 }
105
106 pub fn new_stateful_mut<P: StatefulPrecompileMut + 'static>(p: P) -> Self {
108 Self::StatefulMut(Box::new(p))
109 }
110
111 pub fn call(&mut self, bytes: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult {
113 match *self {
114 Precompile::Standard(p) => p(bytes, gas_limit),
115 Precompile::Env(p) => p(bytes, gas_limit, env),
116 Precompile::Stateful(ref p) => p.call(bytes, gas_limit, env),
117 Precompile::StatefulMut(ref mut p) => p.call_mut(bytes, gas_limit, env),
118 }
119 }
120
121 pub fn call_ref(&self, bytes: &Bytes, gas_limit: u64, env: &Env) -> PrecompileResult {
125 match *self {
126 Precompile::Standard(p) => p(bytes, gas_limit),
127 Precompile::Env(p) => p(bytes, gas_limit, env),
128 Precompile::Stateful(ref p) => p.call(bytes, gas_limit, env),
129 Precompile::StatefulMut(_) => Err(PrecompileErrors::Fatal {
130 msg: "call_ref on mutable stateful precompile".into(),
131 }),
132 }
133 }
134}
135
136#[derive(Clone, Debug, PartialEq, Eq, Hash)]
138pub enum PrecompileErrors {
139 Error(PrecompileError),
140 Fatal { msg: String },
141}
142
143#[cfg(feature = "std")]
144impl std::error::Error for PrecompileErrors {}
145
146impl fmt::Display for PrecompileErrors {
147 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
148 match self {
149 Self::Error(e) => e.fmt(f),
150 Self::Fatal { msg } => f.write_str(msg),
151 }
152 }
153}
154
155#[derive(Clone, Debug, PartialEq, Eq, Hash)]
156pub enum PrecompileError {
157 OutOfGas,
159 Blake2WrongLength,
161 Blake2WrongFinalIndicatorFlag,
162 ModexpExpOverflow,
164 ModexpBaseOverflow,
165 ModexpModOverflow,
166 Bn128FieldPointNotAMember,
168 Bn128AffineGFailedToCreate,
169 Bn128PairLength,
170 BlobInvalidInputLength,
173 BlobMismatchedVersion,
175 BlobVerifyKzgProofFailed,
177 Other(String),
179}
180
181impl PrecompileError {
182 pub fn other(err: impl Into<String>) -> Self {
184 Self::Other(err.into())
185 }
186
187 pub fn is_oog(&self) -> bool {
189 matches!(self, Self::OutOfGas)
190 }
191}
192
193impl From<PrecompileError> for PrecompileErrors {
194 fn from(err: PrecompileError) -> Self {
195 PrecompileErrors::Error(err)
196 }
197}
198
199#[cfg(feature = "std")]
200impl std::error::Error for PrecompileError {}
201
202impl fmt::Display for PrecompileError {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 let s = match self {
205 Self::OutOfGas => "out of gas",
206 Self::Blake2WrongLength => "wrong input length for blake2",
207 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
208 Self::ModexpExpOverflow => "modexp exp overflow",
209 Self::ModexpBaseOverflow => "modexp base overflow",
210 Self::ModexpModOverflow => "modexp mod overflow",
211 Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve",
212 Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve",
213 Self::Bn128PairLength => "bn128 invalid pair length",
214 Self::BlobInvalidInputLength => "invalid blob input length",
215 Self::BlobMismatchedVersion => "mismatched blob version",
216 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
217 Self::Other(s) => s,
218 };
219 f.write_str(s)
220 }
221}
222
223#[cfg(test)]
224mod test {
225 use super::*;
226
227 #[test]
228 fn stateful_precompile_mut() {
229 #[derive(Default, Clone)]
230 struct MyPrecompile {}
231
232 impl StatefulPrecompileMut for MyPrecompile {
233 fn call_mut(
234 &mut self,
235 _bytes: &Bytes,
236 _gas_limit: u64,
237 _env: &Env,
238 ) -> PrecompileResult {
239 Err(PrecompileError::OutOfGas.into())
240 }
241 }
242
243 let mut p = Precompile::new_stateful_mut(MyPrecompile::default());
244 match &mut p {
245 Precompile::StatefulMut(p) => {
246 let _ = p.call_mut(&Bytes::new(), 0, &Env::default());
247 }
248 _ => panic!("not a state"),
249 }
250 }
251}