Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix(precompiles): Allow exit precompiles to work in the standalone engine #473

Merged
merged 1 commit into from
Mar 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 62 additions & 41 deletions engine-precompiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ use crate::bn128::{Bn128Add, Bn128Mul, Bn128Pair};
use crate::hash::{RIPEMD160, SHA256};
use crate::identity::Identity;
use crate::modexp::ModExp;
use crate::native::{ExitToEthereum, ExitToNear};
use crate::native::{exit_to_ethereum, exit_to_near, ExitToEthereum, ExitToNear};
use crate::prelude::types::EthGas;
use crate::prelude::{Vec, H160, H256};
use crate::random::RandomSeed;
use crate::secp256k1::ECRecover;
use aurora_engine_sdk::io::IO;
use aurora_engine_types::{account_id::AccountId, types::Address, vec, BTreeMap, Box};
use evm::backend::Log;
use evm::executor;
Expand Down Expand Up @@ -101,9 +102,15 @@ impl HardFork for Istanbul {}

impl HardFork for Berlin {}

pub struct Precompiles(pub prelude::BTreeMap<Address, Box<dyn Precompile>>);
pub struct Precompiles<I> {
pub generic_precompiles: prelude::BTreeMap<Address, Box<dyn Precompile>>,
// Cannot be part of the generic precompiles because the `dyn` type-erasure messes with
// with the lifetime requirements on the type parameter `I`.
pub near_exit: ExitToNear<I>,
pub ethereum_exit: ExitToEthereum<I>,
}

