Skip to content

Commit

Permalink
Chore: Update to SputnikVM version 0.38.3 (#826)
Browse files Browse the repository at this point in the history
## Description

Updates to the latest version of SputnikVM. There are two improvements:

- A fix to a bug in the `returndatacopy` op code implementation.
- An improvement in performance of accessing the EVM memory.

## Performance / NEAR gas cost considerations

Several gas costs went down a little due to the improved performance in
accessing the EVM memory.

For some reason this also causes the EVM gas cost of the promise results
precompile to increase. I am not sure why, but it's only a small
increase (recall that any EVM transaction must spend at least 21000
gas), so I think's ok.

## Testing

New regression test for the `returndatacopy` bug.
New regression test for the EVM memory performance.
  • Loading branch information
birchmd authored Aug 22, 2023
1 parent 880da84 commit 74590da
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 17 deletions.
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ byte-slice-cast = { version = "1", default-features = false }
criterion = "0.5"
digest = "0.10"
ethabi = { version = "18", default-features = false }
evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false }
evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std"] }
evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std", "tracing"] }
evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.0-aurora", default-features = false, features = ["std", "tracing"] }
evm = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.3-aurora", default-features = false }
evm-core = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.3-aurora", default-features = false, features = ["std"] }
evm-gasometer = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.3-aurora", default-features = false, features = ["std", "tracing"] }
evm-runtime = { git = "https://github.com/aurora-is-near/sputnikvm.git", tag = "v0.38.3-aurora", default-features = false, features = ["std", "tracing"] }
fixed-hash = { version = "0.8.0", default-features = false}
git2 = "0.17"
hex = { version = "0.4", default-features = false, features = ["alloc"] }
Expand Down
2 changes: 1 addition & 1 deletion Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ args = [
"--release",
"--features",
"${CARGO_FEATURES_TEST}",
"bench_modexp_standalone",
"bench_m",
"--",
"--ignored",
]
Expand Down
2 changes: 1 addition & 1 deletion engine-precompiles/src/promise_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub mod costs {
use crate::prelude::types::EthGas;

/// This cost is always charged for calling this precompile.
pub const PROMISE_RESULT_BASE_COST: EthGas = EthGas::new(105);
pub const PROMISE_RESULT_BASE_COST: EthGas = EthGas::new(111);
/// This is the cost per byte of promise result data.
pub const PROMISE_RESULT_BYTE_COST: EthGas = EthGas::new(1);
}
Expand Down
4 changes: 2 additions & 2 deletions engine-tests/src/tests/one_inch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(), 20);
assert_gas_bound(profile.all_gas(), 18);

// Approve giving ERC-20 tokens to the pool
helper.approve_erc20_tokens(&token_a, pool.address());
Expand Down Expand Up @@ -101,7 +101,7 @@ fn test_1_inch_limit_order_deploy() {
// more than 3.5 million Ethereum gas used
assert!(result.gas_used > 3_500_000);
// less than 10 NEAR Tgas used
assert_gas_bound(profile.all_gas(), 10);
assert_gas_bound(profile.all_gas(), 8);
// at least 45% of which is from wasm execution
let wasm_fraction = 100 * profile.wasm_gas() / profile.all_gas();
assert!(
Expand Down
10 changes: 5 additions & 5 deletions engine-tests/src/tests/repro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ fn repro_GdASJ3KESs() {
block_timestamp: 1_645_717_564_644_206_730,
input_path: "src/tests/res/input_GdASJ3KESs.hex",
evm_gas_used: 706_713,
near_gas_used: 121,
near_gas_used: 120,
});
}

Expand All @@ -51,7 +51,7 @@ fn repro_8ru7VEA() {
block_timestamp: 1_648_829_935_343_349_589,
input_path: "src/tests/res/input_8ru7VEA.hex",
evm_gas_used: 1_732_181,
near_gas_used: 220,
near_gas_used: 219,
});
}

Expand All @@ -71,7 +71,7 @@ fn repro_FRcorNv() {
block_timestamp: 1_650_960_438_774_745_116,
input_path: "src/tests/res/input_FRcorNv.hex",
evm_gas_used: 1_239_721,
near_gas_used: 179,
near_gas_used: 177,
});
}

