From 3df96022504fe2ae182fafb2a95ef10e07483526 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Tue, 22 Mar 2022 07:13:02 -0400 Subject: [PATCH] Release 2.5.1. (#470) * Feat(Engine): Precompiles for predecessor_account_id and current_account_id (#462) * Implement a NEAR native version of the Solidity pure arithmetic benchmark to compare EVM execution cost with direct wasm cost (#463) * Fix features related to panic_info_message (#466) * Fix(standalone): set predecessor_account_id appropriately when executing promise callbacks (#467) * Fix(engine): fix bug in checking if an address exists (#469) * Version update * Update unreleased link Co-authored-by: Joshua J. Bouw --- CHANGES.md | 16 ++- Cargo.toml | 1 + README.md | 4 +- VERSION | 2 +- engine-precompiles/src/account_ids.rs | 124 ++++++++++++++++++ engine-precompiles/src/lib.rs | 28 +++- engine-sdk/src/lib.rs | 1 - engine-standalone-storage/src/sync/mod.rs | 7 + .../src/tests/account_id_precompiles.rs | 69 ++++++++++ engine-tests/src/tests/mod.rs | 1 + engine-tests/src/tests/repro.rs | 2 +- engine-tests/src/tests/res/AccountIds.sol | 45 +++++++ engine-tests/src/tests/res/is_contract.sol | 18 +++ engine-tests/src/tests/sanity.rs | 98 +++++++++++++- engine/src/engine.rs | 13 +- engine/src/lib.rs | 5 +- etc/benchmark-contract/Cargo.lock | 62 +++++++++ etc/benchmark-contract/Cargo.toml | 11 ++ etc/benchmark-contract/src/lib.rs | 56 ++++++++ 19 files changed, 548 insertions(+), 15 deletions(-) create mode 100644 engine-precompiles/src/account_ids.rs create mode 100644 engine-tests/src/tests/account_id_precompiles.rs create mode 100644 engine-tests/src/tests/res/AccountIds.sol create mode 100644 engine-tests/src/tests/res/is_contract.sol create mode 100644 etc/benchmark-contract/Cargo.lock create mode 100644 etc/benchmark-contract/Cargo.toml create mode 100644 etc/benchmark-contract/src/lib.rs diff --git a/CHANGES.md b/CHANGES.md index b2a16af2a..154f2b668 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -7,6 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [2.5.1] - 2022-03-16 + +### Fixes + +- Fix for bug in checking address exists introduced in the v2.5.0 release by [@birchmd]. ([#469]) + +### Added + +- New Aurora-only precompiles for checking the current and predecessor NEAR account IDs by [@birchmd]. ([#462]) + +[#462]: https://github.com/aurora-is-near/aurora-engine/pull/462 +[#469]: https://github.com/aurora-is-near/aurora-engine/pull/469 + ## [2.5.0] - 2022-03-09 ### Changes @@ -219,7 +232,8 @@ struct SubmitResult { ## [1.0.0] - 2021-05-12 -[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.0...develop +[Unreleased]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.1...develop +[2.5.1]: https://github.com/aurora-is-near/aurora-engine/compare/2.5.0...2.5.1 [2.5.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.4.0...2.5.0 [2.4.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.3.0...2.4.0 [2.3.0]: https://github.com/aurora-is-near/aurora-engine/compare/2.2.0...2.3.0 diff --git a/Cargo.toml b/Cargo.toml index b2298f22d..3aeef99be 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,4 +41,5 @@ members = [ exclude = [ "etc/state-migration-test", "etc/ft-receiver", + "etc/benchmark-contract", ] diff --git a/README.md b/README.md index 477a9f0de..0f9a3c951 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ documentation. Network | Contract ID | Chain ID | Version ------- | ------------------- | ---------- | ------ Mainnet | [`aurora`][Mainnet] | 1313161554 | 2.4.0 -Testnet | [`aurora`][Testnet] | 1313161555 | 2.5.0 -Local | `aurora.test.near` | 1313161556 | 2.5.0 +Testnet | [`aurora`][Testnet] | 1313161555 | 2.5.1 +Local | `aurora.test.near` | 1313161556 | 2.5.1 [Mainnet]: https://explorer.near.org/accounts/aurora [Testnet]: https://explorer.testnet.near.org/accounts/aurora diff --git a/VERSION b/VERSION index 437459cd9..73462a5a1 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.5.0 +2.5.1 diff --git a/engine-precompiles/src/account_ids.rs b/engine-precompiles/src/account_ids.rs new file mode 100644 index 000000000..df349a460 --- /dev/null +++ b/engine-precompiles/src/account_ids.rs @@ -0,0 +1,124 @@ +use super::{EvmPrecompileResult, Precompile}; +use crate::prelude::types::{Address, EthGas}; +use crate::PrecompileOutput; +use aurora_engine_types::account_id::AccountId; +use evm::{Context, ExitError}; + +mod costs { + use crate::prelude::types::EthGas; + + // TODO(#51): Determine the correct amount of gas + pub(super) const PREDECESSOR_ACCOUNT_GAS: EthGas = EthGas::new(0); + // TODO(#51): Determine the correct amount of gas + pub(super) const CURRENT_ACCOUNT_GAS: EthGas = EthGas::new(0); +} + +pub struct PredecessorAccount { + predecessor_account_id: AccountId, +} + +impl PredecessorAccount { + /// predecessor_account_id precompile address + /// + /// Address: `0x723ffbaba940e75e7bf5f6d61dcbf8d9a4de0fd7` + /// This address is computed as: `&keccak("predecessorAccountId")[12..]` + pub const ADDRESS: Address = + super::make_address(0x723ffbab, 0xa940e75e7bf5f6d61dcbf8d9a4de0fd7); + + pub fn new(predecessor_account_id: AccountId) -> Self { + Self { + predecessor_account_id, + } + } +} + +impl Precompile for PredecessorAccount { + fn required_gas(_input: &[u8]) -> Result { + Ok(costs::PREDECESSOR_ACCOUNT_GAS) + } + + 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); + } + } + + Ok( + PrecompileOutput::without_logs(cost, self.predecessor_account_id.as_bytes().to_vec()) + .into(), + ) + } +} + +pub struct CurrentAccount { + current_account_id: AccountId, +} + +impl CurrentAccount { + /// current_account_id precompile address + /// + /// Address: `0xfefae79e4180eb0284f261205e3f8cea737aff56` + /// This address is computed as: `&keccak("currentAccountId")[12..]` + pub const ADDRESS: Address = + super::make_address(0xfefae79e, 0x4180eb0284f261205e3f8cea737aff56); + + pub fn new(current_account_id: AccountId) -> Self { + Self { current_account_id } + } +} + +impl Precompile for CurrentAccount { + fn required_gas(_input: &[u8]) -> Result { + Ok(costs::PREDECESSOR_ACCOUNT_GAS) + } + + 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); + } + } + + Ok( + PrecompileOutput::without_logs(cost, self.current_account_id.as_bytes().to_vec()) + .into(), + ) + } +} + +#[cfg(test)] +mod tests { + use crate::account_ids::{CurrentAccount, PredecessorAccount}; + use crate::prelude::sdk::types::near_account_to_evm_address; + + #[test] + fn test_predecessor_account_precompile_id() { + assert_eq!( + PredecessorAccount::ADDRESS, + near_account_to_evm_address("predecessorAccountId".as_bytes()) + ); + } + + #[test] + fn test_curent_account_precompile_id() { + assert_eq!( + CurrentAccount::ADDRESS, + near_account_to_evm_address("currentAccountId".as_bytes()) + ); + } +} diff --git a/engine-precompiles/src/lib.rs b/engine-precompiles/src/lib.rs index b2cb3530a..a7bfc88e9 100644 --- a/engine-precompiles/src/lib.rs +++ b/engine-precompiles/src/lib.rs @@ -1,8 +1,8 @@ #![allow(dead_code)] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] -#![cfg_attr(feature = "log", feature(panic_info_message))] +pub mod account_ids; pub mod blake2; pub mod bn128; pub mod hash; @@ -15,6 +15,7 @@ pub mod secp256k1; #[cfg(test)] mod utils; +use crate::account_ids::{CurrentAccount, PredecessorAccount}; use crate::blake2::Blake2F; use crate::bn128::{Bn128Add, Bn128Mul, Bn128Pair}; use crate::hash::{RIPEMD160, SHA256}; @@ -125,6 +126,7 @@ impl executor::stack::PrecompileSet for Precompiles { pub struct PrecompileConstructorContext { pub current_account_id: AccountId, pub random_seed: H256, + pub predecessor_account_id: AccountId, } impl Precompiles { @@ -137,14 +139,18 @@ impl Precompiles { ExitToNear::ADDRESS, ExitToEthereum::ADDRESS, RandomSeed::ADDRESS, + CurrentAccount::ADDRESS, + PredecessorAccount::ADDRESS, ]; let fun: prelude::Vec> = vec![ 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)), + 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)), ]; let map: BTreeMap> = addresses.into_iter().zip(fun).collect(); @@ -165,6 +171,8 @@ impl Precompiles { ExitToNear::ADDRESS, ExitToEthereum::ADDRESS, RandomSeed::ADDRESS, + CurrentAccount::ADDRESS, + PredecessorAccount::ADDRESS, ]; let fun: prelude::Vec> = vec![ Box::new(ECRecover), @@ -176,8 +184,10 @@ impl Precompiles { Box::new(Bn128Mul::::new()), Box::new(Bn128Pair::::new()), Box::new(ExitToNear::new(ctx.current_account_id.clone())), - Box::new(ExitToEthereum::new(ctx.current_account_id)), + 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)), ]; let map: BTreeMap> = addresses.into_iter().zip(fun).collect(); @@ -198,6 +208,8 @@ impl Precompiles { ExitToNear::ADDRESS, ExitToEthereum::ADDRESS, RandomSeed::ADDRESS, + CurrentAccount::ADDRESS, + PredecessorAccount::ADDRESS, ]; let fun: prelude::Vec> = vec![ Box::new(ECRecover), @@ -210,8 +222,10 @@ impl Precompiles { Box::new(Bn128Pair::::new()), Box::new(Blake2F), Box::new(ExitToNear::new(ctx.current_account_id.clone())), - Box::new(ExitToEthereum::new(ctx.current_account_id)), + 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)), ]; let map: BTreeMap> = addresses.into_iter().zip(fun).collect(); @@ -232,6 +246,8 @@ impl Precompiles { ExitToNear::ADDRESS, ExitToEthereum::ADDRESS, RandomSeed::ADDRESS, + CurrentAccount::ADDRESS, + PredecessorAccount::ADDRESS, ]; let fun: prelude::Vec> = vec![ Box::new(ECRecover), @@ -244,8 +260,10 @@ impl Precompiles { Box::new(Bn128Pair::::new()), Box::new(Blake2F), Box::new(ExitToNear::new(ctx.current_account_id.clone())), - Box::new(ExitToEthereum::new(ctx.current_account_id)), + 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)), ]; let map: BTreeMap> = addresses.into_iter().zip(fun).collect(); diff --git a/engine-sdk/src/lib.rs b/engine-sdk/src/lib.rs index b0c18fafe..876bdf9ef 100644 --- a/engine-sdk/src/lib.rs +++ b/engine-sdk/src/lib.rs @@ -1,6 +1,5 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] -#![cfg_attr(feature = "log", feature(panic_info_message))] #[cfg(feature = "contract")] use crate::prelude::Address; diff --git a/engine-standalone-storage/src/sync/mod.rs b/engine-standalone-storage/src/sync/mod.rs index 5b5c3773c..8f9b5be9e 100644 --- a/engine-standalone-storage/src/sync/mod.rs +++ b/engine-standalone-storage/src/sync/mod.rs @@ -139,6 +139,13 @@ pub fn consume_message(storage: &mut crate::Storage, message: Message) -> Result &promise_args.callback.args, ) .expect("Connector deposit function must return valid args"); + // Since this would be executed as a callback, the predecessor_account_id + // is now equal to the current_account_id + let env = { + let mut tmp = env.clone(); + tmp.predecessor_account_id = env.current_account_id; + tmp + }; let maybe_promise_args = connector_contract.finish_deposit( env.predecessor_account_id(), env.current_account_id(), diff --git a/engine-tests/src/tests/account_id_precompiles.rs b/engine-tests/src/tests/account_id_precompiles.rs new file mode 100644 index 000000000..bd60ad758 --- /dev/null +++ b/engine-tests/src/tests/account_id_precompiles.rs @@ -0,0 +1,69 @@ +use crate::test_utils::{self, standalone}; +use aurora_engine::parameters::SubmitResult; + +#[test] +fn test_account_id_precompiles() { + 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 constructor = test_utils::solidity::ContractConstructor::compile_from_source( + "src/tests/res", + "target/solidity_build", + "AccountIds.sol", + "AccountIds", + ); + + // deploy contract + let nonce = signer.use_nonce(); + let contract = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy_without_constructor(nonce.into()), + constructor, + ); + + // check current_account_id is correct + let result = runner + .submit_with_signer(&mut signer, |nonce| { + contract.call_method_without_args("currentAccountId", nonce) + }) + .unwrap(); + assert_eq!(unwrap_ethabi_string(&result), "aurora"); + + // check predecessor_account_id is correct + let result = runner + .submit_with_signer(&mut signer, |nonce| { + contract.call_method_without_args("predecessorAccountId", nonce) + }) + .unwrap(); + assert_eq!(unwrap_ethabi_string(&result), "some-account.near"); + + // double check the case where account_id is the full 64 bytes + let account_id = "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789"; + assert_eq!(account_id.len(), 64); + runner.standalone_runner.as_mut().unwrap().env.block_height += 1000; + runner + .standalone_runner + .as_mut() + .unwrap() + .env + .current_account_id = account_id.parse().unwrap(); + let nonce = signer.use_nonce(); + let tx = contract.call_method_without_args("currentAccountId", nonce.into()); + let result = runner + .standalone_runner + .as_mut() + .unwrap() + .submit_transaction(&signer.secret_key, tx) + .unwrap(); + assert_eq!(unwrap_ethabi_string(&result), account_id); +} + +fn unwrap_ethabi_string(result: &SubmitResult) -> String { + let bytes = test_utils::unwrap_success_slice(result); + let mut tokens = ethabi::decode(&[ethabi::ParamType::String], &bytes).unwrap(); + tokens.pop().unwrap().into_string().unwrap() +} diff --git a/engine-tests/src/tests/mod.rs b/engine-tests/src/tests/mod.rs index 6f6d09ad3..84b3a1b7d 100644 --- a/engine-tests/src/tests/mod.rs +++ b/engine-tests/src/tests/mod.rs @@ -1,4 +1,5 @@ mod access_lists; +mod account_id_precompiles; mod contract_call; mod eip1559; mod erc20; diff --git a/engine-tests/src/tests/repro.rs b/engine-tests/src/tests/repro.rs index d684442ae..ec217f3a9 100644 --- a/engine-tests/src/tests/repro.rs +++ b/engine-tests/src/tests/repro.rs @@ -46,7 +46,7 @@ fn repro_GdASJ3KESs() { SubmitResult::try_from_slice(&outcome.return_data.as_value().unwrap()).unwrap(); assert_eq!(submit_result.gas_used, 706713); - assert_eq!(238, profile.all_gas() / 1_000_000_000_000); + assert_eq!(239, profile.all_gas() / 1_000_000_000_000); // Also validate the SubmitResult in the standalone engine let mut standalone = standalone::StandaloneRunner::default(); diff --git a/engine-tests/src/tests/res/AccountIds.sol b/engine-tests/src/tests/res/AccountIds.sol new file mode 100644 index 000000000..92d0a10bd --- /dev/null +++ b/engine-tests/src/tests/res/AccountIds.sol @@ -0,0 +1,45 @@ +// SPDX-License-Identifier: CC0-1.0 +pragma solidity ^0.8.0; + +contract AccountIds { + function currentAccountId() public returns (string memory) { + // Near accounts are at most 64 1-byte characters (see https://docs.near.org/docs/concepts/account#account-id-rules) + bytes32[2] memory value; + + assembly { + let ret := call(gas(), 0xfefae79e4180eb0284f261205e3f8cea737aff56, 0, 0, 0, value, 64) + } + + return bytes64ToString(value); + } + + function predecessorAccountId() public returns (string memory) { + // Near accounts are at most 64 1-byte characters (see https://docs.near.org/docs/concepts/account#account-id-rules) + bytes32[2] memory value; + + assembly { + let ret := call(gas(), 0x723ffbaba940e75e7bf5f6d61dcbf8d9a4de0fd7, 0, 0, 0, value, 64) + } + + return bytes64ToString(value); + } + + function bytes64ToString(bytes32[2] memory value) private pure returns (string memory) { + uint8 result_len = 0; + while((result_len < 32 && value[0][result_len] != 0) || (result_len >= 32 && result_len < 64 && value[1][result_len - 32] != 0)) { + result_len++; + } + bytes memory result = new bytes(result_len); + uint8 i = 0; + for (i = 0; i < 32 && value[0][i] != 0; i++) { + result[i] = value[0][i]; + } + if (result_len > 32) { + for (i = 0; i < 32 && value[1][i] != 0; i++) { + result[i + 32] = value[1][i]; + } + } + + return string(result); + } +} diff --git a/engine-tests/src/tests/res/is_contract.sol b/engine-tests/src/tests/res/is_contract.sol new file mode 100644 index 000000000..de7cb55fb --- /dev/null +++ b/engine-tests/src/tests/res/is_contract.sol @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.0; + +contract IsContract { + + function isContract(address account) public view returns (bool) { + // According to EIP-1052, 0x0 is the value returned for not-yet created accounts + // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned + // for accounts without code, i.e. `keccak256('')` + bytes32 codehash; + bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470; + // solhint-disable-next-line no-inline-assembly + assembly { codehash := extcodehash(account) } + return (codehash != accountHash && codehash != 0x0); + } + +} diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index 3fd5178a6..044aae9a8 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -175,6 +175,73 @@ fn test_log_address() { assert_eq!(log_address, greet_contract.address); } +#[test] +fn test_is_contract() { + let (mut runner, mut signer, _) = initialize_transfer(); + let signer_address = test_utils::address_from_secret_key(&signer.secret_key); + + let constructor = test_utils::solidity::ContractConstructor::force_compile( + "src/tests/res", + "target/solidity_build", + "is_contract.sol", + "IsContract", + ); + + let nonce = signer.use_nonce(); + let contract = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy_without_constructor(nonce.into()), + constructor, + ); + + let call_contract = |account: Address, + runner: &mut test_utils::AuroraRunner, + signer: &mut test_utils::Signer| + -> bool { + let result = runner + .submit_with_signer(signer, |nonce| { + contract.call_method_with_args( + "isContract", + &[ethabi::Token::Address(account.raw())], + nonce, + ) + }) + .unwrap(); + let bytes = test_utils::unwrap_success_slice(&result); + ethabi::decode(&[ethabi::ParamType::Bool], bytes) + .unwrap() + .pop() + .unwrap() + .into_bool() + .unwrap() + }; + + // Should return false for accounts that don't exist + assert_eq!( + call_contract(Address::from_array([1; 20]), &mut runner, &mut signer), + false, + ); + + // Should return false for accounts that don't have contract code + assert_eq!( + call_contract(signer_address, &mut runner, &mut signer), + false, + ); + + // Should return true for contracts + let erc20_constructor = test_utils::erc20::ERC20Constructor::load(); + let nonce = signer.use_nonce(); + let token_a = runner.deploy_contract( + &signer.secret_key, + |c| c.deploy("TOKEN_A", "TA", nonce.into()), + erc20_constructor, + ); + assert_eq!( + call_contract(token_a.address, &mut runner, &mut signer), + true, + ); +} + #[test] fn test_solidity_pure_bench() { let (mut runner, mut signer, _) = initialize_transfer(); @@ -195,7 +262,7 @@ fn test_solidity_pure_bench() { ); // Number of iterations to do - let loop_limit = 10_000; + let loop_limit: u32 = 10_000; let (result, profile) = runner .submit_with_signer_profiled(&mut signer, |nonce| { contract.call_method_with_args( @@ -216,6 +283,35 @@ fn test_solidity_pure_bench() { "Expected 1500 NEAR Tgas to be used, but only consumed {}", near_gas / 1_000_000_000_000, ); + + // Pure rust version of the same contract + let base_path = std::path::Path::new("../etc").join("benchmark-contract"); + let output_path = + base_path.join("target/wasm32-unknown-unknown/release/benchmark_contract.wasm"); + test_utils::rust::compile(base_path); + let contract_bytes = std::fs::read(output_path).unwrap(); + let code = near_primitives_core::contract::ContractCode::new(contract_bytes, None); + let mut context = runner.context.clone(); + context.input = loop_limit.to_le_bytes().to_vec(); + let (outcome, error) = near_vm_runner::run( + &code, + "cpu_ram_soak_test", + &mut runner.ext, + context, + &runner.wasm_config, + &runner.fees_config, + &[], + runner.current_protocol_version, + Some(&runner.cache), + ); + if let Some(e) = error { + panic!("{:?}", e); + } + let outcome = outcome.unwrap(); + let profile = test_utils::ExecutionProfile::new(&outcome); + // Check the contract actually did the work. + assert_eq!(&outcome.logs, &[format!("Done {} iterations!", loop_limit)]); + assert!(profile.all_gas() < 1_000_000_000_000); // Less than 1 Tgas used! } #[test] diff --git a/engine/src/engine.rs b/engine/src/engine.rs index 3eec5436f..115284685 100644 --- a/engine/src/engine.rs +++ b/engine/src/engine.rs @@ -346,11 +346,17 @@ struct StackExecutorParams { } impl StackExecutorParams { - fn new(gas_limit: u64, current_account_id: AccountId, random_seed: H256) -> Self { + fn new( + gas_limit: u64, + current_account_id: AccountId, + predecessor_account_id: AccountId, + random_seed: H256, + ) -> Self { Self { precompiles: Precompiles::new_london(PrecompileConstructorContext { current_account_id, random_seed, + predecessor_account_id, }), gas_limit, } @@ -510,6 +516,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let executor_params = StackExecutorParams::new( gas_limit, self.current_account_id.clone(), + self.env.predecessor_account_id(), self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); @@ -594,6 +601,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let executor_params = StackExecutorParams::new( gas_limit, self.current_account_id.clone(), + self.env.predecessor_account_id(), self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); @@ -643,6 +651,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> { let executor_params = StackExecutorParams::new( gas_limit, self.current_account_id.clone(), + self.env.predecessor_account_id(), self.env.random_seed(), ); let mut executor = executor_params.make_executor(self); @@ -1452,7 +1461,7 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> { balance: get_balance(&self.io, &address).raw(), }); if !basic_info.balance.is_zero() || !basic_info.nonce.is_zero() { - return false; + return true; } let mut cache = self.contract_code_cache.borrow_mut(); let code = cache.get_or_insert_with(&address, || get_code(&self.io, &address)); diff --git a/engine/src/lib.rs b/engine/src/lib.rs index 002310870..78a51c0ff 100644 --- a/engine/src/lib.rs +++ b/engine/src/lib.rs @@ -1,6 +1,9 @@ #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc_error_handler))] -#![cfg_attr(feature = "log", feature(panic_info_message))] +#![cfg_attr( + all(feature = "log", target_arch = "wasm32"), + feature(panic_info_message) +)] use aurora_engine_types::parameters::PromiseCreateArgs; diff --git a/etc/benchmark-contract/Cargo.lock b/etc/benchmark-contract/Cargo.lock new file mode 100644 index 000000000..86705c0e0 --- /dev/null +++ b/etc/benchmark-contract/Cargo.lock @@ -0,0 +1,62 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "benchmark_contract" +version = "1.0.0" +dependencies = [ + "wee_alloc", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "libc" +version = "0.2.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/etc/benchmark-contract/Cargo.toml b/etc/benchmark-contract/Cargo.toml new file mode 100644 index 000000000..10f5e5f1f --- /dev/null +++ b/etc/benchmark-contract/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "benchmark_contract" +version = "1.0.0" +authors = ["Aurora "] +edition = "2021" + +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +wee_alloc = { version = "0.4.5", default-features = false } diff --git a/etc/benchmark-contract/src/lib.rs b/etc/benchmark-contract/src/lib.rs new file mode 100644 index 000000000..6eed6e40a --- /dev/null +++ b/etc/benchmark-contract/src/lib.rs @@ -0,0 +1,56 @@ +#![no_std] +#![feature(alloc_error_handler)] + +extern crate alloc; + +use alloc::format; + +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +#[panic_handler] +#[no_mangle] +pub unsafe fn panic(_info: &::core::panic::PanicInfo) -> ! { + core::arch::wasm32::unreachable(); +} + +#[alloc_error_handler] +#[no_mangle] +pub unsafe fn on_alloc_error(_: core::alloc::Layout) -> ! { + core::arch::wasm32::unreachable(); +} + +extern "C" { + fn input(register_id: u64); + fn register_len(register_id: u64) -> u64; + fn read_register(register_id: u64, ptr: u64); + fn log_utf8(len: u64, ptr: u64); +} + +#[no_mangle] +pub unsafe extern "C" fn cpu_ram_soak_test() { + let mut buf = [0u8; 100 * 1024]; + let len = buf.len(); + let loop_limit = read_input() as usize; + let mut counter = 0; + for i in 0..loop_limit { + let j = (i * 7 + len / 2) % len; + let k = (i * 3) % len; + let tmp = buf[k]; + buf[k] = buf[j]; + buf[j] = tmp; + counter += 1; + } + let msg = format!("Done {} iterations!", counter); + log_utf8(msg.len() as u64, msg.as_ptr() as u64); +} + +unsafe fn read_input() -> u32 { + const REGISTER_ID: u64 = 1; + input(REGISTER_ID); + let input_len = register_len(REGISTER_ID); + assert_eq!(input_len, 4); + let buf = [0u8; 4]; + read_register(REGISTER_ID, buf.as_ptr() as u64); + u32::from_le_bytes(buf) +}