impl executor::stack::PrecompileSet for Precompiles {
impl<I: IO + Copy> executor::stack::PrecompileSet for Precompiles<I> {
fn execute(
&self,
address: prelude::H160,
Expand All @@ -112,32 +119,32 @@ impl executor::stack::PrecompileSet for Precompiles {
context: &Context,
is_static: bool,
) -> Option<Result<executor::stack::PrecompileOutput, executor::stack::PrecompileFailure>> {
self.0.get(&Address::new(address)).map(|p| {
self.precompile_action(Address::new(address), |p| {
p.run(input, gas_limit.map(EthGas::new), context, is_static)
.map_err(|exit_status| executor::stack::PrecompileFailure::Error { exit_status })
})
}

fn is_precompile(&self, address: prelude::H160) -> bool {
self.0.contains_key(&Address::new(address))
self.precompile_action(Address::new(address), |_| true)
.unwrap_or(false)
}
}

pub struct PrecompileConstructorContext {
pub struct PrecompileConstructorContext<I> {
pub current_account_id: AccountId,
pub random_seed: H256,
pub predecessor_account_id: AccountId,
pub io: I,
}

impl Precompiles {
impl<I: IO + Copy> Precompiles<I> {
#[allow(dead_code)]
pub fn new_homestead(ctx: PrecompileConstructorContext) -> Self {
pub fn new_homestead(ctx: PrecompileConstructorContext<I>) -> Self {
let addresses = vec![
ECRecover::ADDRESS,
SHA256::ADDRESS,
RIPEMD160::ADDRESS,
ExitToNear::ADDRESS,
ExitToEthereum::ADDRESS,
RandomSeed::ADDRESS,
CurrentAccount::ADDRESS,
PredecessorAccount::ADDRESS,
Expand All @@ -146,19 +153,16 @@ impl Precompiles {
Box::new(ECRecover),
Box::new(SHA256),
Box::new(RIPEMD160),
Box::new(ExitToNear::new(ctx.current_account_id.clone())),
Box::new(ExitToEthereum::new(ctx.current_account_id.clone())),
Box::new(RandomSeed::new(ctx.random_seed)),
Box::new(CurrentAccount::new(ctx.current_account_id)),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id)),
Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id.clone())),
];
let map: BTreeMap<Address, Box<dyn Precompile>> = addresses.into_iter().zip(fun).collect();

Precompiles(map)
Self::with_generic_precompiles(map, ctx)
}

#[allow(dead_code)]
pub fn new_byzantium(ctx: PrecompileConstructorContext) -> Self {
pub fn new_byzantium(ctx: PrecompileConstructorContext<I>) -> Self {
let addresses = vec![
ECRecover::ADDRESS,
SHA256::ADDRESS,
Expand All @@ -168,8 +172,6 @@ impl Precompiles {
Bn128Add::<Byzantium>::ADDRESS,
Bn128Mul::<Byzantium>::ADDRESS,
Bn128Pair::<Byzantium>::ADDRESS,
ExitToNear::ADDRESS,
ExitToEthereum::ADDRESS,
RandomSeed::ADDRESS,
CurrentAccount::ADDRESS,
PredecessorAccount::ADDRESS,
Expand All @@ -183,18 +185,16 @@ impl Precompiles {
Box::new(Bn128Add::<Byzantium>::new()),
Box::new(Bn128Mul::<Byzantium>::new()),
Box::new(Bn128Pair::<Byzantium>::new()),
Box::new(ExitToNear::new(ctx.current_account_id.clone())),
Box::new(ExitToEthereum::new(ctx.current_account_id.clone())),
Box::new(RandomSeed::new(ctx.random_seed)),
Box::new(CurrentAccount::new(ctx.current_account_id)),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id)),
Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id.clone())),
];
let map: BTreeMap<Address, Box<dyn Precompile>> = addresses.into_iter().zip(fun).collect();

Precompiles(map)
Self::with_generic_precompiles(map, ctx)
}

pub fn new_istanbul(ctx: PrecompileConstructorContext) -> Self {
pub fn new_istanbul(ctx: PrecompileConstructorContext<I>) -> Self {
let addresses = vec![
ECRecover::ADDRESS,
SHA256::ADDRESS,
Expand All @@ -205,8 +205,6 @@ impl Precompiles {
Bn128Mul::<Istanbul>::ADDRESS,
Bn128Pair::<Istanbul>::ADDRESS,
Blake2F::ADDRESS,
ExitToNear::ADDRESS,
ExitToEthereum::ADDRESS,
RandomSeed::ADDRESS,
CurrentAccount::ADDRESS,
PredecessorAccount::ADDRESS,
Expand All @@ -221,18 +219,16 @@ impl Precompiles {
Box::new(Bn128Mul::<Istanbul>::new()),
Box::new(Bn128Pair::<Istanbul>::new()),
Box::new(Blake2F),
Box::new(ExitToNear::new(ctx.current_account_id.clone())),
Box::new(ExitToEthereum::new(ctx.current_account_id.clone())),
Box::new(RandomSeed::new(ctx.random_seed)),
Box::new(CurrentAccount::new(ctx.current_account_id)),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id)),
Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id.clone())),
];
let map: BTreeMap<Address, Box<dyn Precompile>> = addresses.into_iter().zip(fun).collect();

Precompiles(map)
Self::with_generic_precompiles(map, ctx)
}

pub fn new_berlin(ctx: PrecompileConstructorContext) -> Self {
pub fn new_berlin(ctx: PrecompileConstructorContext<I>) -> Self {
let addresses = vec![
ECRecover::ADDRESS,
SHA256::ADDRESS,
Expand All @@ -243,8 +239,6 @@ impl Precompiles {
Bn128Mul::<Istanbul>::ADDRESS,
Bn128Pair::<Istanbul>::ADDRESS,
Blake2F::ADDRESS,
ExitToNear::ADDRESS,
ExitToEthereum::ADDRESS,
RandomSeed::ADDRESS,
CurrentAccount::ADDRESS,
PredecessorAccount::ADDRESS,
Expand All @@ -259,21 +253,48 @@ impl Precompiles {
Box::new(Bn128Mul::<Istanbul>::new()),
Box::new(Bn128Pair::<Istanbul>::new()),
Box::new(Blake2F),
Box::new(ExitToNear::new(ctx.current_account_id.clone())),
Box::new(ExitToEthereum::new(ctx.current_account_id.clone())),
Box::new(RandomSeed::new(ctx.random_seed)),
Box::new(CurrentAccount::new(ctx.current_account_id)),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id)),
Box::new(CurrentAccount::new(ctx.current_account_id.clone())),
Box::new(PredecessorAccount::new(ctx.predecessor_account_id.clone())),
];
let map: BTreeMap<Address, Box<dyn Precompile>> = addresses.into_iter().zip(fun).collect();

Precompiles(map)
Self::with_generic_precompiles(map, ctx)
}

pub fn new_london(ctx: PrecompileConstructorContext) -> Self {
pub fn new_london(ctx: PrecompileConstructorContext<I>) -> Self {
// no precompile changes in London HF
Self::new_berlin(ctx)
}

fn with_generic_precompiles(
generic_precompiles: BTreeMap<Address, Box<dyn Precompile>>,
ctx: PrecompileConstructorContext<I>,
) -> Self {
let near_exit = ExitToNear::new(ctx.current_account_id.clone(), ctx.io);
let ethereum_exit = ExitToEthereum::new(ctx.current_account_id, ctx.io);

Self {
generic_precompiles,
near_exit,
ethereum_exit,
}
}

fn precompile_action<U, F: FnOnce(&dyn Precompile) -> U>(
&self,
address: Address,
f: F,
) -> Option<U> {
if address == exit_to_near::ADDRESS {
return Some(f(&self.near_exit));
} else if address == exit_to_ethereum::ADDRESS {
return Some(f(&self.ethereum_exit));
}
self.generic_precompiles
.get(&address)
.map(|p| f(p.as_ref()))
}
}

/// fn for making an address by concatenating the bytes from two given numbers,
Expand Down
Loading