Skip to content

Commit

Permalink
Fix(engine): Cache generation values to avoid repeated state reads (#438
Browse files Browse the repository at this point in the history
)
  • Loading branch information
birchmd committed Feb 10, 2022
1 parent 6c1b78d commit b4858e5
Show file tree
Hide file tree
Showing 5 changed files with 27 additions and 20 deletions.
4 changes: 2 additions & 2 deletions engine-tests/src/tests/erc20.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ fn profile_erc20_get_balance() {
runner.profiled_view_call(test_utils::as_view_call(balance_tx, source_address));
assert!(result.is_ok());

// call costs less than 4 Tgas
test_utils::assert_gas_bound(profile.all_gas(), 4);
// call costs less than 3 Tgas
test_utils::assert_gas_bound(profile.all_gas(), 3);
// at least 70% of the cost is spent on wasm computation (as opposed to host functions)
let wasm_fraction = (100 * profile.wasm_gas()) / profile.all_gas();
assert!(
Expand Down
16 changes: 8 additions & 8 deletions engine-tests/src/tests/one_inch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(), 20); // less than 20 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 18); // less than 18 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(), 19); // less than 19 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 18); // less than 18 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);
Expand All @@ -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(), 59); // less than 59 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 48); // less than 48 NEAR Tgas used

// Approve giving ERC-20 tokens to the pool
helper.approve_erc20_tokens(&token_a, pool.address());
Expand All @@ -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(), 89); // less than 89 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 64); // less than 64 NEAR Tgas used

// Same here
helper.runner.context.block_timestamp += 10_000_000 * 1_000_000_000;
Expand All @@ -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(), 91); // less than 91 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 66); // less than 66 NEAR Tgas used

let (result, profile) = helper.pool_withdraw(
&pool,
Expand All @@ -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(), 78); // less than 78 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 57); // less than 57 NEAR Tgas used
}

#[test]
Expand All @@ -100,8 +100,8 @@ fn test_1_inch_limit_order_deploy() {

// more than 3.5 million Ethereum gas used
assert!(result.gas_used > 3_500_000);
// less than 20 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 20);
// less than 17 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 17);
// at least 45% of which is from wasm execution
let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas();
assert!(
Expand Down
4 changes: 2 additions & 2 deletions engine-tests/src/tests/sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ fn test_deploy_largest_contract() {
result.gas_used,
);

// Less than 20 NEAR Tgas
test_utils::assert_gas_bound(profile.all_gas(), 20);
// Less than 18 NEAR Tgas
test_utils::assert_gas_bound(profile.all_gas(), 18);
}

#[test]
Expand Down
10 changes: 5 additions & 5 deletions engine-tests/src/tests/uniswap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn test_uniswap_input_multihop() {
let mut context = UniswapTestContext::new("uniswap");

// evm_gas = 970k
// near total gas = 410 Tgas
// near total gas = 302 Tgas
// Wish: optimize so that this transaction costs less than 200 Tgas.
// For now we just have to increase the burnt gas limit to make it run to completion.
context.runner.wasm_config.limit_config.max_gas_burnt = 500_000_000_000_000;
Expand All @@ -54,17 +54,17 @@ 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(), 126);
test_utils::assert_gas_bound(profile.all_gas(), 88);
let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas();
assert!(
15 <= wasm_fraction && wasm_fraction <= 20,
"{}% is not between 15% and 20%",
20 <= wasm_fraction && wasm_fraction <= 30,
"{}% is not between 20% and 30%",
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(), 61);
test_utils::assert_gas_bound(profile.all_gas(), 48);
let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas();
assert!(
20 <= wasm_fraction && wasm_fraction <= 30,
Expand Down
13 changes: 10 additions & 3 deletions engine/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ use crate::prelude::precompiles::Precompiles;
use crate::prelude::transactions::{EthTransactionKind, NormalizedEthTransaction};
use crate::prelude::{
address_to_key, bytes_to_key, sdk, storage_to_key, u256_to_arr, vec, AccountId, Address,
BorshDeserialize, BorshSerialize, KeyPrefix, PromiseArgs, PromiseCreateArgs, ToString, Vec,
Wei, ERC20_MINT_SELECTOR, H160, H256, U256,
BTreeMap, BorshDeserialize, BorshSerialize, KeyPrefix, PromiseArgs, PromiseCreateArgs,
ToString, Vec, Wei, ERC20_MINT_SELECTOR, H160, H256, U256,
};
use aurora_engine_precompiles::PrecompileConstructorContext;
use core::cell::RefCell;

/// Used as the first byte in the concatenation of data used to compute the blockhash.
/// Could be useful in the future as a version byte, or to distinguish different types of blocks.
Expand Down Expand Up @@ -404,6 +405,7 @@ pub struct Engine<'env, I: IO, E: Env> {
current_account_id: AccountId,
io: I,
env: &'env E,
generation_cache: RefCell<BTreeMap<Address, u32>>,
}

pub(crate) const CONFIG: &Config = &Config::london();
Expand Down Expand Up @@ -435,6 +437,7 @@ impl<'env, I: IO + Copy, E: Env> Engine<'env, I, E> {
current_account_id,
io,
env,
generation_cache: RefCell::new(BTreeMap::new()),
}
}

Expand Down Expand Up @@ -1433,7 +1436,11 @@ impl<'env, I: IO + Copy, E: Env> evm::backend::Backend for Engine<'env, I, E> {
/// Get storage value of address at index.
fn storage(&self, address: H160, index: H256) -> H256 {
let address = Address::new(address);
let generation = get_generation(&self.io, &address);
let generation = *self
.generation_cache
.borrow_mut()
.entry(address)
.or_insert_with(|| get_generation(&self.io, &address));
get_storage(&self.io, &address, &index, generation)
}

Expand Down

0 comments on commit b4858e5

Please sign in to comment.