From e7aa428cac87227287a431c2f800d40a129cb689 Mon Sep 17 00:00:00 2001 From: George Mitenkov Date: Thu, 14 Nov 2024 21:10:20 +0000 Subject: [PATCH] Loader V2 refactoring: - Unify imports - Move environment from storages into ModuleBytesStorages - Move unsync code storage implementation tests - Remove V1 loader test flows --- Cargo.lock | 2 + .../aptos-vm-profiling/src/bins/run_move.rs | 4 +- .../state_view_adapter.rs | 29 +- aptos-move/vm-genesis/src/lib.rs | 12 +- .../move/move-vm/integration-tests/Cargo.toml | 1 + .../src/tests/bad_entry_point_tests.rs | 16 +- .../src/tests/bad_storage_tests.rs | 165 ++--- .../src/tests/binary_format_version.rs | 94 +-- .../src/tests/code_storage_tests.rs | 294 +++++++++ .../src/tests/exec_func_effects_tests.rs | 14 +- .../src/tests/function_arg_tests.rs | 8 +- .../src/tests/instantiation_tests.rs | 28 +- .../src/tests/invariant_violation_tests.rs | 4 +- .../integration-tests/src/tests/leak_tests.rs | 4 +- .../src/tests/loader_tests.rs | 570 +++--------------- .../integration-tests/src/tests/mod.rs | 1 + .../src/tests/mutated_accounts_tests.rs | 11 +- .../src/tests/native_tests.rs | 38 +- .../src/tests/nested_loop_tests.rs | 48 +- .../src/tests/regression_tests.rs | 5 +- .../src/tests/return_value_tests.rs | 8 +- .../tests/runtime_reentrancy_check_tests.rs | 70 +-- .../src/tests/vm_arguments_tests.rs | 14 +- third_party/move/move-vm/runtime/src/lib.rs | 2 - .../move/move-vm/runtime/src/session.rs | 70 +-- .../runtime/src/storage/code_storage.rs | 4 +- .../src/storage/implementations/mod.rs | 2 - .../unreachable_code_storage.rs | 83 --- .../implementations/unsync_code_storage.rs | 123 +--- .../implementations/unsync_module_storage.rs | 296 +-------- .../move-vm/runtime/src/storage/loader.rs | 4 +- .../runtime/src/storage/module_storage.rs | 2 +- .../move-vm/runtime/src/storage/publishing.rs | 33 +- .../move/move-vm/test-utils/Cargo.toml | 1 + .../move/move-vm/test-utils/src/storage.rs | 35 +- .../testing-infra/test-generation/src/lib.rs | 11 +- .../src/vm_test_harness.rs | 234 ++----- .../tools/move-unit-test/src/test_runner.rs | 29 +- 38 files changed, 840 insertions(+), 1529 deletions(-) create mode 100644 third_party/move/move-vm/integration-tests/src/tests/code_storage_tests.rs delete mode 100644 third_party/move/move-vm/runtime/src/storage/implementations/unreachable_code_storage.rs diff --git a/Cargo.lock b/Cargo.lock index 92ed495d200d70..0e3e7f16976cee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11805,6 +11805,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bytes", + "claims", "memory-stats", "move-binary-format", "move-bytecode-verifier", @@ -11876,6 +11877,7 @@ dependencies = [ "move-bytecode-utils", "move-core-types", "move-table-extension", + "move-vm-runtime", "move-vm-types", "once_cell", "serde", diff --git a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs index 667a7c49c0bb40..7cfaccb677a879 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_move.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_move.rs @@ -161,7 +161,7 @@ fn main() -> Result<()> { let runtime_environment = RuntimeEnvironment::new(natives); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut storage = InMemoryStorage::new(); + let mut storage = InMemoryStorage::new(runtime_environment); let test_modules = compile_test_modules(); for module in &test_modules { @@ -188,7 +188,7 @@ fn main() -> Result<()> { let mut sess = vm.new_session_with_extensions(&storage, extensions); let traversal_storage = TraversalStorage::new(); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let args: Vec> = vec![]; match entrypoint { diff --git a/aptos-move/aptos-vm-types/src/module_and_script_storage/state_view_adapter.rs b/aptos-move/aptos-vm-types/src/module_and_script_storage/state_view_adapter.rs index 64627c634797d8..dd7ada09c59acd 100644 --- a/aptos-move/aptos-vm-types/src/module_and_script_storage/state_view_adapter.rs +++ b/aptos-move/aptos-vm-types/src/module_and_script_storage/state_view_adapter.rs @@ -31,11 +31,14 @@ use move_vm_types::{ use std::{ops::Deref, sync::Arc}; /// Avoids orphan rule to implement [ModuleBytesStorage] for [StateView]. -struct StateViewAdapter<'s, S> { +struct StateViewAdapter<'s, S, E> { + environment: E, state_view: BorrowedOrOwned<'s, S>, } -impl<'s, S: StateView> ModuleBytesStorage for StateViewAdapter<'s, S> { +impl<'s, S: StateView, E: WithRuntimeEnvironment> ModuleBytesStorage + for StateViewAdapter<'s, S, E> +{ fn fetch_module_bytes( &self, address: &AccountAddress, @@ -48,7 +51,15 @@ impl<'s, S: StateView> ModuleBytesStorage for StateViewAdapter<'s, S> { } } -impl<'s, S: StateView> Deref for StateViewAdapter<'s, S> { +impl<'s, S: StateView, E: WithRuntimeEnvironment> WithRuntimeEnvironment + for StateViewAdapter<'s, S, E> +{ + fn runtime_environment(&self) -> &RuntimeEnvironment { + self.environment.runtime_environment() + } +} + +impl<'s, S: StateView, E: WithRuntimeEnvironment> Deref for StateViewAdapter<'s, S, E> { type Target = S; fn deref(&self) -> &Self::Target { @@ -67,27 +78,29 @@ impl<'s, S: StateView> Deref for StateViewAdapter<'s, S> { #[delegate(ModuleStorage, where = "S: StateView, E: WithRuntimeEnvironment")] #[delegate(CodeStorage, where = "S: StateView, E: WithRuntimeEnvironment")] pub struct AptosCodeStorageAdapter<'s, S, E> { - storage: UnsyncCodeStorage, E>>, + storage: UnsyncCodeStorage>>, } impl<'s, S: StateView, E: WithRuntimeEnvironment> AptosCodeStorageAdapter<'s, S, E> { /// Creates new instance of [AptosCodeStorageAdapter] built on top of the passed state view and /// the provided runtime environment. - fn from_borrowed(state_view: &'s S, runtime_environment: E) -> Self { + fn from_borrowed(state_view: &'s S, environment: E) -> Self { let adapter = StateViewAdapter { + environment, state_view: BorrowedOrOwned::Borrowed(state_view), }; - let storage = adapter.into_unsync_code_storage(runtime_environment); + let storage = adapter.into_unsync_code_storage(); Self { storage } } /// Creates new instance of [AptosCodeStorageAdapter] capturing the passed state view and the /// provided environment. - fn from_owned(state_view: S, runtime_environment: E) -> Self { + fn from_owned(state_view: S, environment: E) -> Self { let adapter = StateViewAdapter { + environment, state_view: BorrowedOrOwned::Owned(state_view), }; - let storage = adapter.into_unsync_code_storage(runtime_environment); + let storage = adapter.into_unsync_code_storage(); Self { storage } } diff --git a/aptos-move/vm-genesis/src/lib.rs b/aptos-move/vm-genesis/src/lib.rs index 23ad6125e7d079..03cadbb7d6ccab 100644 --- a/aptos-move/vm-genesis/src/lib.rs +++ b/aptos-move/vm-genesis/src/lib.rs @@ -53,7 +53,10 @@ use aptos_vm_types::{ }; use bytes::Bytes; use claims::assert_ok; -use move_binary_format::errors::{Location, VMResult}; +use move_binary_format::{ + compatibility::Compatibility, + errors::{Location, VMResult}, +}; use move_core_types::{ account_address::AccountAddress, identifier::Identifier, @@ -992,7 +995,12 @@ fn publish_framework_with_loader_v1( #[allow(deprecated)] session - .publish_module_bundle(code, addr, &mut UnmeteredGasMeter) + .publish_module_bundle_with_compat_config( + code, + addr, + &mut UnmeteredGasMeter, + Compatibility::full_check(), + ) .unwrap_or_else(|e| { panic!( "Failure publishing package `{}`: {:?}", diff --git a/third_party/move/move-vm/integration-tests/Cargo.toml b/third_party/move/move-vm/integration-tests/Cargo.toml index 99a7339b94520d..466ef5831853e4 100644 --- a/third_party/move/move-vm/integration-tests/Cargo.toml +++ b/third_party/move/move-vm/integration-tests/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" [dependencies] anyhow = { workspace = true } bytes = { workspace = true } +claims = { workspace = true } memory-stats = { workspace = true } move-binary-format = { path = "../../move-binary-format", features = ["testing"] } move-bytecode-verifier = { path = "../../move-bytecode-verifier" } diff --git a/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs index f2addec560a54a..4d3e1e4c248bff 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/bad_entry_point_tests.rs @@ -12,8 +12,9 @@ use move_core_types::{ }; use move_vm_runtime::{ module_traversal::*, move_vm::MoveVM, AsUnsyncModuleStorage, RuntimeEnvironment, + WithRuntimeEnvironment, }; -use move_vm_test_utils::{BlankStorage, InMemoryStorage}; +use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGTH]); @@ -22,13 +23,13 @@ const TEST_ADDR: AccountAddress = AccountAddress::new([42; AccountAddress::LENGT fn call_non_existent_module() { let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let storage = BlankStorage; + let storage = InMemoryStorage::new(runtime_environment); let mut sess = vm.new_session(&storage); let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); let fun_name = Identifier::new("foo").unwrap(); let traversal_storage = TraversalStorage::new(); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -57,18 +58,19 @@ fn call_non_existent_function() { let mut blob = vec![]; m.serialize(&mut blob).unwrap(); - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut storage = InMemoryStorage::new(runtime_environment); + let module_id = ModuleId::new(TEST_ADDR, Identifier::new("M").unwrap()); storage.add_module_bytes(module_id.address(), module_id.name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let vm = MoveVM::new_with_runtime_environment(storage.runtime_environment()); let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); let traversal_storage = TraversalStorage::new(); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( diff --git a/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs index cbc19460eca723..8c0d8c38f8f808 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/bad_storage_tests.rs @@ -15,7 +15,7 @@ use move_core_types::{ }; use move_vm_runtime::{ module_traversal::*, move_vm::MoveVM, AsUnsyncCodeStorage, AsUnsyncModuleStorage, - RuntimeEnvironment, + RuntimeEnvironment, WithRuntimeEnvironment, }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{ @@ -80,7 +80,14 @@ fn test_malformed_resource() { let m = as_module(units.pop().unwrap()); let ms = as_module(units.pop().unwrap()); - let mut storage = InMemoryStorage::new(); + let natives = move_stdlib::natives::all_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), + ); + let runtime_environment = RuntimeEnvironment::new(natives); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + + let mut storage = InMemoryStorage::new(runtime_environment); // Publish module Signer and module M. let mut blob = vec![]; @@ -91,22 +98,13 @@ fn test_malformed_resource() { m.serialize(&mut blob).unwrap(); storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let natives = move_stdlib::natives::all_natives( - AccountAddress::from_hex_literal("0x1").unwrap(), - move_stdlib::natives::GasParameters::zeros(), - ); - let runtime_environment = RuntimeEnvironment::new(natives); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - // Execute the first script to publish a resource Foo. let mut script_blob = vec![]; s1.serialize(&mut script_blob).unwrap(); let mut sess = vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); - let code_storage = storage - .clone() - .into_unsync_code_storage(runtime_environment); + let code_storage = storage.clone().into_unsync_code_storage(); sess.execute_script( script_blob, @@ -194,14 +192,15 @@ fn test_malformed_module() { // Publish M and call M::foo. No errors should be thrown. { - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(m.self_addr(), m.self_name(), blob.clone().into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(m.self_addr(), m.self_name(), blob.clone().into()); + let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &module_id, @@ -226,14 +225,15 @@ fn test_malformed_module() { blob[1] = 0xAD; blob[2] = 0xBE; blob[3] = 0xEF; - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); + let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -269,18 +269,17 @@ fn test_unverifiable_module() { // Publish M and call M::foo to make sure it works. { - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); let mut blob = vec![]; m.serialize(&mut blob).unwrap(); storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment.clone()); - + let module_storage = storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &module_id, &fun_name, @@ -296,7 +295,9 @@ fn test_unverifiable_module() { // Erase the body of M::foo to make it fail verification. // Publish this modified version of M and the VM should fail to load it. { - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); let mut m = m; m.function_defs[0].code.as_mut().unwrap().code = vec![]; @@ -304,11 +305,9 @@ fn test_unverifiable_module() { m.serialize(&mut blob).unwrap(); storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -356,16 +355,16 @@ fn test_missing_module_dependency() { // Publish M and N and call N::bar. Everything should work. { - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); storage.add_module_bytes(m.self_addr(), m.self_name(), blob_m.into()); storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.clone().into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment.clone()); + let module_storage = storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &module_id, @@ -382,14 +381,14 @@ fn test_missing_module_dependency() { // Publish only N and try to call N::bar. The VM should fail to find M and raise // an invariant violation. { - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.into()); + + let mut sess = vm.new_session(&storage); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -437,16 +436,16 @@ fn test_malformed_module_dependency() { // Publish M and N and call N::bar. Everything should work. { - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); storage.add_module_bytes(m.self_addr(), m.self_name(), blob_m.clone().into()); storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.clone().into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment.clone()); + let module_storage = storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &module_id, @@ -467,16 +466,16 @@ fn test_malformed_module_dependency() { blob_m[2] = 0xBE; blob_m[3] = 0xEF; - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); storage.add_module_bytes(m.self_addr(), m.self_name(), blob_m.into()); storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -525,16 +524,16 @@ fn test_unverifiable_module_dependency() { let mut blob_m = vec![]; m.serialize(&mut blob_m).unwrap(); - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); storage.add_module_bytes(m.self_addr(), m.self_name(), blob_m.into()); storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.clone().into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment.clone()); + let module_storage = storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &module_id, @@ -555,16 +554,16 @@ fn test_unverifiable_module_dependency() { let mut blob_m = vec![]; m.serialize(&mut blob_m).unwrap(); - let mut storage = InMemoryStorage::new(); + let runtime_environment = RuntimeEnvironment::new(vec![]); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); storage.add_module_bytes(m.self_addr(), m.self_name(), blob_m.into()); storage.add_module_bytes(n.self_addr(), n.self_name(), blob_n.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( @@ -596,6 +595,12 @@ impl ModuleBytesStorage for BogusModuleStorage { } } +impl WithRuntimeEnvironment for BogusModuleStorage { + fn runtime_environment(&self) -> &RuntimeEnvironment { + unreachable!("Irrelevant for tests") + } +} + impl ModuleResolver for BogusModuleStorage { fn get_module_metadata(&self, _module_id: &ModuleId) -> Vec { vec![] @@ -671,7 +676,7 @@ fn test_storage_returns_bogus_error_when_loading_module() { let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let err = sess .execute_function_bypass_visibility( &module_id, @@ -684,25 +689,21 @@ fn test_storage_returns_bogus_error_when_loading_module() { ) .unwrap_err(); - if !vm.vm_config().use_loader_v2 { - assert_eq!(err.major_status(), *error_code); + // TODO(loader_v2): + // Loader V2 remaps all deserialization and verification errors. Loader V1 does not + // remap them when module resolver is accessed, and only on verification steps. + // Strictly speaking, the storage would never return such an error so V2 behaviour is + // ok. Moreover, the fact that V1 still returns UNKNOWN_BINARY_ERROR and does not + // remap it is weird. + if *error_code == StatusCode::UNKNOWN_VERIFICATION_ERROR { + assert_eq!(err.major_status(), StatusCode::UNEXPECTED_VERIFIER_ERROR); + } else if *error_code == StatusCode::UNKNOWN_BINARY_ERROR { + assert_eq!( + err.major_status(), + StatusCode::UNEXPECTED_DESERIALIZATION_ERROR + ); } else { - // TODO(loader_v2): - // Loader V2 remaps all deserialization and verification errors. Loader V1 does not - // remap them when module resolver is accessed, and only on verification steps. - // Strictly speaking, the storage would never return such an error so V2 behaviour is - // ok. Moreover, the fact that V1 still returns UNKNOWN_BINARY_ERROR and does not - // remap it is weird. - if *error_code == StatusCode::UNKNOWN_VERIFICATION_ERROR { - assert_eq!(err.major_status(), StatusCode::UNEXPECTED_VERIFIER_ERROR); - } else if *error_code == StatusCode::UNKNOWN_BINARY_ERROR { - assert_eq!( - err.major_status(), - StatusCode::UNEXPECTED_DESERIALIZATION_ERROR - ); - } else { - assert_eq!(err.major_status(), *error_code); - } + assert_eq!(err.major_status(), *error_code); } } } @@ -748,25 +749,25 @@ fn test_storage_returns_bogus_error_when_loading_resource() { let traversal_storage = TraversalStorage::new(); for error_code in LIST_OF_ERROR_CODES { - let mut module_storage = InMemoryStorage::new(); + let natives = move_stdlib::natives::all_natives( + AccountAddress::from_hex_literal("0x1").unwrap(), + move_stdlib::natives::GasParameters::zeros(), + ); + let runtime_environment = RuntimeEnvironment::new(natives); + let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + + let mut module_storage = InMemoryStorage::new(runtime_environment); module_storage.add_module_bytes(m.self_addr(), m.self_name(), m_blob.clone().into()); module_storage.add_module_bytes(s.self_addr(), s.self_name(), s_blob.clone().into()); + let storage = BogusResourceStorage { module_storage, bad_status_code: *error_code, }; - let natives = move_stdlib::natives::all_natives( - AccountAddress::from_hex_literal("0x1").unwrap(), - move_stdlib::natives::GasParameters::zeros(), - ); - let runtime_environment = RuntimeEnvironment::new(natives); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); let mut sess = vm.new_session(&storage); - let module_storage = storage - .module_storage - .as_unsync_module_storage(runtime_environment); + let module_storage = storage.module_storage.as_unsync_module_storage(); sess.execute_function_bypass_visibility( &m_id, diff --git a/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs b/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs index a80b0b65a56c89..14ac7a507a57b0 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/binary_format_version.rs @@ -26,49 +26,27 @@ fn test_publish_module_with_custom_max_binary_format_version() { // Should accept both modules with the default settings { - let storage = InMemoryStorage::new(); - let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), ); let runtime_environment = RuntimeEnvironment::new(natives); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut sess = vm.new_session(&storage); + let storage = InMemoryStorage::new(runtime_environment); - if vm.vm_config().use_loader_v2 { - let module_storage = storage.as_unsync_module_storage(runtime_environment); - let new_module_storage = - StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_new - .clone() - .into()]) - .expect("New module should be publishable"); - StagingModuleStorage::create(m.self_addr(), &new_module_storage, vec![b_old + let module_storage = storage.as_unsync_module_storage(); + let new_module_storage = + StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_new .clone() .into()]) - .expect("Old module should be publishable"); - } else { - #[allow(deprecated)] - sess.publish_module_bundle( - vec![b_new.clone()], - *m.self_id().address(), - &mut UnmeteredGasMeter, - ) - .unwrap(); - - #[allow(deprecated)] - sess.publish_module_bundle( - vec![b_old.clone()], - *m.self_id().address(), - &mut UnmeteredGasMeter, - ) - .unwrap(); - } + .expect("New module should be publishable"); + StagingModuleStorage::create(m.self_addr(), &new_module_storage, vec![b_old + .clone() + .into()]) + .expect("Old module should be publishable"); } // Should reject the module with newer version with max binary format version being set to VERSION_MAX - 1 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -81,43 +59,19 @@ fn test_publish_module_with_custom_max_binary_format_version() { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut sess = vm.new_session(&storage); - - if vm.vm_config().use_loader_v2 { - let module_storage = storage.as_unsync_module_storage(runtime_environment); - let result = StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_new - .clone() - .into()]); - if let Err(err) = result { - assert_eq!(err.major_status(), StatusCode::UNKNOWN_VERSION); - } else { - panic!("Module publishing should fail") - } - StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_old - .clone() - .into()]) - .unwrap(); + let storage = InMemoryStorage::new(runtime_environment); + + let module_storage = storage.as_unsync_module_storage(); + let result = StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_new + .clone() + .into()]); + if let Err(err) = result { + assert_eq!(err.major_status(), StatusCode::UNKNOWN_VERSION); } else { - #[allow(deprecated)] - let s = sess - .publish_module_bundle( - vec![b_new.clone()], - *m.self_id().address(), - &mut UnmeteredGasMeter, - ) - .unwrap_err() - .major_status(); - assert_eq!(s, StatusCode::UNKNOWN_VERSION); - - #[allow(deprecated)] - sess.publish_module_bundle( - vec![b_old.clone()], - *m.self_id().address(), - &mut UnmeteredGasMeter, - ) - .unwrap(); + panic!("Module publishing should fail") } + StagingModuleStorage::create(m.self_addr(), &module_storage, vec![b_old.clone().into()]) + .unwrap(); } } @@ -134,15 +88,15 @@ fn test_run_script_with_custom_max_binary_format_version() { // Should accept both modules with the default settings { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), ); let runtime_environment = RuntimeEnvironment::new(natives); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let storage = InMemoryStorage::new(runtime_environment); let mut sess = vm.new_session(&storage); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let args: Vec> = vec![]; sess.execute_script( @@ -168,7 +122,6 @@ fn test_run_script_with_custom_max_binary_format_version() { // Should reject the module with newer version with max binary format version being set to VERSION_MAX - 1 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -182,8 +135,9 @@ fn test_run_script_with_custom_max_binary_format_version() { }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let storage = InMemoryStorage::new(runtime_environment); let mut sess = vm.new_session(&storage); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let args: Vec> = vec![]; assert_eq!( diff --git a/third_party/move/move-vm/integration-tests/src/tests/code_storage_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/code_storage_tests.rs new file mode 100644 index 00000000000000..94638d4a2a0d43 --- /dev/null +++ b/third_party/move/move-vm/integration-tests/src/tests/code_storage_tests.rs @@ -0,0 +1,294 @@ +// Copyright (c) The Move Contributors +// SPDX-License-Identifier: Apache-2.0 + +use bytes::Bytes; +use claims::{assert_err, assert_none, assert_ok, assert_some, assert_some_eq}; +use move_binary_format::{ + file_format::{empty_module_with_dependencies_and_friends, empty_script_with_dependencies}, + file_format_common::VERSION_MAX, + CompiledModule, +}; +use move_core_types::{ + account_address::AccountAddress, ident_str, identifier::Identifier, language_storage::ModuleId, + vm_status::StatusCode, +}; +use move_vm_runtime::{ + AsUnsyncCodeStorage, AsUnsyncModuleStorage, CodeStorage, ModuleStorage, RuntimeEnvironment, +}; +use move_vm_test_utils::InMemoryStorage; +use move_vm_types::sha3_256; + +fn make_script<'a>(dependencies: impl IntoIterator) -> Vec { + let script = empty_script_with_dependencies(dependencies); + + let mut serialized_script = vec![]; + assert_ok!(script.serialize_for_version(Some(VERSION_MAX), &mut serialized_script)); + serialized_script +} + +fn make_module<'a>( + module_name: &'a str, + dependencies: impl IntoIterator, + friends: impl IntoIterator, +) -> (CompiledModule, Bytes) { + let module = empty_module_with_dependencies_and_friends(module_name, dependencies, friends); + + let mut module_bytes = vec![]; + assert_ok!(module.serialize_for_version(Some(VERSION_MAX), &mut module_bytes)); + + (module, module_bytes.into()) +} + +fn add_module_bytes<'a>( + module_bytes_storage: &mut InMemoryStorage, + module_name: &'a str, + dependencies: impl IntoIterator, + friends: impl IntoIterator, +) { + let (module, bytes) = make_module(module_name, dependencies, friends); + module_bytes_storage.add_module_bytes(module.self_addr(), module.self_name(), bytes); +} + +#[test] +fn test_deserialized_script_caching() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); + + let code_storage = module_bytes_storage.into_unsync_code_storage(); + + let serialized_script = make_script(vec!["a"]); + let hash_1 = sha3_256(&serialized_script); + assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); + + let serialized_script = make_script(vec!["b"]); + let hash_2 = sha3_256(&serialized_script); + assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); + + code_storage.assert_cached_state(vec![&hash_1, &hash_2], vec![]); +} + +#[test] +fn test_verified_script_caching() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); + + let code_storage = module_bytes_storage.into_unsync_code_storage(); + + let serialized_script = make_script(vec!["a"]); + let hash = sha3_256(&serialized_script); + assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); + + // Nothing gets loaded into module cache. + code_storage + .module_storage() + .assert_cached_state(vec![], vec![]); + code_storage.assert_cached_state(vec![&hash], vec![]); + + assert_ok!(code_storage.verify_and_cache_script(&serialized_script)); + + // Script is verified, so its dependencies are loaded into cache. + code_storage + .module_storage() + .assert_cached_state(vec![], vec![&a_id, &b_id, &c_id]); + code_storage.assert_cached_state(vec![], vec![&hash]); +} + +#[test] +fn test_module_does_not_exist() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let module_storage = InMemoryStorage::new(runtime_environment).into_unsync_module_storage(); + + let result = module_storage.check_module_exists(&AccountAddress::ZERO, ident_str!("a")); + assert!(!assert_ok!(result)); + + let result = module_storage.fetch_module_size_in_bytes(&AccountAddress::ZERO, ident_str!("a")); + assert_none!(assert_ok!(result)); + + let result = module_storage.fetch_module_metadata(&AccountAddress::ZERO, ident_str!("a")); + assert_none!(assert_ok!(result)); + + let result = module_storage.fetch_deserialized_module(&AccountAddress::ZERO, ident_str!("a")); + assert_none!(assert_ok!(result)); + + let result = module_storage.fetch_verified_module(&AccountAddress::ZERO, ident_str!("a")); + assert_none!(assert_ok!(result)); +} + +#[test] +fn test_module_exists() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + add_module_bytes(&mut module_bytes_storage, "a", vec![], vec![]); + let id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + assert!(assert_ok!( + module_storage.check_module_exists(id.address(), id.name()) + )); + module_storage.assert_cached_state(vec![&id], vec![]); +} + +#[test] +fn test_deserialized_caching() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec!["d", "e"], vec![]); + add_module_bytes(&mut module_bytes_storage, "d", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "e", vec![], vec![]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + let result = module_storage.fetch_module_metadata(a_id.address(), a_id.name()); + let expected = make_module("a", vec!["b", "c"], vec![]).0.metadata; + assert_some_eq!(assert_ok!(result), expected); + module_storage.assert_cached_state(vec![&a_id], vec![]); + + let result = module_storage.fetch_deserialized_module(c_id.address(), c_id.name()); + let expected = make_module("c", vec!["d", "e"], vec![]).0; + assert_eq!(assert_some!(assert_ok!(result)).as_ref(), &expected); + module_storage.assert_cached_state(vec![&a_id, &c_id], vec![]); +} + +#[test] +fn test_dependency_tree_traversal() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + let d_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("d").unwrap()); + let e_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("e").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec!["d", "e"], vec![]); + add_module_bytes(&mut module_bytes_storage, "d", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "e", vec![], vec![]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + assert_ok!(module_storage.fetch_verified_module(c_id.address(), c_id.name())); + module_storage.assert_cached_state(vec![], vec![&c_id, &d_id, &e_id]); + + assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); + module_storage.assert_cached_state(vec![], vec![&a_id, &b_id, &c_id, &d_id, &e_id]); + + assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); +} + +#[test] +fn test_dependency_dag_traversal() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + let d_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("d").unwrap()); + let e_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("e").unwrap()); + let f_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("f").unwrap()); + let g_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("g").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec!["d"], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec!["d"], vec![]); + add_module_bytes(&mut module_bytes_storage, "d", vec!["e", "f"], vec![]); + add_module_bytes(&mut module_bytes_storage, "e", vec!["g"], vec![]); + add_module_bytes(&mut module_bytes_storage, "f", vec!["g"], vec![]); + add_module_bytes(&mut module_bytes_storage, "g", vec![], vec![]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + assert_ok!(module_storage.fetch_deserialized_module(a_id.address(), a_id.name())); + assert_ok!(module_storage.fetch_deserialized_module(c_id.address(), c_id.name())); + module_storage.assert_cached_state(vec![&a_id, &c_id], vec![]); + + assert_ok!(module_storage.fetch_verified_module(d_id.address(), d_id.name())); + module_storage.assert_cached_state(vec![&a_id, &c_id], vec![&d_id, &e_id, &f_id, &g_id]); + + assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); + module_storage.assert_cached_state(vec![], vec![ + &a_id, &b_id, &c_id, &d_id, &e_id, &f_id, &g_id, + ]); +} + +#[test] +fn test_cyclic_dependencies_traversal_fails() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b"], vec![]); + add_module_bytes(&mut module_bytes_storage, "b", vec!["c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec!["a"], vec![]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + let result = module_storage.fetch_verified_module(c_id.address(), c_id.name()); + assert_eq!( + assert_err!(result).major_status(), + StatusCode::CYCLIC_MODULE_DEPENDENCY + ); +} + +#[test] +fn test_cyclic_friends_are_allowed() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec![], vec!["b"]); + add_module_bytes(&mut module_bytes_storage, "b", vec![], vec!["c"]); + add_module_bytes(&mut module_bytes_storage, "c", vec![], vec!["a"]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + let result = module_storage.fetch_verified_module(c_id.address(), c_id.name()); + assert_ok!(result); + + // Since `c` has no dependencies, only it gets deserialized and verified. + module_storage.assert_cached_state(vec![], vec![&c_id]); +} + +#[test] +fn test_transitive_friends_are_allowed_to_be_transitive_dependencies() { + let runtime_environment = RuntimeEnvironment::new(vec![]); + let mut module_bytes_storage = InMemoryStorage::new(runtime_environment); + + let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); + let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); + let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); + + add_module_bytes(&mut module_bytes_storage, "a", vec!["b"], vec!["d"]); + add_module_bytes(&mut module_bytes_storage, "b", vec!["c"], vec![]); + add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); + add_module_bytes(&mut module_bytes_storage, "d", vec![], vec!["c"]); + + let module_storage = module_bytes_storage.into_unsync_module_storage(); + + assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); + module_storage.assert_cached_state(vec![], vec![&a_id, &b_id, &c_id]); +} diff --git a/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs index aa5ca7f8730c98..3e4955ed55e8ad 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/exec_func_effects_tests.rs @@ -95,12 +95,12 @@ fn run( ) -> VMResult<(ChangeSet, SerializedReturnValues)> { let module_id = &module.0; let modules = vec![module.clone()]; - let (runtime_environment, vm, storage) = setup_vm(&modules); + let (vm, storage) = setup_vm(&modules); let mut session = vm.new_session(&storage); let fun_name = Identifier::new(fun_name).unwrap(); let traversal_storage = TraversalStorage::new(); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); session .execute_function_bypass_visibility( @@ -121,12 +121,14 @@ fn run( type ModuleCode = (ModuleId, String); // TODO - move some utility functions to where test infra lives, see about unifying with similar code -fn setup_vm(modules: &[ModuleCode]) -> (RuntimeEnvironment, MoveVM, InMemoryStorage) { - let mut storage = InMemoryStorage::new(); - compile_modules(&mut storage, modules); +fn setup_vm(modules: &[ModuleCode]) -> (MoveVM, InMemoryStorage) { let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - (runtime_environment, vm, storage) + + let mut storage = InMemoryStorage::new(runtime_environment); + compile_modules(&mut storage, modules); + + (vm, storage) } fn compile_modules(storage: &mut InMemoryStorage, modules: &[ModuleCode]) { diff --git a/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs index af4a131afae6e6..598355037af03c 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/function_arg_tests.rs @@ -57,16 +57,16 @@ fn run( let mut blob = vec![]; m.serialize(&mut blob).unwrap(); - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); + let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); let traversal_storage = TraversalStorage::new(); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let args: Vec<_> = args .into_iter() diff --git a/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs index 023fb737b28e4d..a1a13cd0ae39c1 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/instantiation_tests.rs @@ -16,10 +16,9 @@ use move_core_types::{ }; use move_vm_runtime::{ config::VMConfig, move_vm::MoveVM, session::Session, AsUnsyncCodeStorage, ModuleStorage, - RuntimeEnvironment, StagingModuleStorage, + RuntimeEnvironment, StagingModuleStorage, WithRuntimeEnvironment, }; use move_vm_test_utils::InMemoryStorage; -use move_vm_types::gas::UnmeteredGasMeter; #[test] fn instantiation_err() { @@ -114,10 +113,8 @@ fn instantiation_err() { ..VMConfig::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let storage: InMemoryStorage = InMemoryStorage::new(runtime_environment); - let storage: InMemoryStorage = InMemoryStorage::new(); - let mut session = vm.new_session(&storage); let mut mod_bytes = vec![]; cm.serialize(&mut mod_bytes).unwrap(); @@ -132,21 +129,16 @@ fn instantiation_err() { })); } - let module_storage = storage.as_unsync_code_storage(runtime_environment); - // Publish (must succeed!) and then load the function. - if vm.vm_config().use_loader_v2 { - let new_module_storage = - StagingModuleStorage::create(&addr, &module_storage, vec![mod_bytes.into()]) - .expect("Module must publish"); - load_function(&mut session, &new_module_storage, &cm.self_id(), &[ty_arg]) - } else { - #[allow(deprecated)] - session - .publish_module(mod_bytes, addr, &mut UnmeteredGasMeter) + let module_storage = storage.as_unsync_code_storage(); + let new_module_storage = + StagingModuleStorage::create(&addr, &module_storage, vec![mod_bytes.into()]) .expect("Module must publish"); - load_function(&mut session, &module_storage, &cm.self_id(), &[ty_arg]) - } + + let vm = MoveVM::new_with_runtime_environment(storage.runtime_environment()); + let mut session = vm.new_session(&storage); + + load_function(&mut session, &new_module_storage, &cm.self_id(), &[ty_arg]) } fn load_function( diff --git a/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs index 351e9e6419166a..f014535fa2eb5f 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/invariant_violation_tests.rs @@ -76,13 +76,13 @@ fn merge_borrow_states_infinite_loop() { let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let storage: InMemoryStorage = InMemoryStorage::new(); + let storage: InMemoryStorage = InMemoryStorage::new(runtime_environment); let mut session = vm.new_session(&storage); let mut script_bytes = vec![]; cs.serialize(&mut script_bytes).unwrap(); let traversal_storage = TraversalStorage::new(); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let err = session .execute_script( diff --git a/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs index bc70b33b2f1f43..3ebff3b1993134 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/leak_tests.rs @@ -51,13 +51,13 @@ fn leak_with_abort() { let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let storage: InMemoryStorage = InMemoryStorage::new(); + let storage: InMemoryStorage = InMemoryStorage::new(runtime_environment); let mut session = vm.new_session(&storage); let mut script_bytes = vec![]; cs.serialize(&mut script_bytes).unwrap(); let traversal_storage = TraversalStorage::new(); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); for _ in 0..100_000 { let _ = session.execute_script( diff --git a/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs index e63ac3c93f6744..f56eb79c30454f 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/loader_tests.rs @@ -11,7 +11,6 @@ use move_binary_format::{ }, CompiledModule, }; -use move_bytecode_verifier::VerifierConfig; use move_core_types::{ account_address::AccountAddress, ident_str, @@ -19,25 +18,23 @@ use move_core_types::{ language_storage::ModuleId, }; use move_vm_runtime::{ - config::VMConfig, module_traversal::*, move_vm::MoveVM, - unreachable_code_storage::UnreachableCodeStorage, AsUnsyncModuleStorage, ModuleStorage, - RuntimeEnvironment, StagingModuleStorage, + module_traversal::*, move_vm::MoveVM, AsUnsyncModuleStorage, ModuleStorage, RuntimeEnvironment, + StagingModuleStorage, }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::gas::UnmeteredGasMeter; -use std::{path::PathBuf, sync::Arc, thread}; +use std::{path::PathBuf, sync::Arc}; const WORKING_ACCOUNT: AccountAddress = AccountAddress::TWO; struct Adapter { store: InMemoryStorage, vm: Arc, - runtime_environment: RuntimeEnvironment, functions: Vec<(ModuleId, Identifier)>, } impl Adapter { - fn new(store: InMemoryStorage) -> Self { + fn new() -> Self { let functions = vec![ ( ModuleId::new(WORKING_ACCOUNT, Identifier::new("A").unwrap()), @@ -61,65 +58,22 @@ impl Adapter { ), ]; - let config = VMConfig { - verifier_config: VerifierConfig { - ..Default::default() - }, - ..Default::default() - }; - let runtime_environment = RuntimeEnvironment::new_with_config(vec![], config); + let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = Arc::new(MoveVM::new_with_runtime_environment(&runtime_environment)); + let store = InMemoryStorage::new(runtime_environment); Self { store, vm, - runtime_environment, functions, } } - fn fresh(self) -> Self { - let config = VMConfig { - verifier_config: VerifierConfig { - ..Default::default() - }, - ..Default::default() - }; - let runtime_environment = RuntimeEnvironment::new_with_config(vec![], config); - let vm = Arc::new(MoveVM::new_with_runtime_environment(&runtime_environment)); - - Self { - store: self.store, - vm, - runtime_environment, - functions: self.functions, - } + fn storage(&self) -> &InMemoryStorage { + &self.store } - fn publish_modules(&mut self, modules: Vec) { - let mut session = self.vm.new_session(&self.store); - - for module in modules { - let mut binary = vec![]; - module - .serialize(&mut binary) - .unwrap_or_else(|_| panic!("failure in module serialization: {:#?}", module)); - - #[allow(deprecated)] - session - .publish_module(binary, WORKING_ACCOUNT, &mut UnmeteredGasMeter) - .unwrap_or_else(|_| panic!("failure publishing module: {:#?}", module)); - } - - let changeset = session - .finish(&UnreachableCodeStorage) - .expect("failure getting write set"); - self.store - .apply(changeset) - .expect("failure applying write set"); - } - - fn publish_modules_using_loader_v2<'a, M: ModuleStorage>( + fn publish_modules<'a, M: ModuleStorage>( &'a self, module_storage: &'a M, modules: Vec, @@ -138,54 +92,40 @@ impl Adapter { .expect("failure publishing modules") } - fn publish_modules_with_error(&mut self, modules: Vec) { - let mut session = self.vm.new_session(&self.store); - - for module in modules { - let mut binary = vec![]; - module - .serialize(&mut binary) - .unwrap_or_else(|_| panic!("failure in module serialization: {:#?}", module)); - #[allow(deprecated)] - session - .publish_module(binary, WORKING_ACCOUNT, &mut UnmeteredGasMeter) - .expect_err("publishing must fail"); - } - } - fn call_functions(&self, module_storage: &impl ModuleStorage) { for (module_id, name) in &self.functions { self.call_function(module_id, name, module_storage); } } - fn call_functions_async(&self, reps: usize) { - thread::scope(|scope| { - for _ in 0..reps { - for (module_id, name) in self.functions.clone() { - let storage = self.store.clone(); - scope.spawn(move || { - // It is fine to share the VM: we do not publish modules anyway. - let mut session = self.vm.as_ref().new_session(&storage); - let traversal_storage = TraversalStorage::new(); - session - .execute_function_bypass_visibility( - &module_id, - &name, - vec![], - Vec::>::new(), - &mut UnmeteredGasMeter, - &mut TraversalContext::new(&traversal_storage), - &UnreachableCodeStorage, - ) - .unwrap_or_else(|e| { - panic!("Failure executing {}::{}: {:?}", module_id, name, e) - }); - }); - } - } - }); - } + // TODO(loader_v2): Re-implement concurrent loading tests. + // fn call_functions_async(&self, reps: usize) { + // thread::scope(|scope| { + // for _ in 0..reps { + // for (module_id, name) in self.functions.clone() { + // let storage = self.store.clone(); + // scope.spawn(move || { + // // It is fine to share the VM: we do not publish modules anyway. + // let mut session = self.vm.as_ref().new_session(&storage); + // let traversal_storage = TraversalStorage::new(); + // session + // .execute_function_bypass_visibility( + // &module_id, + // &name, + // vec![], + // Vec::>::new(), + // &mut UnmeteredGasMeter, + // &mut TraversalContext::new(&traversal_storage), + // &UnreachableCodeStorage, + // ) + // .unwrap_or_else(|e| { + // panic!("Failure executing {}::{}: {:?}", module_id, name, e) + // }); + // }); + // } + // } + // }); + // } fn call_function( &self, @@ -217,57 +157,48 @@ fn get_modules() -> Vec { #[test] fn load() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let modules = get_modules(); - - // calls all functions sequentially - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - adapter.call_functions(&module_storage); - } else { - adapter.publish_modules(modules); - adapter.call_functions(&UnreachableCodeStorage); - } -} + let adapter = Adapter::new(); + let module_storage = adapter.storage().as_unsync_module_storage(); -#[test] -fn load_concurrent() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); let modules = get_modules(); + let module_storage = adapter.publish_modules(&module_storage, modules); - // Makes 15 threads. Test loader V1 here only because we do not have Sync - // module storage implementation here. Also, even loader V1 tests are not - // really useful because VM cannot be shared across threads... - if !adapter.vm.vm_config().use_loader_v2 { - adapter.publish_modules(modules); - adapter.call_functions_async(3); - } + adapter.call_functions(&module_storage); } -#[test] -fn load_concurrent_many() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let modules = get_modules(); - - // Makes 150 threads. Test loader V1 here only because we do not have Sync - // module storage implementation here. Also, even loader V1 tests are not - // really useful because VM cannot be shared across threads... - if !adapter.vm.vm_config().use_loader_v2 { - adapter.publish_modules(modules); - adapter.call_functions_async(30); - } -} +// TODO(loader_v2): Re-activate tests below. +// #[test] +// fn load_concurrent() { +// let data_store = InMemoryStorage::new(); +// let mut adapter = Adapter::new(data_store); +// let modules = get_modules(); +// +// // Makes 15 threads. Test loader V1 here only because we do not have Sync +// // module storage implementation here. Also, even loader V1 tests are not +// // really useful because VM cannot be shared across threads... +// if !adapter.vm.vm_config().use_loader_v2 { +// adapter.publish_modules(modules); +// adapter.call_functions_async(3); +// } +// } + +// #[test] +// fn load_concurrent_many() { +// let data_store = InMemoryStorage::new(); +// let mut adapter = Adapter::new(data_store); +// let modules = get_modules(); +// +// // Makes 150 threads. Test loader V1 here only because we do not have Sync +// // module storage implementation here. Also, even loader V1 tests are not +// // really useful because VM cannot be shared across threads... +// if !adapter.vm.vm_config().use_loader_v2 { +// adapter.publish_modules(modules); +// adapter.call_functions_async(30); +// } +// } #[test] fn load_phantom_module() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let mut module = empty_module(); module.address_identifiers[0] = WORKING_ACCOUNT; module.identifiers[0] = Identifier::new("I").unwrap(); @@ -311,27 +242,18 @@ fn load_phantom_module() { let module_id = module.self_id(); modules.push(module); - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let new_module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - - let mut session = adapter.vm.new_session(&adapter.store); - let _ = session - .load_function(&new_module_storage, &module_id, ident_str!("foo"), &[]) - .unwrap(); - } else { - adapter.publish_modules(modules); - #[allow(deprecated)] - adapter.vm.load_module(&module_id, &adapter.store).unwrap(); - } + let adapter = Adapter::new(); + let module_storage = adapter.storage().as_unsync_module_storage(); + let new_module_storage = adapter.publish_modules(&module_storage, modules); + + let mut session = adapter.vm.new_session(adapter.storage()); + let _ = session + .load_function(&new_module_storage, &module_id, ident_str!("foo"), &[]) + .unwrap(); } #[test] fn load_with_extra_ability() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let mut module = empty_module(); module.address_identifiers[0] = WORKING_ACCOUNT; module.identifiers[0] = Identifier::new("I").unwrap(); @@ -378,257 +300,18 @@ fn load_with_extra_ability() { let module_id = module.self_id(); modules.push(module); - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let new_module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - - let mut session = adapter.vm.new_session(&adapter.store); - let _ = session - .load_function(&new_module_storage, &module_id, ident_str!("foo"), &[]) - .unwrap(); - } else { - adapter.publish_modules(modules); - #[allow(deprecated)] - adapter.vm.load_module(&module_id, &adapter.store).unwrap(); - } -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_list_err_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; + let adapter = Adapter::new(); + let module_storage = adapter.storage().as_unsync_module_storage(); + let new_module_storage = adapter.publish_modules(&module_storage, modules); - // create a chain of dependencies - let max = 350u64; - dependency_chain(1, max, &mut modules); - adapter.publish_modules(modules); - - let mut adapter = adapter.fresh(); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules_with_error(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_list_err_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a chain of dependencies - let max = 101u64; - dependency_chain(1, max, &mut modules); - adapter.publish_modules(modules); - - let mut adapter = adapter.fresh(); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules_with_error(vec![module]); -} - -#[test] -fn deep_dependency_list_ok_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a chain of dependencies - let max = 100u64; - dependency_chain(1, max, &mut modules); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - adapter.publish_modules_using_loader_v2(&module_storage, vec![module]); - } else { - adapter.publish_modules(modules); - let mut adapter = adapter.fresh(); - adapter.publish_modules(vec![module]); - } -} - -#[test] -fn deep_dependency_list_ok_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a chain of dependencies - let max = 30u64; - dependency_chain(1, max, &mut modules); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - adapter.publish_modules_using_loader_v2(&module_storage, vec![module]); - } else { - adapter.publish_modules(modules); - let mut adapter = adapter.fresh(); - adapter.publish_modules(vec![module]); - } -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_tree_err_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a tree of dependencies - let width = 5u64; - let height = 101u64; - dependency_tree(width, height, &mut modules); - adapter.publish_modules(modules); - - // use one of the module in the tree - let mut adapter = adapter.fresh(); - let name = "ASome".to_string(); - let dep_name = format!("A_{}_{}", height - 1, width - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules_with_error(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_tree_err_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a tree of dependencies - let width = 3u64; - let height = 350u64; - dependency_tree(width, height, &mut modules); - adapter.publish_modules(modules); - - // use one of the module in the tree - let mut adapter = adapter.fresh(); - let name = "ASome".to_string(); - let dep_name = format!("A_{}_{}", height - 1, width - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules_with_error(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_tree_ok_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a tree of dependencies - let width = 10u64; - let height = 20u64; - dependency_tree(width, height, &mut modules); - adapter.publish_modules(modules); - - // use one of the module in the tree - let mut adapter = adapter.fresh(); - let name = "ASome".to_string(); - let dep_name = format!("A_{}_{}", height - 1, width - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_dependency_tree_ok_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a tree of dependencies - let width = 3u64; - let height = 100u64; - dependency_tree(width, height, &mut modules); - adapter.publish_modules(modules); - - // use one of the module in the tree - let mut adapter = adapter.fresh(); - let name = "ASome".to_string(); - let dep_name = format!("A_{}_{}", height - 1, width - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - adapter.publish_modules(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_friend_list_err_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a chain of dependencies - let max = 1000u64; - friend_chain(1, max, &mut modules); - adapter.publish_modules(modules); - - let mut adapter = adapter.fresh(); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_friends(name, deps); - adapter.publish_modules_with_error(vec![module]); -} - -#[ignore = "temporarily disabled because we reimplemented dependency check outside the Move VM"] -#[test] -fn deep_friend_list_err_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - - let mut modules = vec![]; - - // create a chain of dependencies - let max = 101u64; - friend_chain(1, max, &mut modules); - adapter.publish_modules(modules); - - let mut adapter = adapter.fresh(); - let name = format!("A{}", max); - let dep_name = format!("A{}", max - 1); - let deps = vec![dep_name]; - let module = empty_module_with_friends(name, deps); - adapter.publish_modules_with_error(vec![module]); + let mut session = adapter.vm.new_session(&adapter.store); + let _ = session + .load_function(&new_module_storage, &module_id, ident_str!("foo"), &[]) + .unwrap(); } #[test] fn deep_friend_list_ok_0() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let mut modules = vec![]; // create a chain of friends @@ -639,23 +322,14 @@ fn deep_friend_list_ok_0() { let deps = vec![dep_name]; let module = empty_module_with_friends(name, deps); - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - adapter.publish_modules_using_loader_v2(&module_storage, vec![module]); - } else { - adapter.publish_modules(modules); - let mut adapter = adapter.fresh(); - adapter.publish_modules(vec![module]); - } + let adapter = Adapter::new(); + let module_storage = adapter.storage().as_unsync_module_storage(); + let module_storage = adapter.publish_modules(&module_storage, modules); + adapter.publish_modules(&module_storage, vec![module]); } #[test] fn deep_friend_list_ok_1() { - let data_store = InMemoryStorage::new(); - let mut adapter = Adapter::new(data_store); - let mut modules = vec![]; // create a chain of friends @@ -666,16 +340,10 @@ fn deep_friend_list_ok_1() { let deps = vec![dep_name]; let module = empty_module_with_friends(name, deps); - if adapter.vm.vm_config().use_loader_v2 { - let module_storage = - InMemoryStorage::new().into_unsync_module_storage(adapter.runtime_environment.clone()); - let module_storage = adapter.publish_modules_using_loader_v2(&module_storage, modules); - adapter.publish_modules_using_loader_v2(&module_storage, vec![module]); - } else { - adapter.publish_modules(modules); - let mut adapter = adapter.fresh(); - adapter.publish_modules(vec![module]); - } + let adapter = Adapter::new(); + let module_storage = adapter.storage().as_unsync_module_storage(); + let module_storage = adapter.publish_modules(&module_storage, modules); + adapter.publish_modules(&module_storage, vec![module]); } fn leaf_module(name: &str) -> CompiledModule { @@ -685,56 +353,6 @@ fn leaf_module(name: &str) -> CompiledModule { module } -// Create a list of dependent modules -fn dependency_chain(start: u64, end: u64, modules: &mut Vec) { - let module = leaf_module("A0"); - modules.push(module); - - for i in start..end { - let name = format!("A{}", i); - let dep_name = format!("A{}", i - 1); - let deps = vec![dep_name]; - let module = empty_module_with_dependencies(name, deps); - modules.push(module); - } -} - -// Create a tree (well a forest or DAG really) of dependent modules -fn dependency_tree(width: u64, height: u64, modules: &mut Vec) { - let mut deps = vec![]; - for i in 0..width { - let name = format!("A_{}_{}", 0, i); - let module = leaf_module(name.as_str()); - deps.push(name); - modules.push(module); - } - for i in 1..height { - let mut new_deps = vec![]; - for j in 0..width { - let name = format!("A_{}_{}", i, j); - let module = empty_module_with_dependencies(name.clone(), deps.clone()); - new_deps.push(name); - modules.push(module); - } - deps = new_deps; - } -} - -// Create a module that uses (depends on) the list of given modules -fn empty_module_with_dependencies(name: String, deps: Vec) -> CompiledModule { - let mut module = empty_module(); - module.address_identifiers[0] = WORKING_ACCOUNT; - module.identifiers[0] = Identifier::new(name).unwrap(); - for dep in deps { - module.identifiers.push(Identifier::new(dep).unwrap()); - module.module_handles.push(ModuleHandle { - address: AddressIdentifierIndex(0), - name: IdentifierIndex((module.identifiers.len() - 1) as TableIndex), - }); - } - module -} - // Create a list of friends modules fn friend_chain(start: u64, end: u64, modules: &mut Vec) { let module = leaf_module("A0"); diff --git a/third_party/move/move-vm/integration-tests/src/tests/mod.rs b/third_party/move/move-vm/integration-tests/src/tests/mod.rs index 23ca581ad7e71f..9074145a1cbe72 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/mod.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/mod.rs @@ -5,6 +5,7 @@ mod bad_entry_point_tests; mod bad_storage_tests; mod binary_format_version; +mod code_storage_tests; mod exec_func_effects_tests; mod function_arg_tests; mod instantiation_tests; diff --git a/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs index cad3fef8d8dfe9..4ac3628edacb3a 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/mutated_accounts_tests.rs @@ -40,11 +40,12 @@ fn mutated_accounts() { let mut blob = vec![]; m.serialize(&mut blob).unwrap(); - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); + let mut sess = vm.new_session(&storage); let publish = Identifier::new("publish").unwrap(); @@ -54,9 +55,7 @@ fn mutated_accounts() { let account1 = AccountAddress::random(); let traversal_storage = TraversalStorage::new(); - let module_storage = storage - .clone() - .into_unsync_module_storage(runtime_environment); + let module_storage = storage.clone().into_unsync_module_storage(); sess.execute_function_bypass_visibility( &m.self_id(), &publish, diff --git a/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs index 9235f8dc582520..e34604e57a6d14 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/native_tests.rs @@ -11,6 +11,7 @@ use move_core_types::{ use move_vm_runtime::{ config::VMConfig, module_traversal::*, move_vm::MoveVM, native_functions::NativeFunction, session::Session, AsUnsyncCodeStorage, ModuleStorage, RuntimeEnvironment, StagingModuleStorage, + WithRuntimeEnvironment, }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{gas::UnmeteredGasMeter, natives::function::NativeResult}; @@ -55,8 +56,6 @@ fn test_publish_module_with_nested_loops() { let traversal_storage = TraversalStorage::new(); { - let storage = InMemoryStorage::new(); - let natives = vec![( TEST_ADDR, Identifier::new("M").unwrap(), @@ -71,28 +70,23 @@ fn test_publish_module_with_nested_loops() { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_code_storage(runtime_environment); - if vm.vm_config().use_loader_v2 { - let new_module_storage = - StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob - .clone() - .into()]) + let storage = InMemoryStorage::new(runtime_environment); + let module_storage = storage.as_unsync_code_storage(); + + let new_module_storage = + StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob.clone().into()]) .expect("Module should be publishable"); - load_and_run_functions( - &mut sess, - &new_module_storage, - &traversal_storage, - &m.self_id(), - ); - } else { - #[allow(deprecated)] - sess.publish_module(m_blob.clone(), TEST_ADDR, &mut UnmeteredGasMeter) - .unwrap(); - load_and_run_functions(&mut sess, &module_storage, &traversal_storage, &m.self_id()); - }; + + let vm = MoveVM::new_with_runtime_environment(storage.runtime_environment()); + let mut sess = vm.new_session(&storage); + + load_and_run_functions( + &mut sess, + &new_module_storage, + &traversal_storage, + &m.self_id(), + ); } } diff --git a/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs index fe7a62619fb57b..a2895fecea5b07 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/nested_loop_tests.rs @@ -38,7 +38,6 @@ fn test_publish_module_with_nested_loops() { // Should succeed with max_loop_depth = 2 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -51,25 +50,16 @@ fn test_publish_module_with_nested_loops() { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let storage = InMemoryStorage::new(runtime_environment); - let mut sess = vm.new_session(&storage); - if vm.vm_config().use_loader_v2 { - let module_storage = storage.as_unsync_module_storage(runtime_environment); - let result = StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob - .clone() - .into()]); - assert!(result.is_ok()); - } else { - #[allow(deprecated)] - sess.publish_module(m_blob.clone(), TEST_ADDR, &mut UnmeteredGasMeter) - .unwrap(); - } + let module_storage = storage.as_unsync_module_storage(); + let result = + StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob.clone().into()]); + assert!(result.is_ok()); } // Should fail with max_loop_depth = 1 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -82,20 +72,12 @@ fn test_publish_module_with_nested_loops() { ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let storage = InMemoryStorage::new(runtime_environment); - let mut sess = vm.new_session(&storage); - if vm.vm_config().use_loader_v2 { - let module_storage = storage.as_unsync_module_storage(runtime_environment); - let result = StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob - .clone() - .into()]); - assert!(result.is_err()); - } else { - #[allow(deprecated)] - sess.publish_module(m_blob.clone(), TEST_ADDR, &mut UnmeteredGasMeter) - .unwrap_err(); - } + let module_storage = storage.as_unsync_module_storage(); + let result = + StagingModuleStorage::create(&TEST_ADDR, &module_storage, vec![m_blob.clone().into()]); + assert!(result.is_err()); } } @@ -125,7 +107,6 @@ fn test_run_script_with_nested_loops() { // Should succeed with max_loop_depth = 2 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -139,7 +120,9 @@ fn test_run_script_with_nested_loops() { }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + + let storage = InMemoryStorage::new(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let mut sess = vm.new_session(&storage); let args: Vec> = vec![]; @@ -156,7 +139,6 @@ fn test_run_script_with_nested_loops() { // Should fail with max_loop_depth = 1 { - let storage = InMemoryStorage::new(); let natives = move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), @@ -170,7 +152,9 @@ fn test_run_script_with_nested_loops() { }; let runtime_environment = RuntimeEnvironment::new_with_config(natives, vm_config); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + + let storage = InMemoryStorage::new(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let mut sess = vm.new_session(&storage); let args: Vec> = vec![]; diff --git a/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs index 6f99f81e35ffd7..fda580fa31b3e4 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/regression_tests.rs @@ -107,14 +107,15 @@ fn script_large_ty() { println!("Serialized len: {}", script.len()); CompiledModule::deserialize(&module).unwrap(); - let mut storage = InMemoryStorage::new(); let vm_config = VMConfig { verifier_config, paranoid_type_checks: true, ..Default::default() }; let runtime_environment = RuntimeEnvironment::new_with_config(vec![], vm_config); + let move_vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); let module_address = AccountAddress::from_hex_literal("0x42").unwrap(); let module_identifier = Identifier::new("pwn").unwrap(); @@ -137,7 +138,7 @@ fn script_large_ty() { ); let mut session = move_vm.new_session(&storage); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let traversal_storage = TraversalStorage::new(); let res = session .execute_script( diff --git a/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs index 214e9a8dced512..a47091e83c422e 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/return_value_tests.rs @@ -49,11 +49,11 @@ fn run( let mut blob = vec![]; m.serialize(&mut blob).unwrap(); - let mut storage = InMemoryStorage::new(); - storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); - let runtime_environment = RuntimeEnvironment::new(vec![]); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let mut storage = InMemoryStorage::new(runtime_environment); + storage.add_module_bytes(m.self_addr(), m.self_name(), blob.into()); + let mut sess = vm.new_session(&storage); let fun_name = Identifier::new("foo").unwrap(); @@ -63,7 +63,7 @@ fn run( .map(|val| val.simple_serialize().unwrap()) .collect(); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let traversal_storage = TraversalStorage::new(); let SerializedReturnValues { diff --git a/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs index 2aee07b1a5b169..25ea65b55017b6 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/runtime_reentrancy_check_tests.rs @@ -10,7 +10,7 @@ use move_core_types::{ }; use move_vm_runtime::{ module_traversal::*, move_vm::MoveVM, native_functions::NativeFunction, AsUnsyncModuleStorage, - RuntimeEnvironment, + RuntimeEnvironment, WithRuntimeEnvironment, }; use move_vm_test_utils::InMemoryStorage; use move_vm_types::{gas::UnmeteredGasMeter, natives::function::NativeResult}; @@ -73,7 +73,35 @@ fn compile_and_publish(storage: &mut InMemoryStorage, code: String) { #[test] fn runtime_reentrancy_check() { - let mut storage = InMemoryStorage::new(); + let natives = vec![ + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch").unwrap(), + make_dispatch_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch_c").unwrap(), + make_dispatch_c_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("dispatch_d").unwrap(), + make_dispatch_d_native(), + ), + ( + TEST_ADDR, + Identifier::new("B").unwrap(), + Identifier::new("load_c").unwrap(), + make_load_c(), + ), + ]; + + let runtime_environment = RuntimeEnvironment::new(natives); + let mut storage = InMemoryStorage::new(runtime_environment); let code_1 = format!( r#" @@ -87,7 +115,7 @@ fn runtime_reentrancy_check() { native fun dispatch_d(_f: u64); native fun load_c(); }} -"#, + "#, TEST_ADDR.to_hex(), ); @@ -113,7 +141,7 @@ fn runtime_reentrancy_check() { native fun dispatch_d(_f: u64); native fun load_c(); }} -"#, + "#, TEST_ADDR.to_hex(), ); @@ -124,47 +152,19 @@ fn runtime_reentrancy_check() { module 0x{0}::C {{ public fun foo() {{ return }} }} -"#, + "#, TEST_ADDR.to_hex(), ); compile_and_publish(&mut storage, code_3); - let natives = vec![ - ( - TEST_ADDR, - Identifier::new("B").unwrap(), - Identifier::new("dispatch").unwrap(), - make_dispatch_native(), - ), - ( - TEST_ADDR, - Identifier::new("B").unwrap(), - Identifier::new("dispatch_c").unwrap(), - make_dispatch_c_native(), - ), - ( - TEST_ADDR, - Identifier::new("B").unwrap(), - Identifier::new("dispatch_d").unwrap(), - make_dispatch_d_native(), - ), - ( - TEST_ADDR, - Identifier::new("B").unwrap(), - Identifier::new("load_c").unwrap(), - make_load_c(), - ), - ]; - let fun_name = Identifier::new("foo1").unwrap(); let args: Vec> = vec![]; let module_id = ModuleId::new(TEST_ADDR, Identifier::new("A").unwrap()); - let runtime_environment = RuntimeEnvironment::new(natives); - let vm = MoveVM::new_with_runtime_environment(&runtime_environment); + let vm = MoveVM::new_with_runtime_environment(storage.runtime_environment()); let mut sess = vm.new_session(&storage); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let traversal_storage = TraversalStorage::new(); // Call stack look like following: diff --git a/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs b/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs index 7d50db34f20119..b2b089b72ac3a2 100644 --- a/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs +++ b/third_party/move/move-vm/integration-tests/src/tests/vm_arguments_tests.rs @@ -256,8 +256,8 @@ fn call_script_with_args_ty_args_signers( ) -> VMResult<()> { let runtime_environment = RuntimeEnvironment::new(vec![]); let move_vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let storage = InMemoryStorage::new(); - let code_storage = storage.as_unsync_code_storage(runtime_environment); + let storage = InMemoryStorage::new(runtime_environment); + let code_storage = storage.as_unsync_code_storage(); let mut session = move_vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); @@ -287,14 +287,14 @@ fn call_function_with_args_ty_args_signers( ) -> VMResult<()> { let runtime_environment = RuntimeEnvironment::new(vec![]); let move_vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut storage = InMemoryStorage::new(); + let mut storage = InMemoryStorage::new(runtime_environment); let module_id = module.self_id(); let mut module_blob = vec![]; module.serialize(&mut module_blob).unwrap(); storage.add_module_bytes(module_id.address(), module_id.name(), module_blob.into()); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let mut session = move_vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); @@ -782,8 +782,8 @@ fn call_missing_item() { let runtime_environment = RuntimeEnvironment::new(vec![]); let move_vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let mut storage = InMemoryStorage::new(); - let module_storage = storage.as_unsync_module_storage(runtime_environment.clone()); + let mut storage = InMemoryStorage::new(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let mut session = move_vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); @@ -811,7 +811,7 @@ fn call_missing_item() { // missing function storage.add_module_bytes(module_id.address(), module_id.name(), module_blob.into()); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let mut session = move_vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); diff --git a/third_party/move/move-vm/runtime/src/lib.rs b/third_party/move/move-vm/runtime/src/lib.rs index 5229117b63b50c..c60428f35eac1c 100644 --- a/third_party/move/move-vm/runtime/src/lib.rs +++ b/third_party/move/move-vm/runtime/src/lib.rs @@ -33,8 +33,6 @@ mod access_control; mod storage; pub use loader::{LoadedFunction, Module, Script}; -#[cfg(any(test, feature = "testing"))] -pub use storage::implementations::unreachable_code_storage; pub use storage::{ code_storage::{ambassador_impl_CodeStorage, CodeStorage}, environment::{ diff --git a/third_party/move/move-vm/runtime/src/session.rs b/third_party/move/move-vm/runtime/src/session.rs index 1ba2d0c4bc0a2a..6144aa02b045c7 100644 --- a/third_party/move/move-vm/runtime/src/session.rs +++ b/third_party/move/move-vm/runtime/src/session.rs @@ -178,7 +178,7 @@ impl<'r, 'l> Session<'r, 'l> { ) } - /// Publish the given module. + /// Publish a series of modules. /// /// The Move VM MUST return a user error, i.e., an error that's not an invariant violation, if /// - The module fails to deserialize or verify. @@ -186,56 +186,16 @@ impl<'r, 'l> Session<'r, 'l> { /// - (Republishing-only) the module to be updated is not backward compatible with the old module. /// - (Republishing-only) the module to be updated introduces cyclic dependencies. /// - /// The Move VM should not be able to produce other user errors. - /// Besides, no user input should cause the Move VM to return an invariant violation. - /// - /// In case an invariant violation occurs, the whole Session should be considered corrupted and - /// one shall not proceed with effect generation. - #[deprecated] - pub fn publish_module( - &mut self, - module: Vec, - sender: AccountAddress, - gas_meter: &mut impl GasMeter, - ) -> VMResult<()> { - #[allow(deprecated)] - self.publish_module_bundle(vec![module], sender, gas_meter) - } - - /// Publish a series of modules. - /// - /// The Move VM MUST return a user error, i.e., an error that's not an invariant violation, if - /// any module fails to deserialize or verify (see the full list of failing conditions in the - /// `publish_module` API). The publishing of the module series is an all-or-nothing action: - /// either all modules are published to the data store or none is. + /// The publishing of the module series is an all-or-nothing action: either all modules are + /// published to the data store or none is. /// - /// Similar to the `publish_module` API, the Move VM should not be able to produce other user - /// errors. Besides, no user input should cause the Move VM to return an invariant violation. + /// The Move VM should not be able to produce other user errors. Besides, no user input should + /// cause the Move VM to return an invariant violation. /// /// In case an invariant violation occurs, the whole Session should be considered corrupted and /// one shall not proceed with effect generation. /// - /// This operation performs compatibility checks if a module is replaced. See also - /// `move_binary_format::compatibility`. - #[deprecated] - pub fn publish_module_bundle( - &mut self, - modules: Vec>, - sender: AccountAddress, - gas_meter: &mut impl GasMeter, - ) -> VMResult<()> { - #[allow(deprecated)] - self.move_vm.runtime.publish_module_bundle( - modules, - sender, - &mut self.data_cache, - &self.module_store, - gas_meter, - Compatibility::full_check(), - ) - } - - /// Same like `publish_module_bundle` but with a custom compatibility check. + /// This operation performs compatibility checks if a module is replaced. #[deprecated] pub fn publish_module_bundle_with_compat_config( &mut self, @@ -255,24 +215,6 @@ impl<'r, 'l> Session<'r, 'l> { ) } - #[deprecated] - pub fn publish_module_bundle_relax_compatibility( - &mut self, - modules: Vec>, - sender: AccountAddress, - gas_meter: &mut impl GasMeter, - ) -> VMResult<()> { - #[allow(deprecated)] - self.move_vm.runtime.publish_module_bundle( - modules, - sender, - &mut self.data_cache, - &self.module_store, - gas_meter, - Compatibility::no_check(), - ) - } - pub fn num_mutated_resources(&self, sender: &AccountAddress) -> u64 { self.data_cache.num_mutated_resources(sender) } diff --git a/third_party/move/move-vm/runtime/src/storage/code_storage.rs b/third_party/move/move-vm/runtime/src/storage/code_storage.rs index 5274a525431864..bfbf0269d5c765 100644 --- a/third_party/move/move-vm/runtime/src/storage/code_storage.rs +++ b/third_party/move/move-vm/runtime/src/storage/code_storage.rs @@ -1,7 +1,9 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::{loader::Script, logging::expect_no_verification_errors, ModuleStorage}; +use crate::{ + loader::Script, logging::expect_no_verification_errors, storage::module_storage::ModuleStorage, +}; use ambassador::delegatable_trait; use move_binary_format::{errors::VMResult, file_format::CompiledScript}; use move_vm_types::{ diff --git a/third_party/move/move-vm/runtime/src/storage/implementations/mod.rs b/third_party/move/move-vm/runtime/src/storage/implementations/mod.rs index baeb3dcdc767b8..5f67acf29e8e8e 100644 --- a/third_party/move/move-vm/runtime/src/storage/implementations/mod.rs +++ b/third_party/move/move-vm/runtime/src/storage/implementations/mod.rs @@ -1,7 +1,5 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -#[cfg(any(test, feature = "testing"))] -pub mod unreachable_code_storage; pub mod unsync_code_storage; pub mod unsync_module_storage; diff --git a/third_party/move/move-vm/runtime/src/storage/implementations/unreachable_code_storage.rs b/third_party/move/move-vm/runtime/src/storage/implementations/unreachable_code_storage.rs deleted file mode 100644 index b0d24f140bf279..00000000000000 --- a/third_party/move/move-vm/runtime/src/storage/implementations/unreachable_code_storage.rs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) The Move Contributors -// SPDX-License-Identifier: Apache-2.0 - -use crate::{ - CodeStorage, Module, ModuleStorage, RuntimeEnvironment, Script, WithRuntimeEnvironment, -}; -use bytes::Bytes; -use move_binary_format::{errors::VMResult, file_format::CompiledScript, CompiledModule}; -use move_core_types::{account_address::AccountAddress, identifier::IdentStr, metadata::Metadata}; -use std::sync::Arc; - -/// Implementation of code storage (for modules and scripts) traits, to be used in case VM uses -/// V1 loader implementation in tests. -pub struct UnreachableCodeStorage; - -impl WithRuntimeEnvironment for UnreachableCodeStorage { - fn runtime_environment(&self) -> &RuntimeEnvironment { - unreachable!() - } -} - -impl ModuleStorage for UnreachableCodeStorage { - fn check_module_exists( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult { - unreachable!() - } - - fn fetch_module_bytes( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult> { - unreachable!() - } - - fn fetch_module_size_in_bytes( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult> { - unreachable!() - } - - fn fetch_module_metadata( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult>> { - unreachable!() - } - - fn fetch_deserialized_module( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult>> { - unreachable!() - } - - fn fetch_verified_module( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult>> { - unreachable!() - } -} - -impl CodeStorage for UnreachableCodeStorage { - fn deserialize_and_cache_script( - &self, - _serialized_script: &[u8], - ) -> VMResult> { - unreachable!() - } - - fn verify_and_cache_script(&self, _serialized_script: &[u8]) -> VMResult> { - unreachable!() - } -} diff --git a/third_party/move/move-vm/runtime/src/storage/implementations/unsync_code_storage.rs b/third_party/move/move-vm/runtime/src/storage/implementations/unsync_code_storage.rs index 19f6f1ae55fee3..d6a5f2fd8bd048 100644 --- a/third_party/move/move-vm/runtime/src/storage/implementations/unsync_code_storage.rs +++ b/third_party/move/move-vm/runtime/src/storage/implementations/unsync_code_storage.rs @@ -21,7 +21,7 @@ use move_vm_types::code::{ }; use std::sync::Arc; -/// Code storage that stores both modules and scripts (not thread-safe). +/// Not thread-safe code storage that stores both modules and scripts. #[derive(Delegate)] #[delegate(WithRuntimeEnvironment, where = "M: ModuleStorage")] #[delegate(ModuleStorage, where = "M: ModuleStorage")] @@ -40,19 +40,21 @@ impl UnsyncCodeStorage { } /// Test-only method that checks the state of the script cache. - #[cfg(test)] - pub(crate) fn assert_cached_state<'b>( + #[cfg(any(test, feature = "testing"))] + pub fn assert_cached_state<'b>( &self, deserialized: Vec<&'b [u8; 32]>, verified: Vec<&'b [u8; 32]>, ) { + use claims::*; + assert_eq!(self.0.num_scripts(), deserialized.len() + verified.len()); for hash in deserialized { - let script = claims::assert_some!(self.0.get_script(hash)); + let script = assert_some!(self.0.get_script(hash)); assert!(!script.is_verified()) } for hash in verified { - let script = claims::assert_some!(self.0.get_script(hash)); + let script = assert_some!(self.0.get_script(hash)); assert!(script.is_verified()) } } @@ -67,7 +69,7 @@ impl UnsyncCodeStorage { )] #[delegate(ModuleStorage, target = "module_storage", where = "M: ModuleStorage")] #[delegate(ScriptCache, target = "script_cache", where = "M: ModuleStorage")] -pub struct UnsyncCodeStorageImpl { +struct UnsyncCodeStorageImpl { script_cache: UnsyncScriptCache<[u8; 32], CompiledScript, Script>, module_storage: M, } @@ -83,113 +85,20 @@ impl UnsyncCodeStorageImpl { } } -pub trait AsUnsyncCodeStorage<'s, S, E> { - fn as_unsync_code_storage( - &'s self, - runtime_environment: E, - ) -> UnsyncCodeStorage>; +pub trait AsUnsyncCodeStorage<'s, S> { + fn as_unsync_code_storage(&'s self) -> UnsyncCodeStorage>; - fn into_unsync_code_storage( - self, - runtime_environment: E, - ) -> UnsyncCodeStorage>; + fn into_unsync_code_storage(self) -> UnsyncCodeStorage>; } -impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> AsUnsyncCodeStorage<'s, S, E> for S { - fn as_unsync_code_storage( - &'s self, - runtime_environment: E, - ) -> UnsyncCodeStorage> { - UnsyncCodeStorage(UnsyncCodeStorageImpl::new( - self.as_unsync_module_storage(runtime_environment), - )) +impl<'s, S: ModuleBytesStorage + WithRuntimeEnvironment> AsUnsyncCodeStorage<'s, S> for S { + fn as_unsync_code_storage(&'s self) -> UnsyncCodeStorage> { + UnsyncCodeStorage(UnsyncCodeStorageImpl::new(self.as_unsync_module_storage())) } - fn into_unsync_code_storage( - self, - runtime_environment: E, - ) -> UnsyncCodeStorage> { + fn into_unsync_code_storage(self) -> UnsyncCodeStorage> { UnsyncCodeStorage(UnsyncCodeStorageImpl::new( - self.into_unsync_module_storage(runtime_environment), + self.into_unsync_module_storage(), )) } } - -#[cfg(test)] -mod test { - use super::*; - use crate::storage::{ - code_storage::CodeStorage, implementations::unsync_module_storage::test::add_module_bytes, - }; - use claims::assert_ok; - use move_binary_format::{ - file_format::empty_script_with_dependencies, file_format_common::VERSION_DEFAULT, - }; - use move_core_types::{identifier::Identifier, language_storage::ModuleId}; - use move_vm_test_utils::InMemoryStorage; - use move_vm_types::sha3_256; - - fn make_script<'a>(dependencies: impl IntoIterator) -> Vec { - let mut script = empty_script_with_dependencies(dependencies); - script.version = VERSION_DEFAULT; - - let mut serialized_script = vec![]; - assert_ok!(script.serialize(&mut serialized_script)); - serialized_script - } - - #[test] - fn test_deserialized_script_caching() { - let mut module_bytes_storage = InMemoryStorage::new(); - add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let code_storage = module_bytes_storage.into_unsync_code_storage(runtime_environment); - - let serialized_script = make_script(vec!["a"]); - let hash_1 = sha3_256(&serialized_script); - assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); - - let serialized_script = make_script(vec!["b"]); - let hash_2 = sha3_256(&serialized_script); - assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); - - code_storage.assert_cached_state(vec![&hash_1, &hash_2], vec![]); - } - - #[test] - fn test_verified_script_caching() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let code_storage = module_bytes_storage.into_unsync_code_storage(runtime_environment); - - let serialized_script = make_script(vec!["a"]); - let hash = sha3_256(&serialized_script); - assert_ok!(code_storage.deserialize_and_cache_script(&serialized_script)); - - // Nothing gets loaded into module cache. - code_storage - .module_storage() - .assert_cached_state(vec![], vec![]); - code_storage.assert_cached_state(vec![&hash], vec![]); - - assert_ok!(code_storage.verify_and_cache_script(&serialized_script)); - - // Script is verified, so its dependencies are loaded into cache. - code_storage - .module_storage() - .assert_cached_state(vec![], vec![&a_id, &b_id, &c_id]); - code_storage.assert_cached_state(vec![], vec![&hash]); - } -} diff --git a/third_party/move/move-vm/runtime/src/storage/implementations/unsync_module_storage.rs b/third_party/move/move-vm/runtime/src/storage/implementations/unsync_module_storage.rs index fba7581d9d3416..d5ff22ade9fd92 100644 --- a/third_party/move/move-vm/runtime/src/storage/implementations/unsync_module_storage.rs +++ b/third_party/move/move-vm/runtime/src/storage/implementations/unsync_module_storage.rs @@ -80,19 +80,12 @@ struct NoVersion; /// Private implementation of module storage based on non-[Sync] module cache and the baseline /// storage. #[derive(Delegate)] -#[delegate( - WithRuntimeEnvironment, - target = "runtime_environment", - where = "S: ModuleBytesStorage, E: WithRuntimeEnvironment" -)] #[delegate( ModuleCache, target = "module_cache", - where = "S: ModuleBytesStorage, E: WithRuntimeEnvironment" + where = "S: ModuleBytesStorage + WithRuntimeEnvironment" )] -struct UnsyncModuleStorageImpl<'s, S, E> { - /// Environment where this module storage is defined in. - runtime_environment: E, +struct UnsyncModuleStorageImpl<'s, S> { /// Module cache with deserialized or verified modules. module_cache: UnsyncModuleCache, @@ -100,11 +93,19 @@ struct UnsyncModuleStorageImpl<'s, S, E> { base_storage: BorrowedOrOwned<'s, S>, } -impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> UnsyncModuleStorageImpl<'s, S, E> { +impl<'s, S> WithRuntimeEnvironment for UnsyncModuleStorageImpl<'s, S> +where + S: ModuleBytesStorage + WithRuntimeEnvironment, +{ + fn runtime_environment(&self) -> &RuntimeEnvironment { + self.base_storage.runtime_environment() + } +} + +impl<'s, S: ModuleBytesStorage + WithRuntimeEnvironment> UnsyncModuleStorageImpl<'s, S> { /// Private constructor from borrowed byte storage. Creates empty module storage cache. - fn from_borrowed(runtime_environment: E, storage: &'s S) -> Self { + fn from_borrowed(storage: &'s S) -> Self { Self { - runtime_environment, module_cache: UnsyncModuleCache::empty(), base_storage: BorrowedOrOwned::Borrowed(storage), } @@ -112,17 +113,16 @@ impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> UnsyncModuleStorageIm /// Private constructor that captures provided byte storage by value. Creates empty module /// storage cache. - fn from_owned(runtime_environment: E, storage: S) -> Self { + fn from_owned(storage: S) -> Self { Self { - runtime_environment, module_cache: UnsyncModuleCache::empty(), base_storage: BorrowedOrOwned::Owned(storage), } } } -impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> ModuleCodeBuilder - for UnsyncModuleStorageImpl<'s, S, E> +impl<'s, S: ModuleBytesStorage + WithRuntimeEnvironment> ModuleCodeBuilder + for UnsyncModuleStorageImpl<'s, S> { type Deserialized = CompiledModule; type Extension = BytesWithHash; @@ -141,6 +141,7 @@ impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> ModuleCodeBuilder None => return Ok(None), }; let compiled_module = self + .base_storage .runtime_environment() .deserialize_into_compiled_module(&bytes)?; let hash = sha3_256(&bytes); @@ -154,15 +155,15 @@ impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> ModuleCodeBuilder #[derive(Delegate)] #[delegate( WithRuntimeEnvironment, - where = "S: ModuleBytesStorage, E: WithRuntimeEnvironment" + where = "S: ModuleBytesStorage + WithRuntimeEnvironment" )] #[delegate( ModuleStorage, - where = "S: ModuleBytesStorage, E: WithRuntimeEnvironment" + where = "S: ModuleBytesStorage + WithRuntimeEnvironment" )] -pub struct UnsyncModuleStorage<'s, S, E>(UnsyncModuleStorageImpl<'s, S, E>); +pub struct UnsyncModuleStorage<'s, S>(UnsyncModuleStorageImpl<'s, S>); -impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> UnsyncModuleStorage<'s, S, E> { +impl<'s, S: ModuleBytesStorage + WithRuntimeEnvironment> UnsyncModuleStorage<'s, S> { /// The reference to the baseline byte storage used by this module storage. pub fn byte_storage(&self) -> &S { &self.0.base_storage @@ -190,8 +191,8 @@ impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> UnsyncModuleStorage<' } /// Test-only method that checks the state of the module cache. - #[cfg(test)] - pub(crate) fn assert_cached_state<'b>( + #[cfg(any(test, feature = "testing"))] + pub fn assert_cached_state<'b>( &self, deserialized: Vec<&'b ModuleId>, verified: Vec<&'b ModuleId>, @@ -212,253 +213,18 @@ impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> UnsyncModuleStorage<' } } -pub trait AsUnsyncModuleStorage<'s, S, E> { - fn as_unsync_module_storage(&'s self, runtime_environment: E) -> UnsyncModuleStorage<'s, S, E>; - - fn into_unsync_module_storage(self, runtime_environment: E) -> UnsyncModuleStorage<'s, S, E>; -} - -impl<'s, S: ModuleBytesStorage, E: WithRuntimeEnvironment> AsUnsyncModuleStorage<'s, S, E> for S { - fn as_unsync_module_storage(&'s self, runtime_environment: E) -> UnsyncModuleStorage<'s, S, E> { - UnsyncModuleStorage(UnsyncModuleStorageImpl::from_borrowed( - runtime_environment, - self, - )) - } +pub trait AsUnsyncModuleStorage<'s, S> { + fn as_unsync_module_storage(&'s self) -> UnsyncModuleStorage<'s, S>; - fn into_unsync_module_storage(self, runtime_environment: E) -> UnsyncModuleStorage<'s, S, E> { - UnsyncModuleStorage(UnsyncModuleStorageImpl::from_owned( - runtime_environment, - self, - )) - } + fn into_unsync_module_storage(self) -> UnsyncModuleStorage<'s, S>; } -#[cfg(test)] -pub(crate) mod test { - use super::*; - use crate::storage::module_storage::ModuleStorage; - use claims::{assert_err, assert_none, assert_ok, assert_some}; - use move_binary_format::{ - file_format::empty_module_with_dependencies_and_friends, - file_format_common::VERSION_DEFAULT, - }; - use move_core_types::{ - account_address::AccountAddress, ident_str, identifier::Identifier, vm_status::StatusCode, - }; - use move_vm_test_utils::InMemoryStorage; - - fn make_module<'a>( - module_name: &'a str, - dependencies: impl IntoIterator, - friends: impl IntoIterator, - ) -> (CompiledModule, Bytes) { - let mut module = - empty_module_with_dependencies_and_friends(module_name, dependencies, friends); - module.version = VERSION_DEFAULT; - - let mut module_bytes = vec![]; - assert_ok!(module.serialize(&mut module_bytes)); - - (module, module_bytes.into()) - } - - pub(crate) fn add_module_bytes<'a>( - module_bytes_storage: &mut InMemoryStorage, - module_name: &'a str, - dependencies: impl IntoIterator, - friends: impl IntoIterator, - ) { - let (module, bytes) = make_module(module_name, dependencies, friends); - module_bytes_storage.add_module_bytes(module.self_addr(), module.self_name(), bytes); - } - - #[test] - fn test_module_does_not_exist() { - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = InMemoryStorage::new().into_unsync_module_storage(runtime_environment); - - let result = module_storage.check_module_exists(&AccountAddress::ZERO, ident_str!("a")); - assert!(!assert_ok!(result)); - - let result = - module_storage.fetch_module_size_in_bytes(&AccountAddress::ZERO, ident_str!("a")); - assert_none!(assert_ok!(result)); - - let result = module_storage.fetch_module_metadata(&AccountAddress::ZERO, ident_str!("a")); - assert_none!(assert_ok!(result)); - - let result = - module_storage.fetch_deserialized_module(&AccountAddress::ZERO, ident_str!("a")); - assert_none!(assert_ok!(result)); - - let result = module_storage.fetch_verified_module(&AccountAddress::ZERO, ident_str!("a")); - assert_none!(assert_ok!(result)); - } - - #[test] - fn test_module_exists() { - let mut module_bytes_storage = InMemoryStorage::new(); - add_module_bytes(&mut module_bytes_storage, "a", vec![], vec![]); - let id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - assert!(assert_ok!( - module_storage.check_module_exists(id.address(), id.name()) - )); - module_storage.assert_cached_state(vec![&id], vec![]); - } - - #[test] - fn test_deserialized_caching() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec!["d", "e"], vec![]); - add_module_bytes(&mut module_bytes_storage, "d", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "e", vec![], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - let result = module_storage.fetch_module_metadata(a_id.address(), a_id.name()); - let expected = make_module("a", vec!["b", "c"], vec![]).0.metadata; - assert_eq!(assert_some!(assert_ok!(result)), expected); - module_storage.assert_cached_state(vec![&a_id], vec![]); - - let result = module_storage.fetch_deserialized_module(c_id.address(), c_id.name()); - let expected = make_module("c", vec!["d", "e"], vec![]).0; - assert_eq!(assert_some!(assert_ok!(result)).as_ref(), &expected); - module_storage.assert_cached_state(vec![&a_id, &c_id], vec![]); - } - - #[test] - fn test_dependency_tree_traversal() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - let d_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("d").unwrap()); - let e_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("e").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec!["d", "e"], vec![]); - add_module_bytes(&mut module_bytes_storage, "d", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "e", vec![], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - assert_ok!(module_storage.fetch_verified_module(c_id.address(), c_id.name())); - module_storage.assert_cached_state(vec![], vec![&c_id, &d_id, &e_id]); - - assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); - module_storage.assert_cached_state(vec![], vec![&a_id, &b_id, &c_id, &d_id, &e_id]); - - assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); - } - - #[test] - fn test_dependency_dag_traversal() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - let d_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("d").unwrap()); - let e_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("e").unwrap()); - let f_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("f").unwrap()); - let g_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("g").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b", "c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec!["d"], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec!["d"], vec![]); - add_module_bytes(&mut module_bytes_storage, "d", vec!["e", "f"], vec![]); - add_module_bytes(&mut module_bytes_storage, "e", vec!["g"], vec![]); - add_module_bytes(&mut module_bytes_storage, "f", vec!["g"], vec![]); - add_module_bytes(&mut module_bytes_storage, "g", vec![], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - assert_ok!(module_storage.fetch_deserialized_module(a_id.address(), a_id.name())); - assert_ok!(module_storage.fetch_deserialized_module(c_id.address(), c_id.name())); - module_storage.assert_cached_state(vec![&a_id, &c_id], vec![]); - - assert_ok!(module_storage.fetch_verified_module(d_id.address(), d_id.name())); - module_storage.assert_cached_state(vec![&a_id, &c_id], vec![&d_id, &e_id, &f_id, &g_id]); - - assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); - module_storage.assert_cached_state(vec![], vec![ - &a_id, &b_id, &c_id, &d_id, &e_id, &f_id, &g_id, - ]); +impl<'s, S: ModuleBytesStorage + WithRuntimeEnvironment> AsUnsyncModuleStorage<'s, S> for S { + fn as_unsync_module_storage(&'s self) -> UnsyncModuleStorage<'s, S> { + UnsyncModuleStorage(UnsyncModuleStorageImpl::from_borrowed(self)) } - #[test] - fn test_cyclic_dependencies_traversal_fails() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b"], vec![]); - add_module_bytes(&mut module_bytes_storage, "b", vec!["c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec!["a"], vec![]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - let result = module_storage.fetch_verified_module(c_id.address(), c_id.name()); - assert_eq!( - assert_err!(result).major_status(), - StatusCode::CYCLIC_MODULE_DEPENDENCY - ); - } - - #[test] - fn test_cyclic_friends_are_allowed() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec![], vec!["b"]); - add_module_bytes(&mut module_bytes_storage, "b", vec![], vec!["c"]); - add_module_bytes(&mut module_bytes_storage, "c", vec![], vec!["a"]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - let result = module_storage.fetch_verified_module(c_id.address(), c_id.name()); - assert_ok!(result); - - // Since `c` has no dependencies, only it gets deserialized and verified. - module_storage.assert_cached_state(vec![], vec![&c_id]); - } - - #[test] - fn test_transitive_friends_are_allowed_to_be_transitive_dependencies() { - let mut module_bytes_storage = InMemoryStorage::new(); - - let a_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("a").unwrap()); - let b_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("b").unwrap()); - let c_id = ModuleId::new(AccountAddress::ZERO, Identifier::new("c").unwrap()); - - add_module_bytes(&mut module_bytes_storage, "a", vec!["b"], vec!["d"]); - add_module_bytes(&mut module_bytes_storage, "b", vec!["c"], vec![]); - add_module_bytes(&mut module_bytes_storage, "c", vec![], vec![]); - add_module_bytes(&mut module_bytes_storage, "d", vec![], vec!["c"]); - - let runtime_environment = RuntimeEnvironment::new(vec![]); - let module_storage = module_bytes_storage.into_unsync_module_storage(runtime_environment); - - assert_ok!(module_storage.fetch_verified_module(a_id.address(), a_id.name())); - module_storage.assert_cached_state(vec![], vec![&a_id, &b_id, &c_id]); + fn into_unsync_module_storage(self) -> UnsyncModuleStorage<'s, S> { + UnsyncModuleStorage(UnsyncModuleStorageImpl::from_owned(self)) } } diff --git a/third_party/move/move-vm/runtime/src/storage/loader.rs b/third_party/move/move-vm/runtime/src/storage/loader.rs index 3c484c7f74549f..bf93d937b772a8 100644 --- a/third_party/move/move-vm/runtime/src/storage/loader.rs +++ b/third_party/move/move-vm/runtime/src/storage/loader.rs @@ -6,8 +6,8 @@ use crate::{ loader::{Function, LoadedFunctionOwner, Module}, logging::expect_no_verification_errors, module_traversal::TraversalContext, - storage::module_storage::ModuleStorage, - CodeStorage, LoadedFunction, + storage::{code_storage::CodeStorage, module_storage::ModuleStorage}, + LoadedFunction, }; use move_binary_format::{ access::{ModuleAccess, ScriptAccess}, diff --git a/third_party/move/move-vm/runtime/src/storage/module_storage.rs b/third_party/move/move-vm/runtime/src/storage/module_storage.rs index 714871a70cc779..fb2c37a3250fab 100644 --- a/third_party/move/move-vm/runtime/src/storage/module_storage.rs +++ b/third_party/move/move-vm/runtime/src/storage/module_storage.rs @@ -1,7 +1,7 @@ // Copyright (c) The Move Contributors // SPDX-License-Identifier: Apache-2.0 -use crate::{loader::Module, WithRuntimeEnvironment}; +use crate::{loader::Module, storage::environment::WithRuntimeEnvironment}; use ambassador::delegatable_trait; use bytes::Bytes; use hashbrown::HashSet; diff --git a/third_party/move/move-vm/runtime/src/storage/publishing.rs b/third_party/move/move-vm/runtime/src/storage/publishing.rs index d6d3320e9c54ae..72cbdd2357a963 100644 --- a/third_party/move/move-vm/runtime/src/storage/publishing.rs +++ b/third_party/move/move-vm/runtime/src/storage/publishing.rs @@ -2,8 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 use crate::{ - ambassador_impl_ModuleStorage, ambassador_impl_WithRuntimeEnvironment, AsUnsyncModuleStorage, - Module, ModuleStorage, RuntimeEnvironment, UnsyncModuleStorage, WithRuntimeEnvironment, + storage::{ + environment::{ + ambassador_impl_WithRuntimeEnvironment, RuntimeEnvironment, WithRuntimeEnvironment, + }, + implementations::unsync_module_storage::{AsUnsyncModuleStorage, UnsyncModuleStorage}, + module_storage::{ambassador_impl_ModuleStorage, ModuleStorage}, + }, + Module, }; use ambassador::Delegate; use bytes::Bytes; @@ -43,12 +49,21 @@ impl IntoIterator for VerifiedModuleBundle { /// An implementation of [ModuleBytesStorage] that stores some additional staged changes. If used /// by [ModuleStorage], the most recent version of a module will be fetched. struct StagingModuleBytesStorage<'a, M> { + // Runtime environment that shadows the runtime environment of the ground-truth module storage. + staged_runtime_environment: RuntimeEnvironment, // Modules to be published, staged temporarily. staged_module_bytes: BTreeMap>, + // Underlying ground-truth module storage, used as a raw byte storage. module_storage: &'a M, } +impl<'a, M: ModuleStorage> WithRuntimeEnvironment for StagingModuleBytesStorage<'a, M> { + fn runtime_environment(&self) -> &RuntimeEnvironment { + &self.staged_runtime_environment + } +} + impl<'a, M: ModuleStorage> ModuleBytesStorage for StagingModuleBytesStorage<'a, M> { fn fetch_module_bytes( &self, @@ -75,7 +90,7 @@ impl<'a, M: ModuleStorage> ModuleBytesStorage for StagingModuleBytesStorage<'a, #[delegate(WithRuntimeEnvironment, where = "M: ModuleStorage")] #[delegate(ModuleStorage, where = "M: ModuleStorage")] pub struct StagingModuleStorage<'a, M> { - storage: UnsyncModuleStorage<'a, StagingModuleBytesStorage<'a, M>, RuntimeEnvironment>, + storage: UnsyncModuleStorage<'a, StagingModuleBytesStorage<'a, M>>, } impl<'a, M: ModuleStorage> StagingModuleStorage<'a, M> { @@ -110,8 +125,8 @@ impl<'a, M: ModuleStorage> StagingModuleStorage<'a, M> { // TODO(loader_v2): // Avoid clone and instead stage runtime environment so that higher order indices are // resolved through some temporary data structure. - let runtime_environment = existing_module_storage.runtime_environment().clone(); - let deserializer_config = &runtime_environment.vm_config().deserializer_config; + let staged_runtime_environment = existing_module_storage.runtime_environment().clone(); + let deserializer_config = &staged_runtime_environment.vm_config().deserializer_config; // For every module in bundle, run compatibility checks and construct a new bytes storage // view such that added modules shadow any existing ones. @@ -153,7 +168,10 @@ impl<'a, M: ModuleStorage> StagingModuleStorage<'a, M> { existing_module_storage.fetch_deserialized_module(addr, name)? { let old_module = old_module_ref.as_ref(); - if runtime_environment.vm_config().use_compatibility_checker_v2 { + if staged_runtime_environment + .vm_config() + .use_compatibility_checker_v2 + { compatibility .check(old_module, &compiled_module) .map_err(|e| e.finish(Location::Undefined))?; @@ -197,12 +215,13 @@ impl<'a, M: ModuleStorage> StagingModuleStorage<'a, M> { // At this point, we have successfully created a new module storage that also contains the // newly published bundle. let staged_module_bytes_storage = StagingModuleBytesStorage { + staged_runtime_environment, staged_module_bytes, module_storage: existing_module_storage, }; let staged_module_storage = StagingModuleStorage { - storage: staged_module_bytes_storage.into_unsync_module_storage(runtime_environment), + storage: staged_module_bytes_storage.into_unsync_module_storage(), }; // Finally, verify the bundle, performing linking checks for all staged modules. diff --git a/third_party/move/move-vm/test-utils/Cargo.toml b/third_party/move/move-vm/test-utils/Cargo.toml index 1d075c08cca171..055c3f9e2fa152 100644 --- a/third_party/move/move-vm/test-utils/Cargo.toml +++ b/third_party/move/move-vm/test-utils/Cargo.toml @@ -20,6 +20,7 @@ move-binary-format = { path = "../../move-binary-format" } move-bytecode-utils = { path = "../../tools/move-bytecode-utils" } move-core-types = { path = "../../move-core/types" } move-table-extension = { path = "../../extensions/move-table-extension", optional = true } +move-vm-runtime = { path = "../runtime" } move-vm-types = { path = "../types" } [features] diff --git a/third_party/move/move-vm/test-utils/src/storage.rs b/third_party/move/move-vm/test-utils/src/storage.rs index d49f2bd9105460..94a06eba129581 100644 --- a/third_party/move/move-vm/test-utils/src/storage.rs +++ b/third_party/move/move-vm/test-utils/src/storage.rs @@ -4,9 +4,7 @@ use bytes::Bytes; use move_binary_format::{ - deserializer::DeserializerConfig, errors::{PartialVMError, PartialVMResult, VMResult}, - file_format_common::{IDENTIFIER_SIZE_MAX, VERSION_MAX}, CompiledModule, }; use move_bytecode_utils::compiled_module_viewer::CompiledModuleView; @@ -21,6 +19,7 @@ use move_core_types::{ }; #[cfg(feature = "table-extension")] use move_table_extension::{TableChangeSet, TableHandle, TableResolver}; +use move_vm_runtime::{RuntimeEnvironment, WithRuntimeEnvironment}; use move_vm_types::{ code::ModuleBytesStorage, resolver::{resource_size, ModuleResolver, ResourceResolver}, @@ -40,16 +39,6 @@ impl BlankStorage { } } -impl ModuleBytesStorage for BlankStorage { - fn fetch_module_bytes( - &self, - _address: &AccountAddress, - _module_name: &IdentStr, - ) -> VMResult> { - Ok(None) - } -} - impl ModuleResolver for BlankStorage { fn get_module_metadata(&self, _module_id: &ModuleId) -> Vec { vec![] @@ -92,8 +81,11 @@ struct InMemoryAccountStorage { } /// Simple in-memory storage that can be used as a Move VM storage backend for testing purposes. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct InMemoryStorage { + /// The environment used by this storage. + runtime_environment: RuntimeEnvironment, + accounts: BTreeMap, #[cfg(feature = "table-extension")] tables: BTreeMap, Bytes>>, @@ -104,10 +96,10 @@ impl CompiledModuleView for InMemoryStorage { fn view_compiled_module(&self, id: &ModuleId) -> anyhow::Result> { Ok(match self.get_module(id)? { - Some(bytes) => { - let config = DeserializerConfig::new(VERSION_MAX, IDENTIFIER_SIZE_MAX); - Some(CompiledModule::deserialize_with_config(&bytes, &config)?) - }, + Some(bytes) => Some( + self.runtime_environment + .deserialize_into_compiled_module(&bytes)?, + ), None => None, }) } @@ -238,8 +230,9 @@ impl InMemoryStorage { Ok(()) } - pub fn new() -> Self { + pub fn new(runtime_environment: RuntimeEnvironment) -> Self { Self { + runtime_environment, accounts: BTreeMap::new(), #[cfg(feature = "table-extension")] tables: BTreeMap::new(), @@ -283,6 +276,12 @@ impl ModuleBytesStorage for InMemoryStorage { } } +impl WithRuntimeEnvironment for InMemoryStorage { + fn runtime_environment(&self) -> &RuntimeEnvironment { + &self.runtime_environment + } +} + impl ModuleResolver for InMemoryStorage { fn get_module_metadata(&self, _module_id: &ModuleId) -> Vec { vec![] diff --git a/third_party/move/testing-infra/test-generation/src/lib.rs b/third_party/move/testing-infra/test-generation/src/lib.rs index b077021b4a197f..46bdab6c6609fd 100644 --- a/third_party/move/testing-infra/test-generation/src/lib.rs +++ b/third_party/move/testing-infra/test-generation/src/lib.rs @@ -57,8 +57,11 @@ fn run_verifier(module: CompiledModule) -> Result { } // Creates a storage with Move standard library as well as a few additional modules. -fn storage_with_stdlib_and_modules(additional_modules: Vec<&CompiledModule>) -> InMemoryStorage { - let mut storage = InMemoryStorage::new(); +fn storage_with_stdlib_and_modules( + additional_modules: Vec<&CompiledModule>, + runtime_environment: RuntimeEnvironment, +) -> InMemoryStorage { + let mut storage = InMemoryStorage::new(runtime_environment); // First, compile and add standard library. let (_, compiled_units) = Compiler::from_files( @@ -150,8 +153,8 @@ fn execute_function_in_module( let runtime_environment = RuntimeEnvironment::new(natives); let vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let storage = storage_with_stdlib_and_modules(vec![&module]); - let module_storage = storage.as_unsync_module_storage(runtime_environment); + let storage = storage_with_stdlib_and_modules(vec![&module], runtime_environment); + let module_storage = storage.as_unsync_module_storage(); let mut sess = vm.new_session(&storage); let traversal_storage = TraversalStorage::new(); diff --git a/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs b/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs index da5e6faa106ab7..f85ed9c1d7d443 100644 --- a/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs +++ b/third_party/move/testing-infra/transactional-test-runner/src/vm_test_harness.rs @@ -43,7 +43,7 @@ use move_vm_runtime::{ move_vm::MoveVM, session::{SerializedReturnValues, Session}, AsUnsyncCodeStorage, AsUnsyncModuleStorage, ModuleStorage, RuntimeEnvironment, - StagingModuleStorage, WithRuntimeEnvironment, + StagingModuleStorage, }; use move_vm_test_utils::{ gas_schedule::{CostTable, Gas, GasStatus}, @@ -60,31 +60,11 @@ use std::{ const STD_ADDR: AccountAddress = AccountAddress::ONE; -struct RuntimeEnvironmentAdapter(Rc); - -impl RuntimeEnvironmentAdapter { - fn new(runtime_environment: RuntimeEnvironment) -> Self { - Self(Rc::new(runtime_environment)) - } -} - -impl Clone for RuntimeEnvironmentAdapter { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} - -impl WithRuntimeEnvironment for RuntimeEnvironmentAdapter { - fn runtime_environment(&self) -> &RuntimeEnvironment { - self.0.runtime_environment() - } -} - struct SimpleVMTestAdapter<'a> { compiled_state: CompiledState<'a>, - // VM and runtime environment to be shared by all tasks. If we use V1 loader, we store None here. - vm_and_runtime_environment: (Option>, RuntimeEnvironmentAdapter), + /// VM shared by all tasks. + vm: Rc, storage: InMemoryStorage, default_syntax: SyntaxChoice, @@ -169,15 +149,8 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { } let vm_config = vm_config(); - let use_loader_v2 = vm_config.use_loader_v2; - - let runtime_environment = - RuntimeEnvironmentAdapter::new(create_runtime_environment(vm_config)); - let vm = use_loader_v2.then(|| { - let vm = MoveVM::new_with_runtime_environment(&runtime_environment.0); - Rc::new(vm) - }); - let vm_and_runtime_environment = (vm, runtime_environment); + let runtime_environment = create_runtime_environment(vm_config); + let vm = Rc::new(MoveVM::new_with_runtime_environment(&runtime_environment)); let mut adapter = Self { compiled_state: CompiledState::new( @@ -189,73 +162,39 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { default_syntax, comparison_mode, run_config, - vm_and_runtime_environment, - storage: InMemoryStorage::new(), + vm, + storage: InMemoryStorage::new(runtime_environment), }; - let (_, runtime_environment) = adapter.vm_and_runtime_environment(); - let module_storage = adapter - .storage - .clone() - .into_unsync_module_storage(runtime_environment.clone()); - - if runtime_environment.0.vm_config().use_loader_v2 { - let addresses = either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) - .iter() - .map(|tmod| *tmod.named_module.module.self_addr()) - .collect::>(); - assert_eq!(addresses.len(), 1); - - let sender = *addresses.first().unwrap(); - let module_bundle = either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) - .into_iter() - .map(|tmod| { - let mut module_bytes = vec![]; - tmod.named_module - .module - .serialize_for_version( - Some(file_format_common::VERSION_MAX), - &mut module_bytes, - ) - .unwrap(); - module_bytes.into() - }) - .collect(); + let addresses = either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) + .iter() + .map(|tmod| *tmod.named_module.module.self_addr()) + .collect::>(); + assert_eq!(addresses.len(), 1); - StagingModuleStorage::create(&sender, &module_storage, module_bundle) - .expect("All modules should publish") - .release_verified_module_bundle() - .into_iter() - .for_each(|(module_id, bytes)| { - adapter - .storage - .add_module_bytes(module_id.address(), module_id.name(), bytes); - }); - } else { - adapter - .perform_session_action(None, &module_storage, |session, gas_status| { - for module in either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) - .into_iter() - .map(|tmod| &tmod.named_module.module) - { - let mut module_bytes = vec![]; - module - .serialize_for_version( - Some(file_format_common::VERSION_MAX), - &mut module_bytes, - ) - .unwrap(); - let id = module.self_id(); - let sender = *id.address(); - #[allow(deprecated)] - session - .publish_module(module_bytes, sender, gas_status) - .unwrap(); - } - Ok(()) - }) - .unwrap(); - } + let sender = *addresses.first().unwrap(); + let module_bundle = either_or_no_modules(pre_compiled_deps_v1, pre_compiled_deps_v2) + .into_iter() + .map(|tmod| { + let mut module_bytes = vec![]; + tmod.named_module + .module + .serialize_for_version(Some(file_format_common::VERSION_MAX), &mut module_bytes) + .unwrap(); + module_bytes.into() + }) + .collect(); + + let module_storage = adapter.storage.clone().into_unsync_module_storage(); + StagingModuleStorage::create(&sender, &module_storage, module_bundle) + .expect("All modules should publish") + .release_verified_module_bundle() + .into_iter() + .for_each(|(module_id, bytes)| { + adapter + .storage + .add_module_bytes(module_id.address(), module_id.name(), bytes); + }); let mut addr_to_name_mapping = BTreeMap::new(); for (name, addr) in move_stdlib_named_addresses() { @@ -280,14 +219,10 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { &mut self, module: CompiledModule, _named_addr_opt: Option, - gas_budget: Option, + _gas_budget: Option, extra_args: Self::ExtraPublishArgs, ) -> Result<(Option, CompiledModule)> { - let (vm, runtime_environment) = self.vm_and_runtime_environment(); - let module_storage = self - .storage - .clone() - .into_unsync_module_storage(runtime_environment.clone()); + let module_storage = self.storage.clone().into_unsync_module_storage(); let mut module_bytes = vec![]; module.serialize_for_version(Some(file_format_common::VERSION_MAX), &mut module_bytes)?; @@ -304,54 +239,30 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { !extra_args.skip_check_friend_linking, ) }; - if vm.vm_config().use_loader_v2 { - let staging_module_storage = StagingModuleStorage::create_with_compat_config( - &sender, - compat, - &module_storage, - vec![module_bytes.into()], - ) - .map_err(|err| { - anyhow!( - "Unable to publish module '{}'. Got VMError: {}", - module.self_id(), - err.format_test_output( - move_test_debug() || verbose, - !move_test_debug() && self.comparison_mode - ) + let staging_module_storage = StagingModuleStorage::create_with_compat_config( + &sender, + compat, + &module_storage, + vec![module_bytes.into()], + ) + .map_err(|err| { + anyhow!( + "Unable to publish module '{}'. Got VMError: {}", + module.self_id(), + err.format_test_output( + move_test_debug() || verbose, + !move_test_debug() && self.comparison_mode ) - })?; - for (module_id, bytes) in staging_module_storage - .release_verified_module_bundle() - .into_iter() - { - self.storage - .add_module_bytes(module_id.address(), module.name(), bytes); - } - Ok((None, module)) - } else { - let result = - self.perform_session_action(gas_budget, &module_storage, |session, gas_status| { - #[allow(deprecated)] - session.publish_module_bundle_with_compat_config( - vec![module_bytes], - sender, - gas_status, - compat, - ) - }); - match result { - Ok(_) => Ok((None, module)), - Err(err) => Err(anyhow!( - "Unable to publish module '{}'. Got VMError: {}", - module.self_id(), - err.format_test_output( - move_test_debug() || verbose, - !move_test_debug() && self.comparison_mode - ) - )), - } + ) + })?; + for (module_id, bytes) in staging_module_storage + .release_verified_module_bundle() + .into_iter() + { + self.storage + .add_module_bytes(module_id.address(), module.name(), bytes); } + Ok((None, module)) } fn execute_script( @@ -363,11 +274,7 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { gas_budget: Option, extra_args: Self::ExtraRunArgs, ) -> Result> { - let (_, runtime_environment) = self.vm_and_runtime_environment(); - let code_storage = self - .storage - .clone() - .into_unsync_code_storage(runtime_environment.clone()); + let code_storage = self.storage.clone().into_unsync_code_storage(); let signers: Vec<_> = signers .into_iter() @@ -421,11 +328,7 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { gas_budget: Option, extra_args: Self::ExtraRunArgs, ) -> Result<(Option, SerializedReturnValues)> { - let (_, runtime_environment) = self.vm_and_runtime_environment(); - let module_storage = self - .storage - .clone() - .into_unsync_module_storage(runtime_environment.clone()); + let module_storage = self.storage.clone().into_unsync_module_storage(); let signers: Vec<_> = signers .into_iter() @@ -502,32 +405,19 @@ impl<'a> MoveTestAdapter<'a> for SimpleVMTestAdapter<'a> { } impl<'a> SimpleVMTestAdapter<'a> { - fn vm_and_runtime_environment(&self) -> (Rc, RuntimeEnvironmentAdapter) { - let vm = match &self.vm_and_runtime_environment.0 { - Some(vm) => vm.clone(), - None => { - let vm = - MoveVM::new_with_runtime_environment(&self.vm_and_runtime_environment.1 .0); - Rc::new(vm) - }, - }; - (vm, self.vm_and_runtime_environment.1.clone()) - } - fn perform_session_action( &mut self, gas_budget: Option, module_storage: &impl ModuleStorage, f: impl FnOnce(&mut Session, &mut GasStatus) -> VMResult, ) -> VMResult { - let (vm, _) = self.vm_and_runtime_environment(); let (mut session, mut gas_status) = { let gas_status = get_gas_status( &move_vm_test_utils::gas_schedule::INITIAL_COST_SCHEDULE, gas_budget, ) .unwrap(); - let session = vm.new_session(&self.storage); + let session = self.vm.new_session(&self.storage); (session, gas_status) }; diff --git a/third_party/move/tools/move-unit-test/src/test_runner.rs b/third_party/move/tools/move-unit-test/src/test_runner.rs index 6c5e839411fc62..26818353dba7c8 100644 --- a/third_party/move/tools/move-unit-test/src/test_runner.rs +++ b/third_party/move/tools/move-unit-test/src/test_runner.rs @@ -27,7 +27,7 @@ use move_vm_runtime::{ move_vm::MoveVM, native_extensions::NativeContextExtensions, native_functions::NativeFunctionTable, - AsUnsyncModuleStorage, RuntimeEnvironment, + AsUnsyncModuleStorage, RuntimeEnvironment, WithRuntimeEnvironment, }; use move_vm_test_utils::InMemoryStorage; use rayon::prelude::*; @@ -46,7 +46,6 @@ use { pub struct SharedTestingConfig { save_storage_state_on_failure: bool, report_stacktrace_on_abort: bool, - native_function_table: NativeFunctionTable, starting_storage_state: InMemoryStorage, #[allow(dead_code)] // used by some features source_files: Vec, @@ -65,8 +64,9 @@ pub struct TestRunner { /// Setup storage state with the set of modules that will be needed for all tests fn setup_test_storage<'a>( modules: impl Iterator, + runtime_environment: RuntimeEnvironment, ) -> Result { - let mut storage = InMemoryStorage::new(); + let mut storage = InMemoryStorage::new(runtime_environment); let modules = Modules::new(modules); for module in modules .compute_dependency_graph() @@ -127,23 +127,26 @@ impl TestRunner { .values() .map(|(filepath, _)| filepath.to_string()) .collect(); - let modules = tests.module_info.values().map(|info| &info.module); - let mut starting_storage_state = setup_test_storage(modules)?; - if let Some(genesis_state) = genesis_state { - starting_storage_state.apply(genesis_state)?; - } + let native_function_table = native_function_table.unwrap_or_else(|| { move_stdlib::natives::all_natives( AccountAddress::from_hex_literal("0x1").unwrap(), move_stdlib::natives::GasParameters::zeros(), ) }); + let runtime_environment = RuntimeEnvironment::new(native_function_table); + + let modules = tests.module_info.values().map(|info| &info.module); + let mut starting_storage_state = setup_test_storage(modules, runtime_environment)?; + if let Some(genesis_state) = genesis_state { + starting_storage_state.apply(genesis_state)?; + } + Ok(Self { testing_config: SharedTestingConfig { save_storage_state_on_failure, report_stacktrace_on_abort, starting_storage_state, - native_function_table, source_files, record_writeset, #[cfg(feature = "evm-backend")] @@ -254,11 +257,9 @@ impl SharedTestingConfig { ) { // Note: While Move unit tests run concurrently, there is no publishing involved. To keep // things simple, we create a new VM instance for each test. - let runtime_environment = RuntimeEnvironment::new(self.native_function_table.clone()); - let move_vm = MoveVM::new_with_runtime_environment(&runtime_environment); - let module_storage = self - .starting_storage_state - .as_unsync_module_storage(runtime_environment.clone()); + let move_vm = + MoveVM::new_with_runtime_environment(self.starting_storage_state.runtime_environment()); + let module_storage = self.starting_storage_state.as_unsync_module_storage(); let extensions = extensions::new_extensions(); let mut session =