Expand All @@ -88,7 +88,7 @@ fn repro_5bEgfRQ() {
block_timestamp: 1_651_073_772_931_594_646,
input_path: "src/tests/res/input_5bEgfRQ.hex",
evm_gas_used: 6_414_105,
near_gas_used: 654,
near_gas_used: 648,
});
}

Expand All @@ -106,7 +106,7 @@ fn repro_D98vwmi() {
block_timestamp: 1_651_753_443_421_003_245,
input_path: "src/tests/res/input_D98vwmi.hex",
evm_gas_used: 1_035_348,
near_gas_used: 180,
near_gas_used: 179,
});
}

Expand Down
95 changes: 95 additions & 0 deletions engine-tests/src/tests/sanity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,101 @@ const INITIAL_NONCE: u64 = 0;
const TRANSFER_AMOUNT: Wei = Wei::new_u64(123);
const GAS_PRICE: u64 = 10;

#[ignore]
#[test]
fn bench_memory_get_standalone() {
let (mut runner, mut signer, _) = initialize_transfer();

// This EVM program is an infinite loop which causes a large amount of memory to be
// copied onto the EVM stack.
let contract_bytes = vec![
0x5b, 0x3a, 0x33, 0x43, 0x03, 0x59, 0x52, 0x59, 0x42, 0x59, 0x3a, 0x60, 0x05, 0x34, 0xf4,
0x60, 0x33, 0x43, 0x05, 0x52, 0x56,
];
let result = runner
.submit_with_signer(&mut signer, |nonce| {
utils::create_deploy_transaction(contract_bytes, nonce)
})
.unwrap();
let address = Address::try_from_slice(&utils::unwrap_success(result)).unwrap();

runner.standalone_runner.as_mut().unwrap().env.block_height += 100;
let tx = aurora_engine_transactions::legacy::TransactionLegacy {
nonce: signer.use_nonce().into(),
gas_price: U256::zero(),
gas_limit: 10_000_000_u64.into(),
to: Some(address),
value: Wei::zero(),
data: Vec::new(),
};

let start = std::time::Instant::now();
let result = runner
.standalone_runner
.unwrap()
.submit_transaction(&signer.secret_key, tx)
.unwrap();
let duration = start.elapsed().as_secs_f32();
assert!(
matches!(result.status, TransactionStatus::OutOfGas),
"Infinite loops in the EVM run out of gas"
);
assert!(
duration < 8.0,
"Must complete this task in under 8s (in release build). Time taken: {duration} s",
);
}

#[test]
fn test_returndatacopy() {
let (mut runner, mut signer, _) = initialize_transfer();

let deploy_contract = |runner: &mut utils::AuroraRunner,
signer: &mut utils::Signer,
contract_bytes: Vec<u8>|
-> Address {
let deploy = utils::create_deploy_transaction(contract_bytes, signer.use_nonce().into());
let result = runner
.submit_transaction(&signer.secret_key, deploy)
.unwrap();
Address::try_from_slice(&utils::unwrap_success(result)).unwrap()
};

let call_contract =
|runner: &mut utils::AuroraRunner, signer: &mut utils::Signer, address: Address| {
runner
.submit_with_signer(signer, |nonce| {
aurora_engine_transactions::legacy::TransactionLegacy {
nonce,
gas_price: U256::zero(),
gas_limit: u64::MAX.into(),
to: Some(address),
value: Wei::zero(),
data: Vec::new(),
}
})
.unwrap()
};

// Call returndatacopy with len=0 and large memory offset (> u32::MAX)
let contract_bytes = vec![0x60, 0x00, 0x3d, 0x33, 0x3e];
let address = deploy_contract(&mut runner, &mut signer, contract_bytes);
let result = call_contract(&mut runner, &mut signer, address);
assert!(
result.status.is_ok(),
"EVM must handle returndatacopy with len=0"
);

// Call returndatacopy with len=1 and large memory offset (> u32::MAX)
let contract_bytes = vec![0x60, 0x01, 0x3d, 0x33, 0x3e];
let address = deploy_contract(&mut runner, &mut signer, contract_bytes);
let result = call_contract(&mut runner, &mut signer, address);
assert!(
matches!(result.status, TransactionStatus::OutOfGas),
"EVM must run out of gas if len > 0 with large memory offset"
);
}

#[test]
fn test_total_supply_accounting() {
let (mut runner, mut signer, benefactor) = initialize_transfer();
Expand Down

0 comments on commit 74590da

Please sign in to comment.