Skip to content

Commit

Permalink
run near-vm in with_vm_variants (near#8905)
Browse files Browse the repository at this point in the history
Similarly to near#8901, make tests also run with near-vm if they’re testing a recent enough protocol version (which means the changes will actually happen with the near-vm introduction protocol changes)
  • Loading branch information
Ekleog-NEAR authored Apr 13, 2023
1 parent 33e6abf commit f4e882a
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 63 deletions.
62 changes: 45 additions & 17 deletions runtime/near-vm-runner/src/prepare.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,55 +62,77 @@ mod tests {
use crate::tests::with_vm_variants;
use assert_matches::assert_matches;

fn parse_and_prepare_wat(vm_kind: VMKind, wat: &str) -> Result<Vec<u8>, PrepareError> {
fn parse_and_prepare_wat(
config: &VMConfig,
vm_kind: VMKind,
wat: &str,
) -> Result<Vec<u8>, PrepareError> {
let wasm = wat::parse_str(wat).unwrap();
let config = VMConfig::test();
prepare_contract(wasm.as_ref(), &config, vm_kind)
}

#[test]
fn internal_memory_declaration() {
with_vm_variants(|kind| {
let r = parse_and_prepare_wat(kind, r#"(module (memory 1 1))"#);
let config = VMConfig::test();
with_vm_variants(&config, |kind| {
let r = parse_and_prepare_wat(&config, kind, r#"(module (memory 1 1))"#);
assert_matches!(r, Ok(_));
})
}

#[test]
fn memory_imports() {
let config = VMConfig::test();

// This test assumes that maximum page number is configured to a certain number.
assert_eq!(VMConfig::test().limit_config.max_memory_pages, 2048);
assert_eq!(config.limit_config.max_memory_pages, 2048);

with_vm_variants(|kind| {
let r = parse_and_prepare_wat(kind, r#"(module (import "env" "memory" (memory 1 1)))"#);
with_vm_variants(&config, |kind| {
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "env" "memory" (memory 1 1)))"#,
);
assert_matches!(r, Err(PrepareError::Memory));

// No memory import
let r = parse_and_prepare_wat(kind, r#"(module)"#);
let r = parse_and_prepare_wat(&config, kind, r#"(module)"#);
assert_matches!(r, Ok(_));

// initial exceed maximum
let r =
parse_and_prepare_wat(kind, r#"(module (import "env" "memory" (memory 17 1)))"#);
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "env" "memory" (memory 17 1)))"#,
);
assert_matches!(r, Err(PrepareError::Deserialization));

// no maximum
let r = parse_and_prepare_wat(kind, r#"(module (import "env" "memory" (memory 1)))"#);
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "env" "memory" (memory 1)))"#,
);
assert_matches!(r, Err(PrepareError::Memory));

// requested maximum exceed configured maximum
let r =
parse_and_prepare_wat(kind, r#"(module (import "env" "memory" (memory 1 33)))"#);
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "env" "memory" (memory 1 33)))"#,
);
assert_matches!(r, Err(PrepareError::Memory));
})
}

#[test]
fn multiple_valid_memory_are_disabled() {
with_vm_variants(|kind| {
let config = VMConfig::test();
with_vm_variants(&config, |kind| {
// Our preparation and sanitization pass assumes a single memory, so we should fail when
// there are multiple specified.
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module
(import "env" "memory" (memory 1 2048))
Expand All @@ -119,6 +141,7 @@ mod tests {
);
assert_matches!(r, Err(_));
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module
(import "env" "memory" (memory 1 2048))
Expand All @@ -131,16 +154,21 @@ mod tests {

#[test]
fn imports() {
with_vm_variants(|kind| {
let config = VMConfig::test();
with_vm_variants(&config, |kind| {
// nothing can be imported from non-"env" module for now.
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "another_module" "memory" (memory 1 1)))"#,
);
assert_matches!(r, Err(PrepareError::Instantiate));

let r =
parse_and_prepare_wat(kind, r#"(module (import "env" "gas" (func (param i32))))"#);
let r = parse_and_prepare_wat(
&config,
kind,
r#"(module (import "env" "gas" (func (param i32))))"#,
);
assert_matches!(r, Ok(_));

// TODO: Address tests once we check proper function signatures.
Expand Down
10 changes: 8 additions & 2 deletions runtime/near-vm-runner/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ mod ts_contract;
mod wasm_validation;

use crate::vm_kind::VMKind;
use near_primitives::config::ContractPrepareVersion;
use near_primitives::version::ProtocolVersion;
use near_vm_logic::VMContext;
use near_vm_logic::{VMConfig, VMContext};

const CURRENT_ACCOUNT_ID: &str = "alice";
const SIGNER_ACCOUNT_ID: &str = "bob";
Expand All @@ -18,7 +19,7 @@ const PREDECESSOR_ACCOUNT_ID: &str = "carol";

const LATEST_PROTOCOL_VERSION: ProtocolVersion = ProtocolVersion::MAX;

pub(crate) fn with_vm_variants(runner: fn(VMKind) -> ()) {
pub(crate) fn with_vm_variants(cfg: &VMConfig, runner: impl Fn(VMKind) -> ()) {
#[cfg(all(feature = "wasmer0_vm", target_arch = "x86_64"))]
runner(VMKind::Wasmer0);

Expand All @@ -27,6 +28,11 @@ pub(crate) fn with_vm_variants(runner: fn(VMKind) -> ()) {

#[cfg(all(feature = "wasmer2_vm", target_arch = "x86_64"))]
runner(VMKind::Wasmer2);

#[cfg(all(feature = "near_vm", target_arch = "x86_64"))]
if cfg.limit_config.contract_prepare_version == ContractPrepareVersion::V2 {
runner(VMKind::NearVm);
}
}

fn create_context(input: Vec<u8>) -> VMContext {
Expand Down
20 changes: 12 additions & 8 deletions runtime/near-vm-runner/src/tests/cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ use wasmer_engine::Executable;

#[test]
fn test_caches_compilation_error() {
with_vm_variants(|vm_kind: VMKind| {
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
match vm_kind {
VMKind::Wasmer0 | VMKind::Wasmer2 | VMKind::NearVm => {}
VMKind::Wasmtime => return,
Expand All @@ -33,20 +34,21 @@ fn test_caches_compilation_error() {
let terragas = 1000000000000u64;
assert_eq!(cache.len(), 0);
let outcome1 =
make_cached_contract_call_vm(&cache, &code, "method_name1", terragas, vm_kind)
make_cached_contract_call_vm(&config, &cache, &code, "method_name1", terragas, vm_kind)
.expect("bad failure");
println!("{:?}", cache);
assert_eq!(cache.len(), 1);
let outcome2 =
make_cached_contract_call_vm(&cache, &code, "method_name2", terragas, vm_kind)
make_cached_contract_call_vm(&config, &cache, &code, "method_name2", terragas, vm_kind)
.expect("bad failure");
assert_eq!(outcome1.aborted.as_ref(), outcome2.aborted.as_ref());
})
}

#[test]
fn test_does_not_cache_io_error() {
with_vm_variants(|vm_kind: VMKind| {
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
match vm_kind {
VMKind::Wasmer0 | VMKind::Wasmer2 | VMKind::NearVm => {}
VMKind::Wasmtime => return,
Expand All @@ -57,14 +59,16 @@ fn test_does_not_cache_io_error() {
let mut cache = FaultingCompiledContractCache::default();

cache.set_read_fault(true);
let result = make_cached_contract_call_vm(&cache, &code, "main", prepaid_gas, vm_kind);
let result =
make_cached_contract_call_vm(&config, &cache, &code, "main", prepaid_gas, vm_kind);
assert_matches!(
result.err(),
Some(VMRunnerError::CacheError(near_vm_errors::CacheError::ReadError(_)))
);

cache.set_write_fault(true);
let result = make_cached_contract_call_vm(&cache, &code, "main", prepaid_gas, vm_kind);
let result =
make_cached_contract_call_vm(&config, &cache, &code, "main", prepaid_gas, vm_kind);
assert_matches!(
result.err(),
Some(VMRunnerError::CacheError(near_vm_errors::CacheError::WriteError(_)))
Expand All @@ -73,6 +77,7 @@ fn test_does_not_cache_io_error() {
}

fn make_cached_contract_call_vm(
config: &VMConfig,
cache: &dyn CompiledContractCache,
code: &[u8],
method_name: &str,
Expand All @@ -81,12 +86,11 @@ fn make_cached_contract_call_vm(
) -> VMResult {
let mut fake_external = MockedExternal::new();
let mut context = create_context(vec![]);
let config = VMConfig::test();
let fees = RuntimeFeesConfig::test();
let promise_results = vec![];
context.prepaid_gas = prepaid_gas;
let code = ContractCode::new(code.to_vec(), None);
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");
runtime.run(
&code,
method_name,
Expand Down
68 changes: 37 additions & 31 deletions runtime/near-vm-runner/src/tests/rs_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ fn assert_run_result(result: VMResult, expected_value: u64) {

#[test]
pub fn test_read_write() {
with_vm_variants(|vm_kind: VMKind| {
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
let code = test_contract();
let mut fake_external = MockedExternal::new();

let context = create_context(encode(&[10u64, 20u64]));
let config = VMConfig::test();
let fees = RuntimeFeesConfig::test();

let promise_results = vec![];
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");
let result = runtime.run(
&code,
"write_key_value",
Expand Down Expand Up @@ -78,30 +78,34 @@ macro_rules! def_test_ext {
($name:ident, $method:expr, $expected:expr, $input:expr, $validator:expr) => {
#[test]
pub fn $name() {
with_vm_variants(|vm_kind: VMKind| {
run_test_ext($method, $expected, $input, $validator, vm_kind)
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
run_test_ext(&config, $method, $expected, $input, $validator, vm_kind)
});
}
};
($name:ident, $method:expr, $expected:expr, $input:expr) => {
#[test]
pub fn $name() {
with_vm_variants(|vm_kind: VMKind| {
run_test_ext($method, $expected, $input, vec![], vm_kind)
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
run_test_ext(&config, $method, $expected, $input, vec![], vm_kind)
});
}
};
($name:ident, $method:expr, $expected:expr) => {
#[test]
pub fn $name() {
with_vm_variants(|vm_kind: VMKind| {
run_test_ext($method, $expected, &[], vec![], vm_kind)
let config = VMConfig::test();
with_vm_variants(&config, |vm_kind: VMKind| {
run_test_ext(&config, $method, $expected, &[], vec![], vm_kind)
})
}
};
}

fn run_test_ext(
config: &VMConfig,
method: &str,
expected: &[u8],
input: &[u8],
Expand All @@ -112,10 +116,9 @@ fn run_test_ext(
let mut fake_external = MockedExternal::new();
fake_external.validators =
validators.into_iter().map(|(s, b)| (s.parse().unwrap(), b)).collect();
let config = VMConfig::test();
let fees = RuntimeFeesConfig::test();
let context = create_context(input.to_vec());
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");

let outcome = runtime
.run(&code, method, &mut fake_external, context, &fees, &[], LATEST_PROTOCOL_VERSION, None)
Expand Down Expand Up @@ -194,7 +197,8 @@ def_test_ext!(

#[test]
pub fn test_out_of_memory() {
with_vm_variants(|vm_kind: VMKind| {
let config = VMConfig::free();
with_vm_variants(&config, |vm_kind: VMKind| {
// TODO: currently we only run this test on Wasmer.
match vm_kind {
VMKind::Wasmtime => return,
Expand All @@ -205,9 +209,8 @@ pub fn test_out_of_memory() {
let mut fake_external = MockedExternal::new();

let context = create_context(Vec::new());
let config = VMConfig::free();
let fees = RuntimeFeesConfig::free();
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");

let promise_results = vec![];
let result = runtime
Expand Down Expand Up @@ -239,24 +242,26 @@ fn function_call_weight_contract() -> ContractCode {

#[test]
fn attach_unspent_gas_but_burn_all_gas() {
with_vm_variants(|vm_kind: VMKind| {
let prepaid_gas = 100 * 10u64.pow(12);

let mut context = create_context(vec![]);
context.prepaid_gas = prepaid_gas;

let mut config = VMConfig::test();
config.limit_config.max_gas_burnt = context.prepaid_gas / 3;

with_vm_variants(&config, |vm_kind: VMKind| {
let code = function_call_weight_contract();
let mut external = MockedExternal::new();
let mut config = VMConfig::test();
let fees = RuntimeFeesConfig::test();
let mut context = create_context(vec![]);

let prepaid_gas = 100 * 10u64.pow(12);
context.prepaid_gas = prepaid_gas;
config.limit_config.max_gas_burnt = context.prepaid_gas / 3;
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");

let outcome = runtime
.run(
&code,
"attach_unspent_gas_but_burn_all_gas",
&mut external,
context,
context.clone(),
&fees,
&[],
LATEST_PROTOCOL_VERSION,
Expand All @@ -280,23 +285,24 @@ fn attach_unspent_gas_but_burn_all_gas() {

#[test]
fn attach_unspent_gas_but_use_all_gas() {
with_vm_variants(|vm_kind: VMKind| {
let mut context = create_context(vec![]);
context.prepaid_gas = 100 * 10u64.pow(12);

let mut config = VMConfig::test();
config.limit_config.max_gas_burnt = context.prepaid_gas / 3;

with_vm_variants(&config, |vm_kind: VMKind| {
let code = function_call_weight_contract();
let mut external = MockedExternal::new();
let mut config = VMConfig::test();
let fees = RuntimeFeesConfig::test();
let mut context = create_context(vec![]);

context.prepaid_gas = 100 * 10u64.pow(12);
config.limit_config.max_gas_burnt = context.prepaid_gas / 3;
let runtime = vm_kind.runtime(config).expect("runtime has not been compiled");
let runtime = vm_kind.runtime(config.clone()).expect("runtime has not been compiled");

let outcome = runtime
.run(
&code,
"attach_unspent_gas_but_use_all_gas",
&mut external,
context,
context.clone(),
&fees,
&[],
LATEST_PROTOCOL_VERSION,
Expand Down
Loading

0 comments on commit f4e882a

Please sign in to comment.