diff --git a/Cargo.lock b/Cargo.lock index 25c4db8447706..84e1320ac8c6a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -794,7 +794,9 @@ dependencies = [ "clap 4.4.14", "futures", "itertools 0.12.1", + "move-command-line-common", "move-compiler", + "move-compiler-v2", "move-core-types", "move-model", "move-package", diff --git a/aptos-move/aptos-e2e-comparison-testing/Cargo.toml b/aptos-move/aptos-e2e-comparison-testing/Cargo.toml index e28cf89d1a5d4..f8edee26f2e3d 100644 --- a/aptos-move/aptos-e2e-comparison-testing/Cargo.toml +++ b/aptos-move/aptos-e2e-comparison-testing/Cargo.toml @@ -22,7 +22,9 @@ bcs = { workspace = true } clap = { workspace = true } futures = { workspace = true } itertools = { workspace = true } +move-command-line-common = { workspace = true } move-compiler = { workspace = true } +move-compiler-v2 = { workspace = true } move-core-types = { workspace = true } move-model = { workspace = true } move-package = { workspace = true } diff --git a/aptos-move/aptos-e2e-comparison-testing/src/execution.rs b/aptos-move/aptos-e2e-comparison-testing/src/execution.rs index 27838857b47e7..879b373793923 100644 --- a/aptos-move/aptos-e2e-comparison-testing/src/execution.rs +++ b/aptos-move/aptos-e2e-comparison-testing/src/execution.rs @@ -4,24 +4,27 @@ use crate::{ check_aptos_packages_availability, compile_aptos_packages, compile_package, data_state_view::DataStateView, generate_compiled_blob, is_aptos_package, CompilationCache, - DataManager, IndexReader, PackageInfo, TxnIndex, APTOS_COMMONS, + DataManager, IndexReader, PackageInfo, TxnIndex, APTOS_COMMONS, DISABLE_REF_CHECK, + DISABLE_SPEC_CHECK, ENABLE_REF_CHECK, }; use anyhow::Result; use aptos_framework::APTOS_PACKAGES; use aptos_language_e2e_tests::{data_store::FakeDataStore, executor::FakeExecutor}; use aptos_types::{ + access_path::Path, contract_event::ContractEvent, on_chain_config::{FeatureFlag, Features, OnChainConfig}, - transaction::{Transaction, Version}, + state_store::state_key::{inner::StateKeyInner, StateKey}, + transaction::{Transaction, Transaction::UserTransaction, TransactionStatus, Version}, vm_status::VMStatus, - write_set::WriteSet, + write_set::{WriteSet, TOTAL_SUPPLY_STATE_KEY}, }; use aptos_validator_interface::AptosValidatorInterface; use clap::ValueEnum; use itertools::Itertools; use move_core_types::{account_address::AccountAddress, language_storage::ModuleId}; use move_model::metadata::CompilerVersion; -use std::{cmp, collections::HashMap, path::PathBuf, sync::Arc}; +use std::{cmp, collections::HashMap, env, path::PathBuf, sync::Arc}; fn add_packages_to_data_store( data_store: &mut FakeDataStore, @@ -90,18 +93,34 @@ pub struct Execution { input_path: PathBuf, pub execution_mode: ExecutionMode, pub bytecode_version: u32, + pub skip_ref_packages: Option, } impl Execution { + pub fn check_package_skip(&self, package_name: &str) -> bool { + println!("package name:{}", package_name); + if let Some(p) = &self.skip_ref_packages { + let packages = p.split(',').collect_vec(); + packages.contains(&package_name) + } else { + false + } + } + pub fn output_result_str(&self, msg: String) { eprintln!("{}", msg); } - pub fn new(input_path: PathBuf, execution_mode: ExecutionMode) -> Self { + pub fn new( + input_path: PathBuf, + execution_mode: ExecutionMode, + skip_ref_packages: Option, + ) -> Self { Self { input_path, execution_mode, bytecode_version: 6, + skip_ref_packages, } } @@ -220,6 +239,17 @@ impl Execution { if compiled_cache.failed_packages_v2.contains(&package_info) { v2_failed = true; } else { + if self.check_package_skip(&package_info.package_name) { + env::set_var( + "MOVE_COMPILER_EXP", + format!("{},{}", DISABLE_SPEC_CHECK, DISABLE_REF_CHECK), + ); + } else { + env::set_var( + "MOVE_COMPILER_EXP", + format!("{},{}", DISABLE_SPEC_CHECK, ENABLE_REF_CHECK), + ); + } let compiled_res_v2 = compile_package(package_dir, &package_info, Some(CompilerVersion::V2_0)); if let Ok(compiled_res) = compiled_res_v2 { @@ -237,7 +267,10 @@ impl Execution { } } if v1_failed || v2_failed { - let mut err_msg = "compilation failed at ".to_string(); + let mut err_msg = format!( + "compilation for the package {} failed at", + package_info.package_name + ); if v1_failed { err_msg = format!("{} v1", err_msg); } @@ -255,18 +288,16 @@ impl Execution { data_manager: &DataManager, compiled_cache: &mut CompilationCache, ) -> Result<()> { - if let Some(txn_idx) = data_manager.get_txn_index(cur_version) { + if let Some(mut txn_idx) = data_manager.get_txn_index(cur_version) { // compile the code if the source code is available if txn_idx.package_info.is_compilable() && !is_aptos_package(&txn_idx.package_info.package_name) { let compiled_result = self.compile_code(&txn_idx, compiled_cache); if compiled_result.is_err() { - self.output_result_str(format!( - "compilation failed for the package:{} at version:{}", - txn_idx.package_info.package_name, cur_version - )); - return compiled_result; + let err = compiled_result.unwrap_err(); + self.output_result_str(format!("{} at version:{}", err, cur_version)); + return Err(err); } } // read the state data @@ -274,7 +305,7 @@ impl Execution { self.execute_and_compare( cur_version, state, - &txn_idx, + &mut txn_idx, &compiled_cache.compiled_package_cache_v1, &compiled_cache.compiled_package_cache_v2, None, @@ -287,7 +318,7 @@ impl Execution { &self, cur_version: Version, state: FakeDataStore, - txn_idx: &TxnIndex, + txn_idx: &mut TxnIndex, compiled_package_cache: &HashMap>>, compiled_package_cache_v2: &HashMap>>, debugger: Option>, @@ -303,7 +334,7 @@ impl Execution { cur_version, state.clone(), &txn_idx.package_info, - &txn_idx.txn, + &mut txn_idx.txn, package_cache_main, debugger.clone(), v2_flag, @@ -313,7 +344,7 @@ impl Execution { cur_version, state, &txn_idx.package_info, - &txn_idx.txn, + &mut txn_idx.txn, package_cache_other, debugger.clone(), true, @@ -321,10 +352,10 @@ impl Execution { self.print_mismatches(cur_version, &res_main, &res_other); } else { match res_main { - Ok((write_set, events)) => { + Ok(((write_set, events), txn_status)) => { self.output_result_str(format!( - "version:{}\nwrite set:{:?}\n events:{:?}\n", - cur_version, write_set, events + "version:{}\nwrite set:{:?}\n events:{:?}, txn_status:{:?}\n", + cur_version, write_set, events, txn_status )); }, Err(vm_status) => { @@ -342,11 +373,11 @@ impl Execution { version: Version, mut state: FakeDataStore, package_info: &PackageInfo, - txn: &Transaction, + txn: &mut Transaction, compiled_package_cache: &HashMap>>, debugger_opt: Option>, v2_flag: bool, - ) -> Result<(WriteSet, Vec), VMStatus> { + ) -> Result<((WriteSet, Vec), TransactionStatus), VMStatus> { // Always add Aptos (0x1) packages. add_aptos_packages_to_data_store(&mut state, compiled_package_cache); @@ -367,25 +398,55 @@ impl Execution { // We use executor only to get access to block executor and avoid some of // the initializations, but ignore its internal state, i.e., FakeDataStore. let executor = FakeExecutor::no_genesis(); - let txns = vec![txn.clone()]; - + let mut txns = vec![txn.clone()]; + for txn in &mut txns { + if let UserTransaction(signed_transaction) = txn { + signed_transaction.set_max_gmount(signed_transaction.max_gas_amount() * 2); + } + } if let Some(debugger) = debugger_opt { let data_view = DataStateView::new(debugger, version, state); executor - .execute_transaction_block_with_state_view(txns, &data_view) - .map(|mut res| res.pop().unwrap().into()) + .execute_transaction_block_with_state_view(txns, &data_view, false) + .map(|mut res| { + let res_i = res.pop().unwrap(); + (res_i.clone().into(), res_i.status().clone()) + }) } else { - executor - .execute_transaction_block_with_state_view(txns, &state) - .map(|mut res| res.pop().unwrap().into()) + let res = executor + .execute_transaction_block_with_state_view(txns, &state, false) + .map(|mut res| { + let res_i = res.pop().unwrap(); + (res_i.clone().into(), res_i.status().clone()) + }); + res } } + fn filter_stake_key(&self, key: &StateKey) -> bool { + if let StateKeyInner::AccessPath(p) = key.inner() { + let path = p.get_path(); + if let Path::Resource(tag) = path { + if tag.name.as_str() == "CoinStore" && !tag.type_args.is_empty() { + let para_type = &tag.type_args[0]; + if para_type.to_string() == "0x1::aptos_coin::AptosCoin" { + return true; + } + } + } + } + *key == *TOTAL_SUPPLY_STATE_KEY + } + + fn filter_event_key(&self, event: &ContractEvent) -> bool { + event.type_tag().to_string() == "0x1::transaction_fee::FeeStatement" + } + fn print_mismatches( &self, cur_version: u64, - res_1: &Result<(WriteSet, Vec), VMStatus>, - res_2: &Result<(WriteSet, Vec), VMStatus>, + res_1: &Result<((WriteSet, Vec), TransactionStatus), VMStatus>, + res_2: &Result<((WriteSet, Vec), TransactionStatus), VMStatus>, ) { match (res_1, res_2) { (Err(e1), Err(e2)) => { @@ -410,7 +471,14 @@ impl Execution { cur_version )); }, - (Ok(res_1), Ok(res_2)) => { + (Ok((res_1, txn_status_1)), Ok((res_2, txn_status_2))) => { + // compare txn status + if txn_status_1 != txn_status_2 { + println!("txn status is different at version: {}", cur_version); + println!("status from V1:{:?}", txn_status_1); + println!("status from V2:{:?}", txn_status_2); + return; + } // compare events let mut event_error = false; if res_1.1.len() != res_2.1.len() { @@ -419,7 +487,7 @@ impl Execution { for idx in 0..cmp::min(res_1.1.len(), res_2.1.len()) { let event_1 = &res_1.1[idx]; let event_2 = &res_2.1[idx]; - if event_1 != event_2 { + if event_1 != event_2 && !self.filter_event_key(event_1) { event_error = true; self.output_result_str(format!( "event raised from V1: {} at index: {}", @@ -462,11 +530,14 @@ impl Execution { write_set_2.0, idx )); } - if write_set_1.1 != write_set_2.1 { + if write_set_1.1 != write_set_2.1 + && write_set_1.0 == write_set_2.0 + && !self.filter_stake_key(write_set_1.0) + { write_set_error = true; self.output_result_str(format!( - "write set value is different at version: {}, index: {}", - cur_version, idx + "write set value is different at version: {}, index: {} for key:{:?}, key eq:{}", + cur_version, idx, write_set_1.0, write_set_1.0 == write_set_2.0 )); self.output_result_str(format!( "state value at V1: {:?} at index: {}", diff --git a/aptos-move/aptos-e2e-comparison-testing/src/lib.rs b/aptos-move/aptos-e2e-comparison-testing/src/lib.rs index 83dbfb1af3613..06507963062df 100644 --- a/aptos-move/aptos-e2e-comparison-testing/src/lib.rs +++ b/aptos-move/aptos-e2e-comparison-testing/src/lib.rs @@ -57,6 +57,9 @@ const ERR_LOG: &str = "err_log.txt"; const ROCKS_INDEX_DB: &str = "rocks_txn_idx_db"; pub const APTOS_COMMONS: &str = "aptos-commons"; const MAX_TO_FLUSH: usize = 50000; +pub const DISABLE_SPEC_CHECK: &str = "spec-check=off"; +pub const DISABLE_REF_CHECK: &str = "reference-safety=off"; +pub const ENABLE_REF_CHECK: &str = "reference-safety=on"; struct IndexWriter { index_writer: BufWriter, @@ -436,10 +439,10 @@ fn compile_aptos_packages( fn compile_package( root_dir: PathBuf, package_info: &PackageInfo, - compiler_verion: Option, + compiler_version: Option, ) -> anyhow::Result { let mut build_options = aptos_framework::BuildOptions { - compiler_version: compiler_verion, + compiler_version, ..Default::default() }; build_options @@ -450,8 +453,9 @@ fn compile_package( Ok(built_package.package) } else { Err(anyhow::Error::msg(format!( - "compilation failed for compiler: {:?}", - compiler_verion + "compilation failed for the package:{} when using compiler: {:?}", + package_info.package_name.clone(), + compiler_version ))) } } @@ -465,7 +469,16 @@ fn dump_and_compile_from_package_metadata( ) -> anyhow::Result<()> { let root_package_dir = root_dir.join(format!("{}", package_info,)); if compilation_cache.failed_packages_v1.contains(&package_info) { - return Err(anyhow::Error::msg("compilation failed")); + return Err(anyhow::Error::msg(format!( + "compilation failed for the package:{} when using compiler v1", + package_info.package_name + ))); + } + if compilation_cache.failed_packages_v2.contains(&package_info) { + return Err(anyhow::Error::msg(format!( + "compilation failed for the package:{} when using compiler v2", + package_info.package_name + ))); } if !root_package_dir.exists() { std::fs::create_dir_all(root_package_dir.as_path())?; @@ -570,9 +583,14 @@ fn dump_and_compile_from_package_metadata( .insert(package_info.clone(), built_package); } else { if !compilation_cache.failed_packages_v1.contains(&package_info) { - compilation_cache.failed_packages_v1.insert(package_info); + compilation_cache + .failed_packages_v1 + .insert(package_info.clone()); } - return Err(anyhow::Error::msg("compilation failed at v1")); + return Err(anyhow::Error::msg(format!( + "compilation failed for the package:{} when using compiler v1", + package_info.package_name + ))); } if execution_mode.is_some_and(|mode| mode.is_v2_or_compare()) { let package_v2 = @@ -584,10 +602,15 @@ fn dump_and_compile_from_package_metadata( &mut compilation_cache.compiled_package_cache_v2, ); } else { - if !compilation_cache.failed_packages_v1.contains(&package_info) { - compilation_cache.failed_packages_v1.insert(package_info); + if !compilation_cache.failed_packages_v2.contains(&package_info) { + compilation_cache + .failed_packages_v2 + .insert(package_info.clone()); } - return Err(anyhow::Error::msg("compilation failed at v2")); + return Err(anyhow::Error::msg(format!( + "compilation failed for the package:{} when using compiler v2", + package_info.package_name + ))); } } } diff --git a/aptos-move/aptos-e2e-comparison-testing/src/main.rs b/aptos-move/aptos-e2e-comparison-testing/src/main.rs index 0d50666fe345f..0e8ae68cbbe73 100644 --- a/aptos-move/aptos-e2e-comparison-testing/src/main.rs +++ b/aptos-move/aptos-e2e-comparison-testing/src/main.rs @@ -3,12 +3,15 @@ use anyhow::Result; use aptos_comparison_testing::{ - prepare_aptos_packages, DataCollection, Execution, ExecutionMode, OnlineExecutor, APTOS_COMMONS, + prepare_aptos_packages, DataCollection, Execution, ExecutionMode, OnlineExecutor, + APTOS_COMMONS, DISABLE_SPEC_CHECK, }; use aptos_rest_client::Client; use clap::{Parser, Subcommand}; +use move_command_line_common::env::OVERRIDE_EXP_CACHE; +use move_compiler_v2::Experiment; use move_core_types::account_address::AccountAddress; -use std::path::PathBuf; +use std::{env, path::PathBuf}; use url::Url; const BATCH_SIZE: u64 = 500; @@ -58,6 +61,9 @@ pub enum Cmd { /// Used when execution_only is true #[clap(long)] execution_mode: Option, + /// Packages to be skipped for reference safety check + #[clap(long)] + skip_ref_packages: Option, }, /// Execution of txns Execute { @@ -66,6 +72,9 @@ pub enum Cmd { /// Whether to execute against V1, V2 alone or both compilers for comparison #[clap(long)] execution_mode: Option, + /// Packages to be skipped for reference safety check + #[clap(long)] + skip_ref_packages: Option, }, } @@ -86,7 +95,15 @@ pub struct Argument { #[tokio::main] async fn main() -> Result<()> { let args = Argument::parse(); - + env::set_var( + OVERRIDE_EXP_CACHE, + format!( + "{},{}", + Experiment::SPEC_CHECK, + Experiment::REFERENCE_SAFETY + ), + ); + env::set_var("MOVE_COMPILER_EXP", DISABLE_SPEC_CHECK); match args.cmd { Cmd::Dump { endpoint, @@ -129,6 +146,7 @@ async fn main() -> Result<()> { skip_failed_txns, skip_publish_txns, execution_mode, + skip_ref_packages, } => { let batch_size = BATCH_SIZE; let output = if let Some(path) = output_path { @@ -148,12 +166,14 @@ async fn main() -> Result<()> { skip_publish_txns, execution_mode.unwrap_or_default(), endpoint, + skip_ref_packages, )?; online.execute(args.begin_version, args.limit).await?; }, Cmd::Execute { input_path, execution_mode, + skip_ref_packages, } => { let input = if let Some(path) = input_path { path @@ -161,7 +181,8 @@ async fn main() -> Result<()> { PathBuf::from(".") }; prepare_aptos_packages(input.join(APTOS_COMMONS)).await; - let executor = Execution::new(input, execution_mode.unwrap_or_default()); + let executor = + Execution::new(input, execution_mode.unwrap_or_default(), skip_ref_packages); executor .execute_txns(args.begin_version, args.limit) .await?; diff --git a/aptos-move/aptos-e2e-comparison-testing/src/online_execution.rs b/aptos-move/aptos-e2e-comparison-testing/src/online_execution.rs index 166f2ff1e808f..04cbb23a52b36 100644 --- a/aptos-move/aptos-e2e-comparison-testing/src/online_execution.rs +++ b/aptos-move/aptos-e2e-comparison-testing/src/online_execution.rs @@ -4,6 +4,7 @@ use crate::{ compile_aptos_packages, dump_and_compile_from_package_metadata, is_aptos_package, CompilationCache, ExecutionMode, IndexWriter, PackageInfo, TxnIndex, APTOS_COMMONS, + DISABLE_REF_CHECK, DISABLE_SPEC_CHECK, ENABLE_REF_CHECK, }; use anyhow::Result; use aptos_framework::natives::code::PackageMetadata; @@ -14,6 +15,7 @@ use aptos_validator_interface::{AptosValidatorInterface, FilterCondition, RestDe use move_core_types::account_address::AccountAddress; use std::{ collections::HashMap, + env, path::PathBuf, sync::{Arc, Mutex}, }; @@ -26,6 +28,7 @@ pub struct OnlineExecutor { filter_condition: FilterCondition, execution_mode: ExecutionMode, endpoint: String, + skip_ref_packages: Option, } impl OnlineExecutor { @@ -37,6 +40,7 @@ impl OnlineExecutor { skip_publish_txns: bool, execution_mode: ExecutionMode, endpoint: String, + skip_ref_packages: Option, ) -> Self { Self { debugger, @@ -50,6 +54,7 @@ impl OnlineExecutor { }, execution_mode, endpoint, + skip_ref_packages, } } @@ -61,6 +66,7 @@ impl OnlineExecutor { skip_publish_txns: bool, execution_mode: ExecutionMode, endpoint: String, + skip_ref_packages: Option, ) -> Result { Ok(Self::new( Arc::new(RestDebuggerInterface::new(rest_client)), @@ -70,6 +76,7 @@ impl OnlineExecutor { skip_publish_txns, execution_mode, endpoint, + skip_ref_packages, )) } @@ -176,10 +183,15 @@ impl OnlineExecutor { let current_dir = self.current_dir.clone(); let execution_mode = self.execution_mode; let endpoint = self.endpoint.clone(); + let skip_ref_packages = self.skip_ref_packages.clone(); let txn_execution_thread = tokio::task::spawn_blocking(move || { - let executor = crate::Execution::new(current_dir.clone(), execution_mode); - + println!("skip packages:{:?}", skip_ref_packages); + let executor = crate::Execution::new( + current_dir.clone(), + execution_mode, + skip_ref_packages, + ); let mut version_idx = TxnIndex { version, txn: txn.clone(), @@ -188,6 +200,17 @@ impl OnlineExecutor { // handle source code if let Some((address, package_name, map)) = source_code_data { + if executor.check_package_skip(&package_name) { + env::set_var( + "MOVE_COMPILER_EXP", + format!("{},{}", DISABLE_SPEC_CHECK, DISABLE_REF_CHECK), + ); + } else { + env::set_var( + "MOVE_COMPILER_EXP", + format!("{},{}", DISABLE_SPEC_CHECK, ENABLE_REF_CHECK), + ); + } let execution_mode_opt = Some(execution_mode); let package_info_opt = Self::dump_and_check_src( version, @@ -222,7 +245,7 @@ impl OnlineExecutor { executor.execute_and_compare( version, state_store, - &version_idx, + &mut version_idx, &cache_v1, &cache_v2, Some(debugger), diff --git a/aptos-move/aptos-vm-types/src/environment.rs b/aptos-move/aptos-vm-types/src/environment.rs index 618676f8d7034..fca9ede1ee537 100644 --- a/aptos-move/aptos-vm-types/src/environment.rs +++ b/aptos-move/aptos-vm-types/src/environment.rs @@ -84,6 +84,16 @@ impl Environment { )) } + pub fn with_features_for_testing(self, features: Features) -> Arc { + let ty_builder = aptos_default_ty_builder(); + Arc::new(Self::initialize( + features, + self.timed_features, + self.chain_id, + ty_builder, + )) + } + pub fn try_enable_delayed_field_optimization(mut self) -> Self { if self.features.is_aggregator_v2_delayed_fields_enabled() { self.vm_config.delayed_field_optimization_enabled = true; diff --git a/aptos-move/e2e-tests/src/executor.rs b/aptos-move/e2e-tests/src/executor.rs index 1e00807b31264..cc36a54b72231 100644 --- a/aptos-move/e2e-tests/src/executor.rs +++ b/aptos-move/e2e-tests/src/executor.rs @@ -34,14 +34,15 @@ use aptos_types::{ chain_id::ChainId, contract_event::ContractEvent, move_utils::MemberId, - on_chain_config::{AptosVersion, OnChainConfig, ValidatorSet}, + on_chain_config::{AptosVersion, FeatureFlag, Features, OnChainConfig, ValidatorSet}, state_store::{state_key::StateKey, state_value::StateValue, StateView, TStateView}, transaction::{ signature_verified_transaction::{ into_signature_verified_block, SignatureVerifiedTransaction, }, - BlockOutput, ExecutionStatus, SignedTransaction, Transaction, TransactionOutput, - TransactionPayload, TransactionStatus, VMValidatorResult, ViewFunctionOutput, + BlockOutput, EntryFunction, ExecutionStatus, SignedTransaction, Transaction, + TransactionOutput, TransactionPayload, TransactionStatus, VMValidatorResult, + ViewFunctionOutput, }, vm_status::VMStatus, write_set::WriteSet, @@ -49,9 +50,9 @@ use aptos_types::{ use aptos_vm::{ block_executor::{AptosTransactionOutput, BlockAptosVM}, data_cache::AsMoveResolver, - gas::make_prod_gas_meter, - move_vm_ext::{MoveVmExt, SessionId}, - AptosVM, VMValidator, + gas::{get_gas_parameters, make_prod_gas_meter}, + move_vm_ext::{AptosMoveResolver, MoveVmExt, SessionId}, + verifier, AptosVM, VMValidator, }; use aptos_vm_genesis::{generate_genesis_change_set_for_testing_with_count, GenesisOptions}; use aptos_vm_logging::log_schema::AdapterLogSchema; @@ -549,6 +550,7 @@ impl FakeExecutor { &self, txn_block: Vec, state_view: &(impl StateView + Sync), + check_signature: bool, ) -> Result, VMStatus> { let mut trace_map: (usize, Vec, Vec) = TraceSeqMapping::default(); @@ -563,7 +565,15 @@ impl FakeExecutor { } } - let sig_verified_block = into_signature_verified_block(txn_block); + let sig_verified_block = if check_signature { + into_signature_verified_block(txn_block) + } else { + let mut verified = vec![]; + for txn in txn_block { + verified.push(SignatureVerifiedTransaction::Valid(txn)) + } + verified + }; let mode = self.executor_mode.unwrap_or_else(|| { if env::var(ENV_ENABLE_PARALLEL).is_ok() { @@ -647,7 +657,7 @@ impl FakeExecutor { &self, txn_block: Vec, ) -> Result, VMStatus> { - self.execute_transaction_block_with_state_view(txn_block, &self.data_store) + self.execute_transaction_block_with_state_view(txn_block, &self.data_store, true) } pub fn execute_transaction(&self, txn: SignedTransaction) -> TransactionOutput { @@ -1095,6 +1105,83 @@ impl FakeExecutor { self.exec_module(&Self::module(module_name), function_name, type_params, args) } + pub fn try_exec_entry_with_state_view( + &mut self, + senders: Vec, + entry_fn: &EntryFunction, + state_view: &impl AptosMoveResolver, + features: Features, + ) -> Result<(WriteSet, Vec), VMStatus> { + let (gas_params, storage_gas_params, gas_feature_version) = + get_gas_parameters(&features, state_view); + + let are_struct_constructors_enabled = features.is_enabled(FeatureFlag::STRUCT_CONSTRUCTORS); + let env = self + .env + .as_ref() + .clone() + .with_features_for_testing(features); + + let vm = MoveVmExt::new( + LATEST_GAS_FEATURE_VERSION, + gas_params.as_ref(), + env, + state_view, + ); + + let mut session = vm.new_session(state_view, SessionId::void(), None); + let func = + session.load_function(entry_fn.module(), entry_fn.function(), entry_fn.ty_args())?; + let args = verifier::transaction_arg_validation::validate_combine_signer_and_txn_args( + &mut session, + senders, + entry_fn.args().to_vec(), + &func, + are_struct_constructors_enabled, + )?; + + let storage = TraversalStorage::new(); + if gas_params.is_ok() && storage_gas_params.is_ok() { + let gas_params = gas_params.unwrap(); + let mut gas_meter = make_prod_gas_meter( + gas_feature_version, + gas_params.clone().vm, + storage_gas_params.unwrap(), + false, + 100_000_000.into(), + ); + session + .execute_entry_function( + func, + args, + &mut gas_meter, + &mut TraversalContext::new(&storage), + ) + .map_err(|e| e.into_vm_status())?; + } else { + session + .execute_entry_function( + func, + args, + &mut UnmeteredGasMeter, + &mut TraversalContext::new(&storage), + ) + .map_err(|e| e.into_vm_status())?; + } + + let (mut change_set, module_write_set) = session + .finish(&ChangeSetConfigs::unlimited_at_gas_feature_version( + LATEST_GAS_FEATURE_VERSION, + )) + .expect("Failed to generate txn effects"); + change_set.try_materialize_aggregator_v1_delta_set(state_view)?; + let (write_set, events) = change_set + .try_combine_into_storage_change_set(module_write_set) + .expect("Failed to convert to ChangeSet") + .into_inner(); + Ok((write_set, events)) + } + pub fn try_exec( &mut self, module_name: &str, diff --git a/third_party/move/move-command-line-common/src/env.rs b/third_party/move/move-command-line-common/src/env.rs index a2c7df2991849..2b97da76a8632 100644 --- a/third_party/move/move-command-line-common/src/env.rs +++ b/third_party/move/move-command-line-common/src/env.rs @@ -50,6 +50,8 @@ pub fn get_move_compiler_block_v1_from_env() -> bool { read_bool_env_var(MOVE_COMPILER_BLOCK_V1_ENV_VAR) || read_bool_env_var(MVC_BLOCK_V1_ENV_VAR) } +pub const OVERRIDE_EXP_CACHE: &str = "OVERRIDE_EXP_CACHE"; + pub fn read_env_var(v: &str) -> String { std::env::var(v).unwrap_or_else(|_| String::new()) } diff --git a/third_party/move/move-compiler-v2/src/lib.rs b/third_party/move/move-compiler-v2/src/lib.rs index f817957b6b274..a5206e37c9b26 100644 --- a/third_party/move/move-compiler-v2/src/lib.rs +++ b/third_party/move/move-compiler-v2/src/lib.rs @@ -7,7 +7,7 @@ pub mod ast_simplifier; mod bytecode_generator; pub mod cyclic_instantiation_checker; pub mod env_pipeline; -mod experiments; +pub mod experiments; mod file_format_generator; pub mod flow_insensitive_checkers; pub mod function_checker; diff --git a/third_party/move/move-compiler-v2/src/options.rs b/third_party/move/move-compiler-v2/src/options.rs index 60bc379f7211f..1b3c9c02eec51 100644 --- a/third_party/move/move-compiler-v2/src/options.rs +++ b/third_party/move/move-compiler-v2/src/options.rs @@ -6,7 +6,7 @@ use crate::experiments::{DefaultValue, EXPERIMENTS}; use clap::Parser; use codespan_reporting::diagnostic::Severity; use itertools::Itertools; -use move_command_line_common::env::{bool_to_str, read_env_var}; +use move_command_line_common::env::{bool_to_str, read_env_var, OVERRIDE_EXP_CACHE}; use move_compiler::{ command_line as cli, shared::{ @@ -163,8 +163,15 @@ impl Options { visited.iter().clone().join(",") ) } - if let Some(on) = self.experiment_cache.borrow().get(name).cloned() { - return on; + let experiments_to_override = read_env_var(OVERRIDE_EXP_CACHE); + let experiments = experiments_to_override + .split(',') + .map(|s| s.to_string()) + .collect_vec(); + if !experiments.contains(&name.to_string()) { + if let Some(on) = self.experiment_cache.borrow().get(name).cloned() { + return on; + } } if let Some(exp) = EXPERIMENTS.get(&name.to_string()) { // First we look at experiments provided via the command line, second @@ -281,6 +288,14 @@ fn compiler_exp_var() -> Vec { } vec![] }); + if !read_env_var(OVERRIDE_EXP_CACHE).is_empty() { + for s in ["MVC_EXP", "MOVE_COMPILER_EXP"] { + let s = read_env_var(s); + if !s.is_empty() { + return s.split(',').map(|s| s.to_string()).collect(); + } + } + } (*EXP_VAR).clone() } diff --git a/types/src/transaction/mod.rs b/types/src/transaction/mod.rs index 6813e98ceb469..6e63055cc626d 100644 --- a/types/src/transaction/mod.rs +++ b/types/src/transaction/mod.rs @@ -670,6 +670,10 @@ impl SignedTransaction { self.raw_txn.max_gas_amount } + pub fn set_max_gmount(&mut self, new_value: u64) { + self.raw_txn.max_gas_amount = new_value; + } + pub fn gas_unit_price(&self) -> u64 { self.raw_txn.gas_unit_price }