Skip to content

Commit

Permalink
Feat(Engine): Add custom precompile for NEAR prepaid_gas (#479)
Browse files Browse the repository at this point in the history
  • Loading branch information
birchmd committed Apr 27, 2022
1 parent 6c88adc commit 24eccb6
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 5 deletions.
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());
}

0 comments on commit 24eccb6

Please sign in to comment.