rtvm_primitives/
precompile.rs1use crate::{Bytes, Env};
2use core::fmt;
3use dyn_clone::DynClone;
4use std::{boxed::Box, string::String, sync::Arc};
5
6pub type PrecompileResult = Result<(u64, Bytes), PrecompileError>;
10
11pub type StandardPrecompileFn = fn(&Bytes, u64) -> PrecompileResult;
12pub type EnvPrecompileFn = fn(&Bytes, u64, env: &Env) -> PrecompileResult;
13
14pub trait StatefulPrecompile: Sync + Send {
17 fn call(&self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult;
18}
19
20pub trait StatefulPrecompileMut: DynClone + Send + Sync {
23 fn call_mut(&mut self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult;
24}
25
26dyn_clone::clone_trait_object!(StatefulPrecompileMut);
27
28pub type StatefulPrecompileArc = Arc<dyn StatefulPrecompile>;
30
31pub type StatefulPrecompileBox = Box<dyn StatefulPrecompileMut>;
33
34#[derive(Clone)]
36pub enum Precompile {
37 Standard(StandardPrecompileFn),
39 Env(EnvPrecompileFn),
41 Stateful(StatefulPrecompileArc),
44 StatefulMut(StatefulPrecompileBox),
47}
48
49impl From<StandardPrecompileFn> for Precompile {
50 fn from(p: StandardPrecompileFn) -> Self {
51 Precompile::Standard(p)
52 }
53}
54
55impl From<EnvPrecompileFn> for Precompile {
56 fn from(p: EnvPrecompileFn) -> Self {
57 Precompile::Env(p)
58 }
59}
60
61impl From<StatefulPrecompileArc> for Precompile {
62 fn from(p: StatefulPrecompileArc) -> Self {
63 Precompile::Stateful(p)
64 }
65}
66
67impl From<StatefulPrecompileBox> for Precompile {
68 fn from(p: StatefulPrecompileBox) -> Self {
69 Precompile::StatefulMut(p)
70 }
71}
72
73impl fmt::Debug for Precompile {
74 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75 match self {
76 Precompile::Standard(_) => f.write_str("Standard"),
77 Precompile::Env(_) => f.write_str("Env"),
78 Precompile::Stateful(_) => f.write_str("Stateful"),
79 Precompile::StatefulMut(_) => f.write_str("StatefulMut"),
80 }
81 }
82}
83
84impl Precompile {
85 pub fn new_stateful<P: StatefulPrecompile + 'static>(p: P) -> Self {
87 Self::Stateful(Arc::new(p))
88 }
89
90 pub fn new_stateful_mut<P: StatefulPrecompileMut + 'static>(p: P) -> Self {
92 Self::StatefulMut(Box::new(p))
93 }
94
95 pub fn call(&mut self, bytes: &Bytes, gas_price: u64, env: &Env) -> PrecompileResult {
97 match self {
98 Precompile::Standard(p) => p(bytes, gas_price),
99 Precompile::Env(p) => p(bytes, gas_price, env),
100 Precompile::Stateful(p) => p.call(bytes, gas_price, env),
101 Precompile::StatefulMut(p) => p.call_mut(bytes, gas_price, env),
102 }
103 }
104}
105
106#[derive(Clone, Debug, PartialEq, Eq, Hash)]
107pub enum PrecompileError {
108 OutOfGas,
110 Blake2WrongLength,
112 Blake2WrongFinalIndicatorFlag,
113 ModexpExpOverflow,
115 ModexpBaseOverflow,
116 ModexpModOverflow,
117 Bn128FieldPointNotAMember,
119 Bn128AffineGFailedToCreate,
120 Bn128PairLength,
121 BlobInvalidInputLength,
124 BlobMismatchedVersion,
126 BlobVerifyKzgProofFailed,
128 Other(String),
130}
131
132impl PrecompileError {
133 pub fn other(err: impl Into<String>) -> Self {
134 Self::Other(err.into())
135 }
136}
137
138#[cfg(feature = "std")]
139impl std::error::Error for PrecompileError {}
140
141impl fmt::Display for PrecompileError {
142 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
143 let s = match self {
144 Self::OutOfGas => "out of gas",
145 Self::Blake2WrongLength => "wrong input length for blake2",
146 Self::Blake2WrongFinalIndicatorFlag => "wrong final indicator flag for blake2",
147 Self::ModexpExpOverflow => "modexp exp overflow",
148 Self::ModexpBaseOverflow => "modexp base overflow",
149 Self::ModexpModOverflow => "modexp mod overflow",
150 Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve",
151 Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve",
152 Self::Bn128PairLength => "bn128 invalid pair length",
153 Self::BlobInvalidInputLength => "invalid blob input length",
154 Self::BlobMismatchedVersion => "mismatched blob version",
155 Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed",
156 Self::Other(s) => s,
157 };
158 f.write_str(s)
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165
166 #[test]
167 fn stateful_precompile_mut() {
168 #[derive(Default, Clone)]
169 struct MyPrecompile {}
170
171 impl StatefulPrecompileMut for MyPrecompile {
172 fn call_mut(
173 &mut self,
174 _bytes: &Bytes,
175 _gas_price: u64,
176 _env: &Env,
177 ) -> PrecompileResult {
178 PrecompileResult::Err(PrecompileError::OutOfGas)
179 }
180 }
181
182 let mut p = Precompile::new_stateful_mut(MyPrecompile::default());
183 match &mut p {
184 Precompile::StatefulMut(p) => {
185 let _ = p.call_mut(&Bytes::new(), 0, &Env::default());
186 }
187 _ => panic!("not a state"),
188 }
189 }
190}