use crate::{
precompile::{Precompile, PrecompileResult},
primitives::{db::Database, Address, Bytes, HashMap},
};
use core::ops::{Deref, DerefMut};
use dyn_clone::DynClone;
use revm_precompile::Precompiles;
use std::{boxed::Box, sync::Arc};
use super::InnerEvmContext;
pub enum ContextPrecompile<DB: Database> {
Ordinary(Precompile),
ContextStateful(ContextStatefulPrecompileArc<DB>),
ContextStatefulMut(ContextStatefulPrecompileBox<DB>),
}
impl<DB: Database> Clone for ContextPrecompile<DB> {
fn clone(&self) -> Self {
match self {
Self::Ordinary(arg0) => Self::Ordinary(arg0.clone()),
Self::ContextStateful(arg0) => Self::ContextStateful(arg0.clone()),
Self::ContextStatefulMut(arg0) => Self::ContextStatefulMut(arg0.clone()),
}
}
}
#[derive(Clone)]
pub struct ContextPrecompiles<DB: Database> {
inner: HashMap<Address, ContextPrecompile<DB>>,
}
impl<DB: Database> ContextPrecompiles<DB> {
#[inline]
pub fn addresses(&self) -> impl Iterator<Item = &Address> {
self.inner.keys()
}
#[inline]
pub fn extend(
&mut self,
other: impl IntoIterator<Item = impl Into<(Address, ContextPrecompile<DB>)>>,
) {
self.inner.extend(other.into_iter().map(Into::into));
}
#[inline]
pub fn call(
&mut self,
addess: Address,
bytes: &Bytes,
gas_price: u64,
evmctx: &mut InnerEvmContext<DB>,
) -> Option<PrecompileResult> {
let precompile = self.inner.get_mut(&addess)?;
match precompile {
ContextPrecompile::Ordinary(p) => Some(p.call(bytes, gas_price, &evmctx.env)),
ContextPrecompile::ContextStatefulMut(p) => Some(p.call_mut(bytes, gas_price, evmctx)),
ContextPrecompile::ContextStateful(p) => Some(p.call(bytes, gas_price, evmctx)),
}
}
}
impl<DB: Database> Default for ContextPrecompiles<DB> {
fn default() -> Self {
Self {
inner: Default::default(),
}
}
}
impl<DB: Database> Deref for ContextPrecompiles<DB> {
type Target = HashMap<Address, ContextPrecompile<DB>>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}
impl<DB: Database> DerefMut for ContextPrecompiles<DB> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.inner
}
}
pub trait ContextStatefulPrecompile<DB: Database>: Sync + Send {
fn call(
&self,
bytes: &Bytes,
gas_price: u64,
evmctx: &mut InnerEvmContext<DB>,
) -> PrecompileResult;
}
pub trait ContextStatefulPrecompileMut<DB: Database>: DynClone + Send + Sync {
fn call_mut(
&mut self,
bytes: &Bytes,
gas_price: u64,
evmctx: &mut InnerEvmContext<DB>,
) -> PrecompileResult;
}
dyn_clone::clone_trait_object!(<DB> ContextStatefulPrecompileMut<DB>);
pub type ContextStatefulPrecompileArc<DB> = Arc<dyn ContextStatefulPrecompile<DB>>;
pub type ContextStatefulPrecompileBox<DB> = Box<dyn ContextStatefulPrecompileMut<DB>>;
impl<DB: Database> From<Precompile> for ContextPrecompile<DB> {
fn from(p: Precompile) -> Self {
ContextPrecompile::Ordinary(p)
}
}
impl<DB: Database> From<Precompiles> for ContextPrecompiles<DB> {
fn from(p: Precompiles) -> Self {
ContextPrecompiles {
inner: p.inner.into_iter().map(|(k, v)| (k, v.into())).collect(),
}
}
}
impl<DB: Database> From<&Precompiles> for ContextPrecompiles<DB> {
fn from(p: &Precompiles) -> Self {
ContextPrecompiles {
inner: p
.inner
.iter()
.map(|(&k, v)| (k, v.clone().into()))
.collect(),
}
}
}