From f8ea05c36c30cee770981c08722cc0716198a852 Mon Sep 17 00:00:00 2001 From: Michael Birch Date: Mon, 3 Jan 2022 18:33:56 +0100 Subject: [PATCH] Feat(tests): Mock touching trie nodes (#408) --- .../src/test_utils/mocked_external.rs | 176 ++++++++++++++++++ engine-tests/src/test_utils/mod.rs | 6 +- engine-tests/src/tests/one_inch.rs | 20 +- engine-tests/src/tests/sanity.rs | 4 +- engine-tests/src/tests/uniswap.rs | 8 +- 5 files changed, 196 insertions(+), 18 deletions(-) create mode 100644 engine-tests/src/test_utils/mocked_external.rs diff --git a/engine-tests/src/test_utils/mocked_external.rs b/engine-tests/src/test_utils/mocked_external.rs new file mode 100644 index 000000000..f2b1ec38c --- /dev/null +++ b/engine-tests/src/test_utils/mocked_external.rs @@ -0,0 +1,176 @@ +use near_vm_logic::mocks::mock_external::MockedExternal; + +pub(crate) struct MockedExternalWithTrie<'a> { + underlying: &'a mut MockedExternal, + trie_node_count: std::cell::Cell, +} + +impl<'a> MockedExternalWithTrie<'a> { + pub fn new(ext: &'a mut MockedExternal) -> Self { + Self { + underlying: ext, + trie_node_count: std::cell::Cell::new(0), + } + } + + fn increment_trie_node_count(&self, amount: u64) { + let cell_value = self.trie_node_count.get(); + self.trie_node_count.set(cell_value + amount); + } +} + +impl<'b> near_vm_logic::External for MockedExternalWithTrie<'b> { + fn storage_set(&mut self, key: &[u8], value: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.increment_trie_node_count(10); + self.underlying.storage_set(key, value) + } + + fn storage_get<'a>( + &'a self, + key: &[u8], + ) -> Result>, near_vm_logic::VMLogicError> { + self.increment_trie_node_count(10); + self.underlying.storage_get(key) + } + + fn storage_remove(&mut self, key: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.increment_trie_node_count(10); + self.underlying.storage_remove(key) + } + + fn storage_remove_subtree(&mut self, prefix: &[u8]) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.storage_remove_subtree(prefix) + } + + fn storage_has_key(&mut self, key: &[u8]) -> Result { + self.underlying.storage_has_key(key) + } + + fn create_receipt( + &mut self, + receipt_indices: Vec, + receiver_id: near_primitives::types::AccountId, + ) -> Result { + self.underlying.create_receipt(receipt_indices, receiver_id) + } + + fn append_action_create_account( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_create_account(receipt_index) + } + + fn append_action_deploy_contract( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + code: Vec, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_deploy_contract(receipt_index, code) + } + + fn append_action_function_call( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + method_name: Vec, + arguments: Vec, + attached_deposit: near_primitives::types::Balance, + prepaid_gas: near_primitives::types::Gas, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_function_call( + receipt_index, + method_name, + arguments, + attached_deposit, + prepaid_gas, + ) + } + + fn append_action_transfer( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + amount: near_primitives::types::Balance, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_transfer(receipt_index, amount) + } + + fn append_action_stake( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + stake: near_primitives::types::Balance, + public_key: near_vm_logic::types::PublicKey, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_stake(receipt_index, stake, public_key) + } + + fn append_action_add_key_with_full_access( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + nonce: u64, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_add_key_with_full_access(receipt_index, public_key, nonce) + } + + fn append_action_add_key_with_function_call( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + nonce: u64, + allowance: Option, + receiver_id: near_primitives::types::AccountId, + method_names: Vec>, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying.append_action_add_key_with_function_call( + receipt_index, + public_key, + nonce, + allowance, + receiver_id, + method_names, + ) + } + + fn append_action_delete_key( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + public_key: near_vm_logic::types::PublicKey, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_delete_key(receipt_index, public_key) + } + + fn append_action_delete_account( + &mut self, + receipt_index: near_vm_logic::types::ReceiptIndex, + beneficiary_id: near_primitives::types::AccountId, + ) -> Result<(), near_vm_logic::VMLogicError> { + self.underlying + .append_action_delete_account(receipt_index, beneficiary_id) + } + + fn get_touched_nodes_count(&self) -> u64 { + self.trie_node_count.get() + } + + fn reset_touched_nodes_counter(&mut self) { + self.trie_node_count.set(0) + } + + fn validator_stake( + &self, + account_id: &near_primitives::types::AccountId, + ) -> Result, near_vm_logic::VMLogicError> { + self.underlying.validator_stake(account_id) + } + + fn validator_total_stake( + &self, + ) -> Result { + self.underlying.validator_total_stake() + } +} diff --git a/engine-tests/src/test_utils/mod.rs b/engine-tests/src/test_utils/mod.rs index ff6f90da3..b86f61790 100644 --- a/engine-tests/src/test_utils/mod.rs +++ b/engine-tests/src/test_utils/mod.rs @@ -35,6 +35,7 @@ pub(crate) const DEPLOY_ERC20: &str = "deploy_erc20_token"; pub(crate) mod erc20; pub(crate) mod exit_precompile; +pub(crate) mod mocked_external; pub(crate) mod one_inch; pub(crate) mod random; pub(crate) mod rust; @@ -183,10 +184,11 @@ impl AuroraRunner { input, ); + let mut ext = mocked_external::MockedExternalWithTrie::new(&mut self.ext); let (maybe_outcome, maybe_error) = near_vm_runner::run( &self.code, method_name, - &mut self.ext, + &mut ext, self.context.clone(), &self.wasm_config, &self.fees_config, @@ -538,7 +540,7 @@ impl Default for AuroraRunner { /// (which was removed in https://github.com/near/nearcore/pull/4438). #[derive(Default, Clone)] pub(crate) struct ExecutionProfile { - host_breakdown: ProfileData, + pub host_breakdown: ProfileData, wasm_gas: u64, } diff --git a/engine-tests/src/tests/one_inch.rs b/engine-tests/src/tests/one_inch.rs index ecdb070d0..211bda40e 100644 --- a/engine-tests/src/tests/one_inch.rs +++ b/engine-tests/src/tests/one_inch.rs @@ -23,11 +23,11 @@ fn test_1inch_liquidity_protocol() { let (result, profile, deployer_address) = helper.create_mooniswap_deployer(); assert!(result.gas_used >= 5_100_000); // more than 5.1M EVM gas used - assert_gas_bound(profile.all_gas(), 15); // less than 15 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 20); // less than 20 NEAR Tgas used let (result, profile, pool_factory) = helper.create_pool_factory(&deployer_address); assert!(result.gas_used >= 2_800_000); // more than 2.8M EVM gas used - assert_gas_bound(profile.all_gas(), 13); // less than 22 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 19); // less than 19 NEAR Tgas used // create some ERC-20 tokens to have a liquidity pool for let signer_address = test_utils::address_from_secret_key(&helper.signer.secret_key); @@ -39,7 +39,7 @@ fn test_1inch_liquidity_protocol() { let (result, profile, pool) = helper.create_pool(&pool_factory, token_a.0.address, token_b.0.address); assert!(result.gas_used >= 4_500_000); // more than 4.5M EVM gas used - assert_gas_bound(profile.all_gas(), 36); // less than 36 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 59); // less than 59 NEAR Tgas used // Approve giving ERC-20 tokens to the pool helper.approve_erc20_tokens(&token_a, pool.address()); @@ -58,7 +58,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 302_000); // more than 302k EVM gas used - assert_gas_bound(profile.all_gas(), 46); // less than 46 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 89); // less than 89 NEAR Tgas used // Same here helper.runner.context.block_timestamp += 10_000_000 * 1_000_000_000; @@ -73,7 +73,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 210_000); // more than 210k EVM gas used - assert_gas_bound(profile.all_gas(), 50); // less than 49 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 91); // less than 91 NEAR Tgas used let (result, profile) = helper.pool_withdraw( &pool, @@ -84,7 +84,7 @@ fn test_1inch_liquidity_protocol() { }, ); assert!(result.gas_used >= 150_000); // more than 150k EVM gas used - assert_gas_bound(profile.all_gas(), 40); // less than 40 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 78); // less than 78 NEAR Tgas used } #[test] @@ -100,13 +100,13 @@ fn test_1_inch_limit_order_deploy() { // more than 3.5 million Ethereum gas used assert!(result.gas_used > 3_500_000); - // less than 15 NEAR Tgas used - assert_gas_bound(profile.all_gas(), 15); + // less than 18 NEAR Tgas used + assert_gas_bound(profile.all_gas(), 18); // at least 45% of which is from wasm execution let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); assert!( - wasm_fraction >= 45, - "{}% is not greater than 45%", + wasm_fraction >= 33, + "{}% is not greater than 33%", wasm_fraction ); } diff --git a/engine-tests/src/tests/sanity.rs b/engine-tests/src/tests/sanity.rs index 0d32a88b5..ed32c764e 100644 --- a/engine-tests/src/tests/sanity.rs +++ b/engine-tests/src/tests/sanity.rs @@ -92,8 +92,8 @@ fn test_deploy_largest_contract() { result.gas_used, ); - // Less than 28 NEAR Tgas - test_utils::assert_gas_bound(profile.all_gas(), 15); + // Less than 20 NEAR Tgas + test_utils::assert_gas_bound(profile.all_gas(), 20); } #[test] diff --git a/engine-tests/src/tests/uniswap.rs b/engine-tests/src/tests/uniswap.rs index a566bf3a0..17beea580 100644 --- a/engine-tests/src/tests/uniswap.rs +++ b/engine-tests/src/tests/uniswap.rs @@ -29,15 +29,15 @@ fn test_uniswap_exact_output() { let (_result, profile) = context.add_equal_liquidity(LIQUIDITY_AMOUNT.into(), &token_a, &token_b); - test_utils::assert_gas_bound(profile.all_gas(), 64); + test_utils::assert_gas_bound(profile.all_gas(), 126); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); - assert!(wasm_fraction >= 46, "{}% not more than 46%", wasm_fraction); + assert!(wasm_fraction >= 23, "{}% not more than 23%", wasm_fraction); let (_amount_in, profile) = context.exact_output_single(&token_a, &token_b, OUTPUT_AMOUNT.into()); - test_utils::assert_gas_bound(profile.all_gas(), 36); + test_utils::assert_gas_bound(profile.all_gas(), 61); let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas(); - assert!(wasm_fraction >= 52, "{}% not more than 52%", wasm_fraction); + assert!(wasm_fraction >= 30, "{}% not more than 30%", wasm_fraction); } #[derive(Debug, Copy, Clone, PartialEq, Eq)]