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 primitives;
27
28pub use id::PrecompileId;
29pub use interface::*;
30
31use core::fmt::{self, Debug};
32
33cfg_if::cfg_if! {
35 if #[cfg(feature = "bn")]{
36 use ark_bn254 as _;
37 use ark_ff as _;
38 use ark_ec as _;
39 use ark_serialize as _;
40 }
41}
42
43use arrayref as _;
44
45cfg_if::cfg_if! {
47 if #[cfg(feature = "blst")]{
48 use ark_bls12_381 as _;
49 use ark_ff as _;
50 use ark_ec as _;
51 use ark_serialize as _;
52 }
53}
54
55#[cfg(feature = "gmp")]
57use aurora_engine_modexp as _;
58
59#[cfg(feature = "p256-aws-lc-rs")]
61use p256 as _;
62
63use core::hash::Hash;
64use primitives::{
65 hardfork::SpecId, short_address, Address, AddressMap, AddressSet, HashMap, OnceLock,
66 SHORT_ADDRESS_CAP,
67};
68use std::vec::Vec;
69
70#[inline]
72pub fn calc_linear_cost(len: usize, base: u64, word: u64) -> u64 {
73 (len as u64).div_ceil(32) * word + base
74}
75
76#[deprecated(note = "please use `calc_linear_cost` instead")]
78pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
79 calc_linear_cost(len, base, word)
80}
81
82#[derive(Clone, Debug)]
84pub struct Precompiles {
85 inner: AddressMap<Precompile>,
87 addresses: AddressSet,
89 optimized_access: Vec<Option<Precompile>>,
91 all_short_addresses: bool,
93}
94
95impl Default for Precompiles {
96 fn default() -> Self {
97 Self {
98 inner: HashMap::default(),
99 addresses: AddressSet::default(),
100 optimized_access: vec![None; SHORT_ADDRESS_CAP],
101 all_short_addresses: true,
102 }
103 }
104}
105
106impl Precompiles {
107 pub fn new(spec: PrecompileSpecId) -> &'static Self {
109 match spec {
110 PrecompileSpecId::HOMESTEAD => Self::homestead(),
111 PrecompileSpecId::BYZANTIUM => Self::byzantium(),
112 PrecompileSpecId::ISTANBUL => Self::istanbul(),
113 PrecompileSpecId::BERLIN => Self::berlin(),
114 PrecompileSpecId::CANCUN => Self::cancun(),
115 PrecompileSpecId::PRAGUE => Self::prague(),
116 PrecompileSpecId::OSAKA => Self::osaka(),
117 }
118 }
119
120 pub fn homestead() -> &'static Self {
122 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
123 INSTANCE.get_or_init(|| {
124 let mut precompiles = Precompiles::default();
125 precompiles.extend([
126 secp256k1::ECRECOVER,
127 hash::SHA256,
128 hash::RIPEMD160,
129 identity::FUN,
130 ]);
131 precompiles
132 })
133 }
134
135 pub fn inner(&self) -> &AddressMap<Precompile> {
137 &self.inner
138 }
139
140 pub fn byzantium() -> &'static Self {
142 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
143 INSTANCE.get_or_init(|| {
144 let mut precompiles = Self::homestead().clone();
145 precompiles.extend([
146 modexp::BYZANTIUM,
148 bn254::add::BYZANTIUM,
151 bn254::mul::BYZANTIUM,
152 bn254::pair::BYZANTIUM,
153 ]);
154 precompiles
155 })
156 }
157
158 pub fn istanbul() -> &'static Self {
160 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
161 INSTANCE.get_or_init(|| {
162 let mut precompiles = Self::byzantium().clone();
163 precompiles.extend([
164 bn254::add::ISTANBUL,
166 bn254::mul::ISTANBUL,
167 bn254::pair::ISTANBUL,
168 blake2::FUN,
170 ]);
171 precompiles
172 })
173 }
174
175 pub fn berlin() -> &'static Self {
177 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
178 INSTANCE.get_or_init(|| {
179 let mut precompiles = Self::istanbul().clone();
180 precompiles.extend([
181 modexp::BERLIN,
183 ]);
184 precompiles
185 })
186 }
187
188 pub fn cancun() -> &'static Self {
193 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
194 INSTANCE.get_or_init(|| {
195 let mut precompiles = Self::berlin().clone();
196 precompiles.extend([
197 kzg_point_evaluation::POINT_EVALUATION,
199 ]);
200 precompiles
201 })
202 }
203
204 pub fn prague() -> &'static Self {
206 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
207 INSTANCE.get_or_init(|| {
208 let mut precompiles = Self::cancun().clone();
209 precompiles.extend(bls12_381::precompiles());
210 precompiles
211 })
212 }
213
214 pub fn osaka() -> &'static Self {
216 static INSTANCE: OnceLock<Precompiles> = OnceLock::new();
217 INSTANCE.get_or_init(|| {
218 let mut precompiles = Self::prague().clone();
219 precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]);
220 precompiles
221 })
222 }
223
224 pub fn latest() -> &'static Self {
226 Self::osaka()
227 }
228
229 #[inline]
231 pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
232 self.inner.keys()
233 }
234
235 #[inline]
237 pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
238 self.inner.into_keys()
239 }
240
241 #[inline]
243 pub fn contains(&self, address: &Address) -> bool {
244 self.inner.contains_key(address)
245 }
246
247 #[inline]
249 pub fn get(&self, address: &Address) -> Option<&Precompile> {
250 if let Some(short_address) = short_address(address) {
251 return self.optimized_access[short_address].as_ref();
252 }
253 self.inner.get(address)
254 }
255
256 #[inline]
258 pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
259 self.inner.get_mut(address)
260 }
261
262 pub fn is_empty(&self) -> bool {
264 self.inner.is_empty()
265 }
266
267 pub fn len(&self) -> usize {
269 self.inner.len()
270 }
271
272 pub fn addresses_set(&self) -> &AddressSet {
274 &self.addresses
275 }
276
277 #[inline]
281 pub fn extend(&mut self, other: impl IntoIterator<Item = Precompile>) {
282 let iter = other.into_iter();
283 let (lower, _) = iter.size_hint();
284 self.addresses.reserve(lower);
285 self.inner.reserve(lower);
286 for item in iter {
287 let address = *item.address();
288 if let Some(short_idx) = short_address(&address) {
289 self.optimized_access[short_idx] = Some(item.clone());
290 } else {
291 self.all_short_addresses = false;
292 }
293 self.addresses.insert(address);
294 self.inner.insert(address, item);
295 }
296 }
297
298 pub fn difference(&self, other: &Self) -> Self {
302 let Self { inner, .. } = self;
303
304 let inner = inner
305 .iter()
306 .filter(|(a, _)| !other.inner.contains_key(*a))
307 .map(|(a, p)| (*a, p.clone()))
308 .collect::<AddressMap<_>>();
309
310 let mut precompiles = Self::default();
311 precompiles.extend(inner.into_iter().map(|p| p.1));
312 precompiles
313 }
314
315 pub fn intersection(&self, other: &Self) -> Self {
319 let Self { inner, .. } = self;
320
321 let inner = inner
322 .iter()
323 .filter(|(a, _)| other.inner.contains_key(*a))
324 .map(|(a, p)| (*a, p.clone()))
325 .collect::<AddressMap<_>>();
326
327 let mut precompiles = Self::default();
328 precompiles.extend(inner.into_iter().map(|p| p.1));
329 precompiles
330 }
331}
332
333#[derive(Clone)]
335pub struct Precompile {
336 id: PrecompileId,
338 address: Address,
340 fn_: PrecompileFn,
342}
343
344impl Debug for Precompile {
345 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
346 write!(
347 f,
348 "Precompile {{ id: {:?}, address: {:?} }}",
349 self.id, self.address
350 )
351 }
352}
353
354impl From<(PrecompileId, Address, PrecompileFn)> for Precompile {
355 fn from((id, address, fn_): (PrecompileId, Address, PrecompileFn)) -> Self {
356 Precompile { id, address, fn_ }
357 }
358}
359
360impl From<Precompile> for (PrecompileId, Address) {
361 fn from(value: Precompile) -> Self {
362 (value.id, value.address)
363 }
364}
365
366impl Precompile {
367 pub const fn new(id: PrecompileId, address: Address, fn_: PrecompileFn) -> Self {
369 Self { id, address, fn_ }
370 }
371
372 #[inline]
374 pub fn id(&self) -> &PrecompileId {
375 &self.id
376 }
377
378 #[inline]
380 pub fn address(&self) -> &Address {
381 &self.address
382 }
383
384 #[inline]
389 pub fn execute(&self, input: &[u8], gas_limit: u64, reservoir: u64) -> PrecompileResult {
390 (self.fn_)(input, gas_limit, reservoir)
391 }
392}
393
394#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
396pub enum PrecompileSpecId {
397 HOMESTEAD,
399 BYZANTIUM,
404 ISTANBUL,
409 BERLIN,
412 CANCUN,
415 PRAGUE,
424 OSAKA,
428}
429
430impl From<SpecId> for PrecompileSpecId {
431 fn from(spec_id: SpecId) -> Self {
432 Self::from_spec_id(spec_id)
433 }
434}
435
436impl PrecompileSpecId {
437 pub const fn from_spec_id(spec_id: primitives::hardfork::SpecId) -> Self {
439 use primitives::hardfork::SpecId::*;
440 match spec_id {
441 FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
442 Self::HOMESTEAD
443 }
444 BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
445 ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
446 BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
447 CANCUN => Self::CANCUN,
448 PRAGUE => Self::PRAGUE,
449 OSAKA | AMSTERDAM => Self::OSAKA,
450 }
451 }
452}
453
454#[inline]
460pub const fn u64_to_address(x: u64) -> Address {
461 let x = x.to_be_bytes();
462 Address::new([
463 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],
464 ])
465}
466
467#[cfg(test)]
468mod test {
469 use super::*;
470
471 fn temp_precompile(_input: &[u8], _gas_limit: u64, reservoir: u64) -> PrecompileResult {
472 Ok(PrecompileOutput::halt(PrecompileHalt::OutOfGas, reservoir))
473 }
474
475 #[test]
476 fn test_optimized_access() {
477 let mut precompiles = Precompiles::istanbul().clone();
478 assert!(precompiles.optimized_access[9].is_some());
479 assert!(precompiles.optimized_access[10].is_none());
480
481 precompiles.extend([Precompile::new(
482 PrecompileId::Custom("test".into()),
483 u64_to_address(100),
484 temp_precompile,
485 )]);
486 precompiles.extend([Precompile::new(
487 PrecompileId::Custom("test".into()),
488 u64_to_address(101),
489 temp_precompile,
490 )]);
491
492 let output = precompiles.optimized_access[100]
493 .as_ref()
494 .unwrap()
495 .execute(&[], u64::MAX, 0)
496 .unwrap();
497 assert!(matches!(
498 output.status,
499 PrecompileStatus::Halt(PrecompileHalt::OutOfGas)
500 ));
501
502 let output = precompiles
503 .get(&Address::left_padding_from(&[101]))
504 .unwrap()
505 .execute(&[], u64::MAX, 0)
506 .unwrap();
507 assert!(matches!(
508 output.status,
509 PrecompileStatus::Halt(PrecompileHalt::OutOfGas)
510 ));
511 }
512
513 #[test]
514 fn test_difference_precompile_sets() {
515 let difference = Precompiles::istanbul().difference(Precompiles::berlin());
516 assert!(difference.is_empty());
517 }
518
519 #[test]
520 fn test_intersection_precompile_sets() {
521 let intersection = Precompiles::homestead().intersection(Precompiles::byzantium());
522
523 assert_eq!(intersection.len(), 4)
524 }
525}