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

Feat(Engine): Add custom precompile for NEAR prepaid_gas #479

Merged
merged 2 commits into from
Apr 8, 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
4 changes: 2 additions & 2 deletions engine-precompiles/src/account_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ use evm::{Context, ExitError};
mod costs {
use crate::prelude::types::EthGas;

// TODO(#51): Determine the correct amount of gas
// TODO(#483): Determine the correct amount of gas
pub(super) const PREDECESSOR_ACCOUNT_GAS: EthGas = EthGas::new(0);
// TODO(#51): Determine the correct amount of gas
// TODO(#483): Determine the correct amount of gas
pub(super) const CURRENT_ACCOUNT_GAS: EthGas = EthGas::new(0);
}

Expand Down
7 changes: 7 additions & 0 deletions engine-precompiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod identity;
pub mod modexp;
pub mod native;
mod prelude;
pub mod prepaid_gas;
pub mod random;
pub mod secp256k1;
#[cfg(test)]
Expand All @@ -24,6 +25,7 @@ use crate::modexp::ModExp;
use crate::native::{exit_to_ethereum, exit_to_near, ExitToEthereum, ExitToNear};
use crate::prelude::types::EthGas;
use crate::prelude::{Vec, H160, H256};
use crate::prepaid_gas::PrepaidGas;
use crate::random::RandomSeed;
use crate::secp256k1::ECRecover;
use aurora_engine_sdk::env::Env;
Expand Down Expand Up @@ -110,6 +112,7 @@ pub struct Precompiles<'a, I, E> {
pub near_exit: ExitToNear<I>,
pub ethereum_exit: ExitToEthereum<I>,
pub predecessor_account_id: PredecessorAccount<'a, E>,
pub prepaid_gas: PrepaidGas<'a, E>,
}

