#![cfg_attr(not(test), warn(unused_crate_dependencies))]
#![cfg_attr(not(feature = "std"), no_std)]
#[macro_use]
#[cfg(not(feature = "std"))]
extern crate alloc as std;
pub mod blake2;
#[cfg(feature = "blst")]
pub mod bls12_381;
pub mod bn128;
pub mod fatal_precompile;
pub mod hash;
pub mod identity;
#[cfg(any(feature = "c-kzg", feature = "kzg-rs"))]
pub mod kzg_point_evaluation;
pub mod modexp;
pub mod secp256k1;
#[cfg(feature = "secp256r1")]
pub mod secp256r1;
pub mod utilities;
pub use fatal_precompile::fatal_precompile;
#[cfg(all(feature = "c-kzg", feature = "kzg-rs"))]
use kzg_rs as _;
pub use primitives::{
precompile::{PrecompileError as Error, *},
Address, Bytes, HashMap, HashSet, Log, B256,
};
#[doc(hidden)]
pub use revm_primitives as primitives;
use cfg_if::cfg_if;
use core::hash::Hash;
use once_cell::race::OnceBox;
use std::{boxed::Box, vec::Vec};
pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 {
(len as u64).div_ceil(32) * word + base
}
#[derive(Clone, Default, Debug)]
pub struct Precompiles {
inner: HashMap<Address, Precompile>,
addresses: HashSet<Address>,
}
impl Precompiles {
pub fn new(spec: PrecompileSpecId) -> &'static Self {
match spec {
PrecompileSpecId::HOMESTEAD => Self::homestead(),
PrecompileSpecId::BYZANTIUM => Self::byzantium(),
PrecompileSpecId::ISTANBUL => Self::istanbul(),
PrecompileSpecId::BERLIN => Self::berlin(),
PrecompileSpecId::CANCUN => Self::cancun(),
PrecompileSpecId::PRAGUE => Self::prague(),
PrecompileSpecId::LATEST => Self::latest(),
}
}
pub fn homestead() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Precompiles::default();
precompiles.extend([
secp256k1::ECRECOVER,
hash::SHA256,
hash::RIPEMD160,
identity::FUN,
]);
Box::new(precompiles)
})
}
pub fn inner(&self) -> &HashMap<Address, Precompile> {
&self.inner
}
pub fn byzantium() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Self::homestead().clone();
precompiles.extend([
bn128::add::BYZANTIUM,
bn128::mul::BYZANTIUM,
bn128::pair::BYZANTIUM,
modexp::BYZANTIUM,
]);
Box::new(precompiles)
})
}
pub fn istanbul() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Self::byzantium().clone();
precompiles.extend([
bn128::add::ISTANBUL,
bn128::mul::ISTANBUL,
bn128::pair::ISTANBUL,
blake2::FUN,
]);
Box::new(precompiles)
})
}
pub fn berlin() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Self::istanbul().clone();
precompiles.extend([
modexp::BERLIN,
]);
Box::new(precompiles)
})
}
pub fn cancun() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let mut precompiles = Self::berlin().clone();
cfg_if! {
if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] {
let precompile = kzg_point_evaluation::POINT_EVALUATION.clone();
} else {
let precompile = fatal_precompile(u64_to_address(0x0A), "c-kzg feature is not enabled".into());
}
}
precompiles.extend([
precompile,
]);
Box::new(precompiles)
})
}
pub fn prague() -> &'static Self {
static INSTANCE: OnceBox<Precompiles> = OnceBox::new();
INSTANCE.get_or_init(|| {
let precompiles = Self::cancun().clone();
#[cfg(feature = "blst")]
let precompiles = {
let mut precompiles = precompiles;
precompiles.extend(bls12_381::precompiles());
precompiles
};
Box::new(precompiles)
})
}
pub fn latest() -> &'static Self {
Self::prague()
}
#[inline]
pub fn addresses(&self) -> impl ExactSizeIterator<Item = &Address> {
self.inner.keys()
}
#[inline]
pub fn into_addresses(self) -> impl ExactSizeIterator<Item = Address> {
self.inner.into_keys()
}
#[inline]
pub fn contains(&self, address: &Address) -> bool {
self.inner.contains_key(address)
}
#[inline]
pub fn get(&self, address: &Address) -> Option<&Precompile> {
self.inner.get(address)
}
#[inline]
pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> {
self.inner.get_mut(address)
}
pub fn is_empty(&self) -> bool {
self.inner.len() == 0
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn addresses_set(&self) -> &HashSet<Address> {
&self.addresses
}
#[inline]
pub fn extend(&mut self, other: impl IntoIterator<Item = PrecompileWithAddress>) {
let items = other.into_iter().collect::<Vec<_>>();
self.addresses.extend(items.iter().map(|p| *p.address()));
self.inner.extend(items.into_iter().map(Into::into));
}
}
#[derive(Clone, Debug)]
pub struct PrecompileWithAddress(pub Address, pub Precompile);
impl From<(Address, Precompile)> for PrecompileWithAddress {
fn from(value: (Address, Precompile)) -> Self {
PrecompileWithAddress(value.0, value.1)
}
}
impl From<PrecompileWithAddress> for (Address, Precompile) {
fn from(value: PrecompileWithAddress) -> Self {
(value.0, value.1)
}
}
impl PrecompileWithAddress {
#[inline]
pub fn address(&self) -> &Address {
&self.0
}
#[inline]
pub fn precompile(&self) -> &Precompile {
&self.1
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)]
pub enum PrecompileSpecId {
HOMESTEAD,
BYZANTIUM,
ISTANBUL,
BERLIN,
CANCUN,
PRAGUE,
LATEST,
}
impl PrecompileSpecId {
pub const fn from_spec_id(spec_id: revm_primitives::SpecId) -> Self {
use revm_primitives::SpecId::*;
match spec_id {
FRONTIER | FRONTIER_THAWING | HOMESTEAD | DAO_FORK | TANGERINE | SPURIOUS_DRAGON => {
Self::HOMESTEAD
}
BYZANTIUM | CONSTANTINOPLE | PETERSBURG => Self::BYZANTIUM,
ISTANBUL | MUIR_GLACIER => Self::ISTANBUL,
BERLIN | LONDON | ARROW_GLACIER | GRAY_GLACIER | MERGE | SHANGHAI => Self::BERLIN,
CANCUN => Self::CANCUN,
PRAGUE | OSAKA => Self::PRAGUE,
LATEST => Self::LATEST,
#[cfg(feature = "optimism")]
BEDROCK | REGOLITH | CANYON => Self::BERLIN,
#[cfg(feature = "optimism")]
ECOTONE | FJORD | GRANITE | HOLOCENE => Self::CANCUN,
}
}
}
#[inline]
pub const fn u64_to_address(x: u64) -> Address {
let x = x.to_be_bytes();
Address::new([
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],
])
}