From 069a10a63c785436e299196d0cdc5531ed648c08 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Wed, 30 Mar 2022 17:51:41 +0200 Subject: [PATCH 1/2] Feat(Engine): Add custom precompile for NEAR prepaid_gas --- engine-precompiles/src/lib.rs | 7 ++ engine-precompiles/src/prepaid_gas.rs | 72 +++++++++++++++++++ engine-tests/src/tests/mod.rs | 1 + .../src/tests/prepaid_gas_precompile.rs | 41 +++++++++++ 4 files changed, 121 insertions(+) create mode 100644 engine-precompiles/src/prepaid_gas.rs create mode 100644 engine-tests/src/tests/prepaid_gas_precompile.rs diff --git a/engine-precompiles/src/lib.rs b/engine-precompiles/src/lib.rs index 9383ed25e..c24286a17 100644 --- a/engine-precompiles/src/lib.rs +++ b/engine-precompiles/src/lib.rs @@ -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)] @@ -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; @@ -110,6 +112,7 @@ pub struct Precompiles<'a, I, E> { pub near_exit: ExitToNear, pub ethereum_exit: ExitToEthereum, 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> { @@ -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, } } @@ -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) diff --git a/engine-precompiles/src/prepaid_gas.rs b/engine-precompiles/src/prepaid_gas.rs new file mode 100644 index 000000000..64767d536 --- /dev/null +++ b/engine-precompiles/src/prepaid_gas.rs @@ -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(#51): 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 { + Ok(costs::PREPAID_GAS_COST) + } + + fn run( + &self, + input: &[u8], + target_gas: Option, + _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()) + ); + } +} diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index 84b3a1b7d..5ffa55f4d 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -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; diff --git a/engine-tests/src/tests/prepaid_gas_precompile.rs b/engine-tests/src/tests/prepaid_gas_precompile.rs new file mode 100644 index 000000000..f008dcf08 --- /dev/null +++ b/engine-tests/src/tests/prepaid_gas_precompile.rs @@ -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()); +} From 198a898091a09fe81fef3ef10f6f9e288ec122f4 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Tue, 5 Apr 2022 17:20:55 +0200 Subject: [PATCH 2/2] Tag EVM cost estimating with new 483 TODO --- engine-precompiles/src/account_ids.rs | 4 ++-- engine-precompiles/src/native.rs | 4 ++-- engine-precompiles/src/prepaid_gas.rs | 2 +- engine-precompiles/src/random.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/engine-precompiles/src/account_ids.rs b/engine-precompiles/src/account_ids.rs index 0aff5d912..a69c15c0a 100644 --- a/engine-precompiles/src/account_ids.rs +++ b/engine-precompiles/src/account_ids.rs @@ -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); } diff --git a/engine-precompiles/src/native.rs b/engine-precompiles/src/native.rs index 58ece47d2..99df0a964 100644 --- a/engine-precompiles/src/native.rs +++ b/engine-precompiles/src/native.rs @@ -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 diff --git a/engine-precompiles/src/prepaid_gas.rs b/engine-precompiles/src/prepaid_gas.rs index 64767d536..7aacc8e90 100644 --- a/engine-precompiles/src/prepaid_gas.rs +++ b/engine-precompiles/src/prepaid_gas.rs @@ -14,7 +14,7 @@ pub const ADDRESS: Address = crate::make_address(0x536822d2, 0x7de53629ef1f84c60 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 PREPAID_GAS_COST: EthGas = EthGas::new(0); } diff --git a/engine-precompiles/src/random.rs b/engine-precompiles/src/random.rs index b71f2509e..e46e0f47d 100644 --- a/engine-precompiles/src/random.rs +++ b/engine-precompiles/src/random.rs @@ -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); }