impl<'a, I: IO + Copy, E: Env> executor::stack::PrecompileSet for Precompiles<'a, I, E> {
Expand Down Expand Up @@ -268,12 +271,14 @@ impl<'a, I: IO + Copy, E: Env> Precompiles<'a, I, E> {
let near_exit = ExitToNear::new(ctx.current_account_id.clone(), ctx.io);
let ethereum_exit = ExitToEthereum::new(ctx.current_account_id, ctx.io);
let predecessor_account_id = PredecessorAccount::new(ctx.env);
let prepaid_gas = PrepaidGas::new(ctx.env);

Self {
generic_precompiles,
near_exit,
ethereum_exit,
predecessor_account_id,
prepaid_gas,
}
}

Expand All @@ -288,6 +293,8 @@ impl<'a, I: IO + Copy, E: Env> Precompiles<'a, I, E> {
return Some(f(&self.ethereum_exit));
} else if address == predecessor_account::ADDRESS {
return Some(f(&self.predecessor_account_id));
} else if address == prepaid_gas::ADDRESS {
return Some(f(&self.prepaid_gas));
}
self.generic_precompiles
.get(&address)
Expand Down
4 changes: 2 additions & 2 deletions engine-precompiles/src/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ const ERR_TARGET_TOKEN_NOT_FOUND: &str = "Target token not found";
mod costs {
use crate::prelude::types::{EthGas, NearGas};

// TODO(#51): Determine the correct amount of gas
// TODO(#483): Determine the correct amount of gas
pub(super) const EXIT_TO_NEAR_GAS: EthGas = EthGas::new(0);

// TODO(#51): Determine the correct amount of gas
// TODO(#483): Determine the correct amount of gas
pub(super) const EXIT_TO_ETHEREUM_GAS: EthGas = EthGas::new(0);

// TODO(#332): Determine the correct amount of gas
Expand Down
72 changes: 72 additions & 0 deletions engine-precompiles/src/prepaid_gas.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
use super::{EvmPrecompileResult, Precompile};
use crate::prelude::types::{Address, EthGas};
use crate::PrecompileOutput;
use aurora_engine_sdk::env::Env;
use aurora_engine_types::{vec, U256};
use evm::{Context, ExitError};

/// predecessor_account_id precompile address
///
/// Address: `0x536822d27de53629ef1f84c60555689e9488609f`
/// This address is computed as: `&keccak("prepaidGas")[12..]`
pub const ADDRESS: Address = crate::make_address(0x536822d2, 0x7de53629ef1f84c60555689e9488609f);

mod costs {
use crate::prelude::types::EthGas;

// TODO(#483): Determine the correct amount of gas
pub(super) const PREPAID_GAS_COST: EthGas = EthGas::new(0);
}

pub struct PrepaidGas<'a, E> {
env: &'a E,
}

impl<'a, E> PrepaidGas<'a, E> {
pub fn new(env: &'a E) -> Self {
Self { env }
}
}

impl<'a, E: Env> Precompile for PrepaidGas<'a, E> {
fn required_gas(_input: &[u8]) -> Result<EthGas, ExitError> {
Ok(costs::PREPAID_GAS_COST)
}

fn run(
&self,
input: &[u8],
target_gas: Option<EthGas>,
_context: &Context,
_is_static: bool,
) -> EvmPrecompileResult {
let cost = Self::required_gas(input)?;
if let Some(target_gas) = target_gas {
if cost > target_gas {
return Err(ExitError::OutOfGas);
}
}

let prepaid_gas = self.env.prepaid_gas();
let bytes = {
let mut buf = vec![0; 32];
U256::from(prepaid_gas.as_u64()).to_big_endian(&mut buf);
buf
};
Ok(PrecompileOutput::without_logs(cost, bytes).into())
}
}

#[cfg(test)]
mod tests {
use crate::prelude::sdk::types::near_account_to_evm_address;
use crate::prepaid_gas;

#[test]
fn test_prepaid_gas_precompile_id() {
assert_eq!(
prepaid_gas::ADDRESS,
near_account_to_evm_address("prepaidGas".as_bytes())
);
}
}
2 changes: 1 addition & 1 deletion engine-precompiles/src/random.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use evm::{Context, ExitError};
mod costs {
use crate::prelude::types::EthGas;

// TODO(#51): Determine the correct amount of gas
// TODO(#483): Determine the correct amount of gas
pub(super) const RANDOM_BYTES_GAS: EthGas = EthGas::new(0);
}

Expand Down
1 change: 1 addition & 0 deletions engine-tests/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod eth_connector;
#[cfg(feature = "meta-call")]
mod meta_parsing;
mod one_inch;
mod prepaid_gas_precompile;
mod random;
mod repro;
mod sanity;
Expand Down
41 changes: 41 additions & 0 deletions engine-tests/src/tests/prepaid_gas_precompile.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
use crate::test_utils::{self, standalone};
use aurora_engine_precompiles::prepaid_gas;
use aurora_engine_transactions::legacy::TransactionLegacy;
use aurora_engine_types::{types::Wei, U256};

#[test]
fn test_prepaid_gas_precompile() {
let mut signer = test_utils::Signer::random();
let mut runner = test_utils::deploy_evm();
let mut standalone = standalone::StandaloneRunner::default();

standalone.init_evm();
runner.standalone_runner = Some(standalone);

let transaction = TransactionLegacy {
nonce: signer.use_nonce().into(),
gas_price: U256::zero(),
gas_limit: u64::MAX.into(),
to: Some(prepaid_gas::ADDRESS),
value: Wei::zero(),
data: Vec::new(),
};

const EXPECTED_VALUE: u64 = 157_277_246_352_223;
runner.context.prepaid_gas = EXPECTED_VALUE;
let result = runner
.submit_transaction(&signer.secret_key, transaction.clone())
.unwrap();

assert_eq!(
U256::from(EXPECTED_VALUE),
U256::from_big_endian(test_utils::unwrap_success_slice(&result)),
);

// confirm the precompile works in view calls too
let sender = test_utils::address_from_secret_key(&signer.secret_key);
let result = runner
.view_call(test_utils::as_view_call(transaction, sender))
.unwrap();
assert!(result.is_ok());
}