1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
5#![cfg_attr(not(feature = "std"), no_std)]
6
7#[macro_use]
8#[cfg(not(feature = "std"))]
9extern crate alloc as std;
10
11pub mod blake2;
12#[cfg(feature = "blst")]
13pub mod bls12_381;
14pub mod bn128;
15pub mod fatal_precompile;
16pub mod hash;
17pub mod identity;
18#[cfg(any(feature = "c-kzg", feature = "kzg-rs"))]
19pub mod kzg_point_evaluation;
20pub mod modexp;
21pub mod secp256k1;
22#[cfg(feature = "secp256r1")]
23pub mod secp256r1;
24pub mod utilities;
25
26pub use fatal_precompile::fatal_precompile;
27
28#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))]
29use kzg_rs as _;
31pub use primitives::{
32 precompile::{PrecompileError as Error, *},
33 Address, Bytes, HashMap, HashSet, Log, B256,
34};
35#[doc(hidden)]
36pub use revm_primitives as primitives;
37
38use cfg_if::cfg_if;
39use core::hash::Hash;
40use once_cell::race::OnceBox;
41use std::{boxed::Box, vec::Vec};
42
43pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
44 (len as u64).div_ceil(32) * word + base
45}
46
47#[derive(Clone, Default, Debug)]
48pub struct Precompiles {
49 inner: HashMap<Address, Precompile>,
51 addresses: HashSet<Address>,
53}
54
55impl Precompiles {
56 pub fn new(spec: PrecompileSpecId) -> &'static Self {
58 match spec {
59 PrecompileSpecId::HOMESTEAD => Self::homestead(),
60 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
61 PrecompileSpecId::ISTANBUL => Self::istanbul(),
62 PrecompileSpecId::BERLIN => Self::berlin(),
63 PrecompileSpecId::CANCUN => Self::cancun(),
64 PrecompileSpecId::PRAGUE => Self::prague(),
65 PrecompileSpecId::LATEST => Self::latest(),
66 }
67 }
68
69 pub fn homestead() -> &'static Self {
71 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
72 INSTANCE.get_or_init(|| {
73 let mut precompiles = Precompiles::default();
74 precompiles.extend([
75 secp256k1::ECRECOVER,
76 hash::SHA256,
77 hash::RIPEMD160,
78 identity::FUN,
79 ]);
80 Box::new(precompiles)
81 })
82 }
83
84 pub fn inner(&self) -> &HashMap<Address, Precompile> {
86 &self.inner
87 }
88
89 pub fn byzantium() -> &'static Self {
91 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
92 INSTANCE.get_or_init(|| {
93 let mut precompiles = Self::homestead().clone();
94 precompiles.extend([
95 bn128::add::BYZANTIUM,
98 bn128::mul::BYZANTIUM,
99 bn128::pair::BYZANTIUM,
100 modexp::BYZANTIUM,
102 ]);
103 Box::new(precompiles)
104 })
105 }
106
107 pub fn istanbul() -> &'static Self {
109 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
110 INSTANCE.get_or_init(|| {
111 let mut precompiles = Self::byzantium().clone();
112 precompiles.extend([
113 bn128::add::ISTANBUL,
115 bn128::mul::ISTANBUL,
116 bn128::pair::ISTANBUL,
117 blake2::FUN,
119 ]);
120 Box::new(precompiles)
121 })
122 }
123
124 pub fn berlin() -> &'static Self {
126 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
127 INSTANCE.get_or_init(|| {
128 let mut precompiles = Self::istanbul().clone();
129 precompiles.extend([
130 modexp::BERLIN,
132 ]);
133 Box::new(precompiles)
134 })
135 }
136
137 pub fn cancun() -> &'static Self {
142 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
143 INSTANCE.get_or_init(|| {
144 let mut precompiles = Self::berlin().clone();
145
146 cfg_if! {
148 if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
149 let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
150 } else {
151 let precompile = fatal_precompile(u64_to_address(0x0A), "c-kzg feature is not enabled".into());
153 }
154 }
155
156 precompiles.extend([
157 precompile,
158 ]);
159
160 Box::new(precompiles)
161 })
162 }
163
164 pub fn prague() -> &'static Self {
166 static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
167 INSTANCE.get_or_init(|| {
168 let precompiles = Self::cancun().clone();
169
170 #[cfg(feature = "blst")]
172 let precompiles = {
173 let mut precompiles = precompiles;
174 precompiles.extend(bls12_381::precompiles());
175 precompiles
176 };
177
178 Box::new(precompiles)
179 })
180 }
181
182 pub fn latest() -> &'static Self {
184 Self::prague()
185 }
186
187 #[inline]
189 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
190 self.inner.keys()
191 }
192
193 #[inline]
195 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
196 self.inner.into_keys()
197 }
198
199 #[inline]
201 pub fn contains(&self, address: &Address) -> bool {
202 self.inner.contains_key(address)
203 }
204
205 #[inline]
207 pub fn get(&self, address: &Address) -> Option<&Precompile> {
208 self.inner.get(address)
209 }
210
211 #[inline]
213 pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
214 self.inner.get_mut(address)
215 }
216
217 pub fn is_empty(&self) -> bool {
219 self.inner.len() == 0
220 }
221
222 pub fn len(&self) -> usize {
224 self.inner.len()
225 }
226
227 pub fn addresses_set(&self) -> &HashSet<Address> {
229 &self.addresses
230 }
231
232 #[inline]
236 pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
237 let items = other.into_iter().collect::<Vec<_>>();
238 self.addresses.extend(items.iter().map(|p| *p.address()));
239 self.inner.extend(items.into_iter().map(Into::into));
240 }
241}
242
243#[derive(Clone, Debug)]
244pub struct PrecompileWithAddress(pub Address, pub Precompile);
245
246impl From<(Address, Precompile)> for PrecompileWithAddress {
247 fn from(value: (Address, Precompile)) -> Self {
248 PrecompileWithAddress(value.0, value.1)
249 }
250}
251
252impl From<PrecompileWithAddress> for (Address, Precompile) {
253 fn from(value: PrecompileWithAddress) -> Self {
254 (value.0, value.1)
255 }
256}
257
258impl PrecompileWithAddress {
259 #[inline]
261 pub fn address(&self) -> &Address {
262 &self.0
263 }
264
265 #[inline]
267 pub fn precompile(&self) -> &Precompile {
268 &self.1
269 }
270}
271
272#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
273pub enum PrecompileSpecId {
274 HOMESTEAD,
275 BYZANTIUM,
276 ISTANBUL,
277 BERLIN,
278 CANCUN,
279 PRAGUE,
280 LATEST,
281}
282
283impl PrecompileSpecId {
284 pub const fn from_spec_id(spec_id: revm_primitives::SpecId) -> Self {
286 use revm_primitives::SpecId::*;
287 match spec_id {
288 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
289 Self::HOMESTEAD
290 }
291 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
292 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
293 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
294 CANCUN => Self::CANCUN,
295 PRAGUE | OSAKA => Self::PRAGUE,
296 LATEST => Self::LATEST,
297 #[cfg(feature = "optimism")]
298 BEDROCK | REGOLITH | CANYON => Self::BERLIN,
299 #[cfg(feature = "optimism")]
300 ECOTONE | FJORD | GRANITE | HOLOCENE => Self::CANCUN,
301 }
302 }
303}
304
305#[inline]
310pub const fn u64_to_address(x: u64) -> Address {
311 let x = x.to_be_bytes();
312 Address::new([
313 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],
314 ])
315}