1#![warn(rustdoc::all)]
5#![cfg_attr(not(test), warn(unused_crate_dependencies))]
6#![deny(unused_must_use, rust_2018_idioms)]
7#![cfg_attr(not(feature = "std"), no_std)]
8
9#[macro_use]
10#[cfg(not(feature = "std"))]
11extern crate alloc as std;
12
13pub mod blake2;
14pub mod bn128;
15pub mod hash;
16pub mod identity;
17#[cfg(feature = "c-kzg")]
18pub mod kzg_point_evaluation;
19pub mod modexp;
20pub mod secp256k1;
21pub mod utilities;
22
23use core::hash::Hash;
24use once_cell::race::OnceBox;
25#[doc(hidden)]
26pub use rtvm_primitives as primitives;
27pub use rtvm_primitives::{
28 precompile::{PrecompileError as Error, *},
29 Address, Bytes, HashMap, Log, B256,
30};
31use std::{boxed::Box, vec::Vec};
32
33pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
34 (len as u64 + 32 - 1) / 32 * word + base
35}
36
37#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
38pub struct PrecompileOutput {
39 pub cost: u64,
40 pub output: Vec<u8>,
41 pub logs: Vec<Log>,
42}
43
44impl PrecompileOutput {
45 pub fn without_logs(cost: u64, output: Vec<u8>) -> Self {
46 Self {
47 cost,
48 output,
49 logs: Vec::new(),
50 }
51 }
52}
53#[derive(Clone, Default, Debug)]
54pub struct Precompiles {
55 pub inner: HashMap<Address, Precompile>,
57}
58
59impl Precompiles {
60 pub fn new(spec: PrecompileSpecId) -> &'static Self {
62 match spec {
63 PrecompileSpecId::HOMESTEAD => Self::homestead(),
64 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
65 PrecompileSpecId::ISTANBUL => Self::istanbul(),
66 PrecompileSpecId::BERLIN => Self::berlin(),
67 PrecompileSpecId::CANCUN => Self::cancun(),
68 PrecompileSpecId::LATEST => Self::latest(),
69 }
70 }
71
72 pub fn homestead() -> &'static Self {
74 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
75 INSTANCE.get_or_init(|| {
76 let mut precompiles = Precompiles::default();
77 precompiles.extend([
78 secp256k1::ECRECOVER,
79 hash::SHA256,
80 hash::RIPEMD160,
81 identity::FUN,
82 ]);
83 Box::new(precompiles)
84 })
85 }
86
87 pub fn byzantium() -> &'static Self {
89 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
90 INSTANCE.get_or_init(|| {
91 let mut precompiles = Self::homestead().clone();
92 precompiles.extend([
93 bn128::add::BYZANTIUM,
96 bn128::mul::BYZANTIUM,
97 bn128::pair::BYZANTIUM,
98 modexp::BYZANTIUM,
100 ]);
101 Box::new(precompiles)
102 })
103 }
104
105 pub fn istanbul() -> &'static Self {
107 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
108 INSTANCE.get_or_init(|| {
109 let mut precompiles = Self::byzantium().clone();
110 precompiles.extend([
111 blake2::FUN,
113 bn128::add::ISTANBUL,
115 bn128::mul::ISTANBUL,
116 bn128::pair::ISTANBUL,
117 ]);
118 Box::new(precompiles)
119 })
120 }
121
122 pub fn berlin() -> &'static Self {
124 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
125 INSTANCE.get_or_init(|| {
126 let mut precompiles = Self::istanbul().clone();
127 precompiles.extend([
128 modexp::BERLIN,
130 ]);
131 Box::new(precompiles)
132 })
133 }
134
135 pub fn cancun() -> &'static Self {
140 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
141 INSTANCE.get_or_init(|| {
142 let precompiles = Self::berlin().clone();
143
144 #[cfg(feature = "c-kzg")]
146 let precompiles = {
147 let mut precompiles = precompiles;
148 precompiles.extend([
149 kzg_point_evaluation::POINT_EVALUATION,
151 ]);
152 precompiles
153 };
154
155 Box::new(precompiles)
156 })
157 }
158
159 pub fn latest() -> &'static Self {
161 Self::cancun()
162 }
163
164 #[inline]
166 pub fn addresses(&self) -> impl Iterator<Item = &Address> {
167 self.inner.keys()
168 }
169
170 #[inline]
172 pub fn into_addresses(self) -> impl Iterator<Item = Address> {
173 self.inner.into_keys()
174 }
175
176 #[inline]
178 pub fn contains(&self, address: &Address) -> bool {
179 self.inner.contains_key(address)
180 }
181
182 #[inline]
184 pub fn get(&self, address: &Address) -> Option<&Precompile> {
185 self.inner.get(address)
186 }
187
188 #[inline]
190 pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
191 self.inner.get_mut(address)
192 }
193
194 pub fn is_empty(&self) -> bool {
196 self.inner.len() == 0
197 }
198
199 pub fn len(&self) -> usize {
201 self.inner.len()
202 }
203
204 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
208 self.inner.extend(other.into_iter().map(Into::into));
209 }
210}
211
212#[derive(Clone, Debug)]
213pub struct PrecompileWithAddress(pub Address, pub Precompile);
214
215impl From<(Address, Precompile)> for PrecompileWithAddress {
216 fn from(value: (Address, Precompile)) -> Self {
217 PrecompileWithAddress(value.0, value.1)
218 }
219}
220
221impl From<PrecompileWithAddress> for (Address, Precompile) {
222 fn from(value: PrecompileWithAddress) -> Self {
223 (value.0, value.1)
224 }
225}
226
227#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
228pub enum PrecompileSpecId {
229 HOMESTEAD,
230 BYZANTIUM,
231 ISTANBUL,
232 BERLIN,
233 CANCUN,
234 LATEST,
235}
236
237impl PrecompileSpecId {
238 pub const fn from_spec_id(spec_id: rtvm_primitives::SpecId) -> Self {
240 use rtvm_primitives::SpecId::*;
241 match spec_id {
242 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
243 Self::HOMESTEAD
244 }
245 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
246 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
247 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
248 CANCUN | PRAGUE => Self::CANCUN,
249 LATEST => Self::LATEST,
250 #[cfg(feature = "optimism")]
251 BEDROCK | REGOLITH | CANYON => Self::BERLIN,
252 #[cfg(feature = "optimism")]
253 ECOTONE => Self::CANCUN,
254 }
255 }
256}
257
258#[inline]
263pub const fn u64_to_address(x: u64) -> Address {
264 let x = x.to_be_bytes();
265 Address::new([
266 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, x[0], x[1], x[2], x[3], x[4], x[5], x[6], x[7],
267 ])
268}