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;
12pub mod bls12_381;
13pub mod bls12_381_const;
14pub mod bls12_381_utils;
15pub mod bn254;
16pub mod hash;
17mod id;
18pub mod identity;
19pub mod interface;
20pub mod kzg_point_evaluation;
21pub mod modexp;
22pub mod secp256k1;
23pub mod secp256r1;
24pub mod utilities;
25
26pub use id::PrecompileId;
27pub use interface::*;
28
29cfg_if::cfg_if! {
31 if #[cfg(feature = "bn")]{
32 use ark_bn254 as _;
33 use ark_ff as _;
34 use ark_ec as _;
35 use ark_serialize as _;
36 }
37}
38
39use arrayref as _;
40
41cfg_if::cfg_if! {
43 if #[cfg(feature = "blst")]{
44 use ark_bls12_381 as _;
45 use ark_ff as _;
46 use ark_ec as _;
47 use ark_serialize as _;
48 }
49}
50
51#[cfg(feature = "gmp")]
53use aurora_engine_modexp as _;
54
55use core::hash::Hash;
56use primitives::{
57 hardfork::SpecId, short_address, Address, AddressMap, AddressSet, HashMap, OnceLock,
58 SHORT_ADDRESS_CAP,
59};
60use std::vec::Vec;
61
62#[inline]
64pub fn calc_linear_cost(len: usize, base: u64, word: u64) -> u64 {
65 (len as u64).div_ceil(32) * word + base
66}
67
68#[deprecated(note = "please use `calc_linear_cost` instead")]
70pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
71 calc_linear_cost(len, base, word)
72}
73
74#[derive(Clone, Debug)]
76pub struct Precompiles {
77 inner: AddressMap<Precompile>,
79 addresses: AddressSet,
81 optimized_access: Vec<Option<Precompile>>,
83 all_short_addresses: bool,
85}
86
87impl Default for Precompiles {
88 fn default() -> Self {
89 Self {
90 inner: HashMap::default(),
91 addresses: AddressSet::default(),
92 optimized_access: vec![None; SHORT_ADDRESS_CAP],
93 all_short_addresses: true,
94 }
95 }
96}
97
98impl Precompiles {
99 pub fn new(spec: PrecompileSpecId) -> &'static Self {
101 match spec {
102 PrecompileSpecId::HOMESTEAD => Self::homestead(),
103 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
104 PrecompileSpecId::ISTANBUL => Self::istanbul(),
105 PrecompileSpecId::BERLIN => Self::berlin(),
106 PrecompileSpecId::CANCUN => Self::cancun(),
107 PrecompileSpecId::PRAGUE => Self::prague(),
108 PrecompileSpecId::OSAKA => Self::osaka(),
109 }
110 }
111
112 pub fn homestead() -> &'static Self {
114 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
115 INSTANCE.get_or_init(|| {
116 let mut precompiles = Precompiles::default();
117 precompiles.extend([
118 secp256k1::ECRECOVER,
119 hash::SHA256,
120 hash::RIPEMD160,
121 identity::FUN,
122 ]);
123 precompiles
124 })
125 }
126
127 pub fn inner(&self) -> &AddressMap<Precompile> {
129 &self.inner
130 }
131
132 pub fn byzantium() -> &'static Self {
134 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
135 INSTANCE.get_or_init(|| {
136 let mut precompiles = Self::homestead().clone();
137 precompiles.extend([
138 modexp::BYZANTIUM,
140 bn254::add::BYZANTIUM,
143 bn254::mul::BYZANTIUM,
144 bn254::pair::BYZANTIUM,
145 ]);
146 precompiles
147 })
148 }
149
150 pub fn istanbul() -> &'static Self {
152 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
153 INSTANCE.get_or_init(|| {
154 let mut precompiles = Self::byzantium().clone();
155 precompiles.extend([
156 bn254::add::ISTANBUL,
158 bn254::mul::ISTANBUL,
159 bn254::pair::ISTANBUL,
160 blake2::FUN,
162 ]);
163 precompiles
164 })
165 }
166
167 pub fn berlin() -> &'static Self {
169 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
170 INSTANCE.get_or_init(|| {
171 let mut precompiles = Self::istanbul().clone();
172 precompiles.extend([
173 modexp::BERLIN,
175 ]);
176 precompiles
177 })
178 }
179
180 pub fn cancun() -> &'static Self {
185 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
186 INSTANCE.get_or_init(|| {
187 let mut precompiles = Self::berlin().clone();
188 precompiles.extend([
189 kzg_point_evaluation::POINT_EVALUATION,
191 ]);
192 precompiles
193 })
194 }
195
196 pub fn prague() -> &'static Self {
198 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
199 INSTANCE.get_or_init(|| {
200 let mut precompiles = Self::cancun().clone();
201 precompiles.extend(bls12_381::precompiles());
202 precompiles
203 })
204 }
205
206 pub fn osaka() -> &'static Self {
208 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
209 INSTANCE.get_or_init(|| {
210 let mut precompiles = Self::prague().clone();
211 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]);
212 precompiles
213 })
214 }
215
216 pub fn latest() -> &'static Self {
218 Self::osaka()
219 }
220
221 #[inline]
223 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
224 self.inner.keys()
225 }
226
227 #[inline]
229 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
230 self.inner.into_keys()
231 }
232
233 #[inline]
235 pub fn contains(&self, address: &Address) -> bool {
236 self.inner.contains_key(address)
237 }
238
239 #[inline]
241 pub fn get(&self, address: &Address) -> Option<&Precompile> {
242 if let Some(short_address) = short_address(address) {
243 return self.optimized_access[short_address].as_ref();
244 }
245 self.inner.get(address)
246 }
247
248 #[inline]
250 pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
251 self.inner.get_mut(address)
252 }
253
254 pub fn is_empty(&self) -> bool {
256 self.inner.is_empty()
257 }
258
259 pub fn len(&self) -> usize {
261 self.inner.len()
262 }
263
264 pub fn addresses_set(&self) -> &AddressSet {
266 &self.addresses
267 }
268
269 #[inline]
273 pub fn extend(&mut self, other: impl IntoIterator<Item = Precompile>) {
274 let iter = other.into_iter();
275 let (lower, _) = iter.size_hint();
276 self.addresses.reserve(lower);
277 self.inner.reserve(lower);
278 for item in iter {
279 let address = *item.address();
280 if let Some(short_idx) = short_address(&address) {
281 self.optimized_access[short_idx] = Some(item.clone());
282 } else {
283 self.all_short_addresses = false;
284 }
285 self.addresses.insert(address);
286 self.inner.insert(address, item);
287 }
288 }
289
290 pub fn difference(&self, other: &Self) -> Self {
294 let Self { inner, .. } = self;
295
296 let inner = inner
297 .iter()
298 .filter(|(a, _)| !other.inner.contains_key(*a))
299 .map(|(a, p)| (*a, p.clone()))
300 .collect::<AddressMap<_>>();
301
302 let mut precompiles = Self::default();
303 precompiles.extend(inner.into_iter().map(|p| p.1));
304 precompiles
305 }
306
307 pub fn intersection(&self, other: &Self) -> Self {
311 let Self { inner, .. } = self;
312
313 let inner = inner
314 .iter()
315 .filter(|(a, _)| other.inner.contains_key(*a))
316 .map(|(a, p)| (*a, p.clone()))
317 .collect::<AddressMap<_>>();
318
319 let mut precompiles = Self::default();
320 precompiles.extend(inner.into_iter().map(|p| p.1));
321 precompiles
322 }
323}
324
325#[derive(Clone, Debug)]
327pub struct Precompile {
328 id: PrecompileId,
330 address: Address,
332 fn_: PrecompileFn,
334}
335
336impl From<(PrecompileId, Address, PrecompileFn)> for Precompile {
337 fn from((id, address, fn_): (PrecompileId, Address, PrecompileFn)) -> Self {
338 Precompile { id, address, fn_ }
339 }
340}
341
342impl From<Precompile> for (PrecompileId, Address, PrecompileFn) {
343 fn from(value: Precompile) -> Self {
344 (value.id, value.address, value.fn_)
345 }
346}
347
348impl Precompile {
349 pub const fn new(id: PrecompileId, address: Address, fn_: PrecompileFn) -> Self {
351 Self { id, address, fn_ }
352 }
353
354 #[inline]
356 pub fn id(&self) -> &PrecompileId {
357 &self.id
358 }
359
360 #[inline]
362 pub fn address(&self) -> &Address {
363 &self.address
364 }
365
366 #[inline]
368 pub fn precompile(&self) -> &PrecompileFn {
369 &self.fn_
370 }
371
372 #[inline]
374 pub fn into_precompile(self) -> PrecompileFn {
375 self.fn_
376 }
377
378 #[inline]
380 pub fn execute(&self, input: &[u8], gas_limit: u64) -> PrecompileResult {
381 (self.fn_)(input, gas_limit)
382 }
383}
384
385#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
387pub enum PrecompileSpecId {
388 HOMESTEAD,
390 BYZANTIUM,
395 ISTANBUL,
400 BERLIN,
403 CANCUN,
406 PRAGUE,
415 OSAKA,
419}
420
421impl From<SpecId> for PrecompileSpecId {
422 fn from(spec_id: SpecId) -> Self {
423 Self::from_spec_id(spec_id)
424 }
425}
426
427impl PrecompileSpecId {
428 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
430 use primitives::hardfork::SpecId::*;
431 match spec_id {
432 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
433 Self::HOMESTEAD
434 }
435 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
436 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
437 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
438 CANCUN => Self::CANCUN,
439 PRAGUE => Self::PRAGUE,
440 OSAKA | AMSTERDAM => Self::OSAKA,
441 }
442 }
443}
444
445#[inline]
451pub const fn u64_to_address(x: u64) -> Address {
452 let x = x.to_be_bytes();
453 Address::new([
454 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],
455 ])
456}
457
458#[cfg(test)]
459mod test {
460 use super::*;
461
462 fn temp_precompile(_input: &[u8], _gas_limit: u64) -> PrecompileResult {
463 PrecompileResult::Err(PrecompileError::OutOfGas)
464 }
465
466 #[test]
467 fn test_optimized_access() {
468 let mut precompiles = Precompiles::istanbul().clone();
469 assert!(precompiles.optimized_access[9].is_some());
470 assert!(precompiles.optimized_access[10].is_none());
471
472 precompiles.extend([Precompile::new(
473 PrecompileId::Custom("test".into()),
474 u64_to_address(100),
475 temp_precompile,
476 )]);
477 precompiles.extend([Precompile::new(
478 PrecompileId::Custom("test".into()),
479 u64_to_address(101),
480 temp_precompile,
481 )]);
482
483 assert_eq!(
484 precompiles.optimized_access[100]
485 .as_ref()
486 .unwrap()
487 .execute(&[], u64::MAX),
488 PrecompileResult::Err(PrecompileError::OutOfGas)
489 );
490
491 assert_eq!(
492 precompiles
493 .get(&Address::left_padding_from(&[101]))
494 .unwrap()
495 .execute(&[], u64::MAX),
496 PrecompileResult::Err(PrecompileError::OutOfGas)
497 );
498 }
499
500 #[test]
501 fn test_difference_precompile_sets() {
502 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
503 assert!(difference.is_empty());
504 }
505
506 #[test]
507 fn test_intersection_precompile_sets() {
508 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
509
510 assert_eq!(intersection.len(), 4)
511 }
512}