From 21a8b49ab02811ee4b5c1a0202b502f6c83758b1 Mon Sep 17 00:00:00 2001 From: George Mitenkov Date: Tue, 5 Nov 2024 17:45:12 +0000 Subject: [PATCH] [global cache] Draft e2e implementation --- Cargo.lock | 24 ++ Cargo.toml | 2 + aptos-move/aptos-debugger/Cargo.toml | 1 + .../aptos-debugger/src/aptos_debugger.rs | 13 +- .../aptos-e2e-comparison-testing/Cargo.toml | 1 + .../src/data_collection.rs | 15 +- .../aptos-global-cache-manager/Cargo.toml | 22 ++ .../aptos-global-cache-manager/src/lib.rs | 236 ++++++++++++++++++ .../aptos-transaction-benchmarks/Cargo.toml | 1 + .../src/transaction_bench_state.rs | 16 ++ .../Cargo.toml | 1 + .../src/aptos_test_harness.rs | 25 +- .../aptos-vm-environment/src/environment.rs | 6 +- aptos-move/aptos-vm-profiling/Cargo.toml | 1 + .../src/bins/run_aptos_p2p.rs | 13 +- aptos-move/aptos-vm/Cargo.toml | 1 + aptos-move/aptos-vm/src/aptos_vm.rs | 3 + aptos-move/aptos-vm/src/block_executor/mod.rs | 137 ++-------- aptos-move/aptos-vm/src/lib.rs | 13 +- .../sharded_executor_service.rs | 2 +- .../aptos-vm/tests/sharded_block_executor.rs | 46 +++- aptos-move/e2e-tests/src/executor.rs | 2 +- execution/executor-benchmark/Cargo.toml | 1 + .../executor-benchmark/src/native_executor.rs | 4 + execution/executor-service/Cargo.toml | 1 + execution/executor-service/src/test_utils.rs | 25 +- execution/executor/Cargo.toml | 1 + execution/executor/src/block_executor/mod.rs | 32 ++- execution/executor/src/chunk_executor/mod.rs | 13 +- .../src/chunk_executor/transaction_chunk.rs | 15 +- execution/executor/src/db_bootstrapper/mod.rs | 12 +- execution/executor/src/fuzzing.rs | 4 + .../src/tests/mock_vm/mock_vm_test.rs | 35 ++- execution/executor/src/tests/mock_vm/mod.rs | 4 + execution/executor/src/tests/mod.rs | 24 +- .../src/workflow/do_get_execution_output.rs | 31 ++- .../execution/ptx-executor/Cargo.toml | 1 + .../execution/ptx-executor/src/lib.rs | 4 + storage/db-tool/Cargo.toml | 1 + storage/db-tool/src/replay_on_archive.rs | 20 +- types/src/on_chain_config/aptos_features.rs | 3 + types/src/read_only_module_cache.rs | 33 +-- 42 files changed, 625 insertions(+), 220 deletions(-) create mode 100644 aptos-move/aptos-global-cache-manager/Cargo.toml create mode 100644 aptos-move/aptos-global-cache-manager/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 163f51b79c8d24..8576bcf92377bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -810,6 +810,7 @@ version = "0.1.0" dependencies = [ "anyhow", "aptos-framework", + "aptos-global-cache-manager", "aptos-language-e2e-tests", "aptos-rest-client", "aptos-types", @@ -1262,6 +1263,7 @@ dependencies = [ "aptos-executor", "aptos-executor-test-helpers", "aptos-executor-types", + "aptos-global-cache-manager", "aptos-logger", "aptos-storage-interface", "aptos-temppath", @@ -1460,6 +1462,7 @@ dependencies = [ "aptos-executor-types", "aptos-experimental-runtimes", "aptos-genesis", + "aptos-global-cache-manager", "aptos-indexer-grpc-table-info", "aptos-infallible", "aptos-logger", @@ -1501,6 +1504,7 @@ dependencies = [ "aptos-experimental-ptx-executor", "aptos-experimental-runtimes", "aptos-genesis", + "aptos-global-cache-manager", "aptos-jellyfish-merkle", "aptos-logger", "aptos-metrics-core", @@ -1539,6 +1543,7 @@ version = "0.1.0" dependencies = [ "aptos-block-partitioner", "aptos-config", + "aptos-global-cache-manager", "aptos-infallible", "aptos-language-e2e-tests", "aptos-logger", @@ -1649,6 +1654,7 @@ dependencies = [ "aptos-executor", "aptos-executor-types", "aptos-experimental-runtimes", + "aptos-global-cache-manager", "aptos-infallible", "aptos-logger", "aptos-metrics-core", @@ -2053,6 +2059,19 @@ dependencies = [ "ureq", ] +[[package]] +name = "aptos-global-cache-manager" +version = "0.0.1" +dependencies = [ + "aptos-crypto", + "aptos-types", + "aptos-vm-environment", + "move-binary-format", + "move-core-types", + "move-vm-runtime", + "parking_lot 0.12.1", +] + [[package]] name = "aptos-global-constants" version = "0.1.0" @@ -2879,6 +2898,7 @@ dependencies = [ "aptos-consensus", "aptos-crypto", "aptos-gas-profiling", + "aptos-global-cache-manager", "aptos-logger", "aptos-rest-client", "aptos-types", @@ -4229,6 +4249,7 @@ dependencies = [ "aptos-block-executor", "aptos-block-partitioner", "aptos-crypto", + "aptos-global-cache-manager", "aptos-language-e2e-tests", "aptos-logger", "aptos-metrics-core", @@ -4333,6 +4354,7 @@ dependencies = [ "aptos-crypto", "aptos-framework", "aptos-gas-schedule", + "aptos-global-cache-manager", "aptos-language-e2e-tests", "aptos-resource-viewer", "aptos-storage-interface", @@ -4506,6 +4528,7 @@ dependencies = [ "aptos-gas-algebra", "aptos-gas-meter", "aptos-gas-schedule", + "aptos-global-cache-manager", "aptos-infallible", "aptos-language-e2e-tests", "aptos-logger", @@ -4629,6 +4652,7 @@ dependencies = [ "anyhow", "aptos-cached-packages", "aptos-gas-schedule", + "aptos-global-cache-manager", "aptos-language-e2e-tests", "aptos-move-stdlib", "aptos-native-interface", diff --git a/Cargo.toml b/Cargo.toml index c9b687d313c277..d5cc548f071792 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,6 +16,7 @@ members = [ "aptos-move/aptos-gas-profiling", "aptos-move/aptos-gas-schedule", "aptos-move/aptos-gas-schedule-updator", + "aptos-move/aptos-global-cache-manager", "aptos-move/aptos-memory-usage-tracker", "aptos-move/aptos-native-interface", "aptos-move/aptos-release-builder", @@ -358,6 +359,7 @@ aptos-gas-schedule = { path = "aptos-move/aptos-gas-schedule" } aptos-gas-schedule-updator = { path = "aptos-move/aptos-gas-schedule-updator" } aptos-genesis = { path = "crates/aptos-genesis" } aptos-github-client = { path = "crates/aptos-github-client" } +aptos-global-cache-manager = { path = "aptos-move/aptos-global-cache-manager" } aptos-global-constants = { path = "config/global-constants" } aptos-id-generator = { path = "crates/aptos-id-generator" } aptos-indexer = { path = "crates/indexer" } diff --git a/aptos-move/aptos-debugger/Cargo.toml b/aptos-move/aptos-debugger/Cargo.toml index 8e83673767603b..d8bfc76cd3e603 100644 --- a/aptos-move/aptos-debugger/Cargo.toml +++ b/aptos-move/aptos-debugger/Cargo.toml @@ -18,6 +18,7 @@ aptos-block-executor = { workspace = true } aptos-consensus = { workspace = true } aptos-crypto = { workspace = true } aptos-gas-profiling = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-logger = { workspace = true } aptos-rest-client = { workspace = true } aptos-types = { workspace = true } diff --git a/aptos-move/aptos-debugger/src/aptos_debugger.rs b/aptos-move/aptos-debugger/src/aptos_debugger.rs index 743bea9f096167..85ef339be8a491 100644 --- a/aptos-move/aptos-debugger/src/aptos_debugger.rs +++ b/aptos-move/aptos-debugger/src/aptos_debugger.rs @@ -4,6 +4,7 @@ use anyhow::{bail, format_err, Result}; use aptos_block_executor::txn_commit_hook::NoOpTransactionCommitHook; use aptos_gas_profiling::{GasProfiler, TransactionGasLog}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_rest_client::Client; use aptos_types::{ account_address::AccountAddress, @@ -428,9 +429,15 @@ fn execute_block_no_limit( state_view: &DebuggerStateView, concurrency_level: usize, ) -> Result, VMStatus> { - BlockAptosVM::execute_block::<_, NoOpTransactionCommitHook>( + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(state_view, None)?; + let result = BlockAptosVM::execute_block::< + _, + NoOpTransactionCommitHook, + >( sig_verified_txns, state_view, + &global_cache_manager, BlockExecutorConfig { local: BlockExecutorLocalConfig { concurrency_level, @@ -441,5 +448,7 @@ fn execute_block_no_limit( }, None, ) - .map(BlockOutput::into_transaction_outputs_forced) + .map(BlockOutput::into_transaction_outputs_forced); + global_cache_manager.mark_block_execution_end(None)?; + result } diff --git a/aptos-move/aptos-e2e-comparison-testing/Cargo.toml b/aptos-move/aptos-e2e-comparison-testing/Cargo.toml index 30c851670b4df7..71af9ffdc387d8 100644 --- a/aptos-move/aptos-e2e-comparison-testing/Cargo.toml +++ b/aptos-move/aptos-e2e-comparison-testing/Cargo.toml @@ -13,6 +13,7 @@ default-run = "aptos-comparison-testing" [dependencies] anyhow = { workspace = true } aptos-framework = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-language-e2e-tests = { workspace = true } aptos-rest-client = { workspace = true } aptos-types = { workspace = true } diff --git a/aptos-move/aptos-e2e-comparison-testing/src/data_collection.rs b/aptos-move/aptos-e2e-comparison-testing/src/data_collection.rs index 837f495c22287c..1c7d868dd49043 100644 --- a/aptos-move/aptos-e2e-comparison-testing/src/data_collection.rs +++ b/aptos-move/aptos-e2e-comparison-testing/src/data_collection.rs @@ -7,6 +7,7 @@ use crate::{ }; use anyhow::{format_err, Result}; use aptos_framework::natives::code::PackageMetadata; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_rest_client::Client; use aptos_types::{ state_store::{state_key::StateKey, state_value::StateValue, TStateView}, @@ -92,8 +93,18 @@ impl DataCollection { // FIXME(#10412): remove the assert let val = debugger_state_view.get_state_value(TOTAL_SUPPLY_STATE_KEY.deref()); assert!(val.is_ok() && val.unwrap().is_some()); - AptosVM::execute_block_no_limit(&sig_verified_txns, debugger_state_view) - .map_err(|err| format_err!("Unexpected VM Error: {:?}", err)) + + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(debugger_state_view, None)?; + let result = AptosVM::execute_block_no_limit( + &sig_verified_txns, + debugger_state_view, + &global_cache_manager, + ) + .map_err(|err| format_err!("Unexpected VM Error: {:?}", err)); + global_cache_manager.mark_block_execution_end(None)?; + + result } fn dump_and_check_src( diff --git a/aptos-move/aptos-global-cache-manager/Cargo.toml b/aptos-move/aptos-global-cache-manager/Cargo.toml new file mode 100644 index 00000000000000..71fcaae3ce1e5b --- /dev/null +++ b/aptos-move/aptos-global-cache-manager/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "aptos-global-cache-manager" +description = "Aptos global module and environement cache manager" +version = "0.0.1" + +# Workspace inherited keys +authors = { workspace = true } +edition = { workspace = true } +homepage = { workspace = true } +license = { workspace = true } +publish = { workspace = true } +repository = { workspace = true } +rust-version = { workspace = true } + +[dependencies] +aptos-crypto = { workspace = true } +aptos-types = { workspace = true } +aptos-vm-environment = { workspace = true } +parking_lot = { workspace = true } +move-binary-format = { workspace = true } +move-core-types = { workspace = true } +move-vm-runtime = { workspace = true } diff --git a/aptos-move/aptos-global-cache-manager/src/lib.rs b/aptos-move/aptos-global-cache-manager/src/lib.rs new file mode 100644 index 00000000000000..490f66f08f0a59 --- /dev/null +++ b/aptos-move/aptos-global-cache-manager/src/lib.rs @@ -0,0 +1,236 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use aptos_crypto::HashValue; +use aptos_types::{ + read_only_module_cache::ReadOnlyModuleCache, state_store::StateView, + vm::modules::AptosModuleExtension, +}; +use aptos_vm_environment::environment::AptosEnvironment; +use move_binary_format::{errors::Location, CompiledModule}; +use move_core_types::{ + language_storage::ModuleId, + vm_status::{StatusCode, VMStatus}, +}; +use move_vm_runtime::{Module, WithRuntimeEnvironment}; +use parking_lot::Mutex; +use std::sync::{ + atomic::{AtomicBool, Ordering}, + Arc, +}; + +fn invariant_violation(msg: &str) -> VMStatus { + VMStatus::error( + StatusCode::UNKNOWN_INVARIANT_VIOLATION_ERROR, + Some(msg.to_string()), + ) +} + +struct GlobalCacheConfig { + module_cache_capacity: usize, + struct_name_index_map_capacity: usize, +} + +impl Default for GlobalCacheConfig { + fn default() -> Self { + Self { + module_cache_capacity: 100_000, + struct_name_index_map_capacity: 100_000, + } + } +} + +#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)] +enum BlockId { + Unset, + Set(Option), +} + +impl BlockId { + fn is_unset(&self) -> bool { + matches!(self, Self::Unset) + } +} + +pub struct GlobalCacheManager { + config: GlobalCacheConfig, + + module_cache: Arc>, + + previous_block_id: Mutex, + previous_environment: Mutex>, + + ready_for_next_block: AtomicBool, +} + +impl GlobalCacheManager { + #[allow(clippy::new_without_default)] + pub fn new() -> Self { + Self { + config: GlobalCacheConfig::default(), + module_cache: Arc::new(ReadOnlyModuleCache::empty()), + previous_block_id: Mutex::new(BlockId::Unset), + previous_environment: Mutex::new(None), + ready_for_next_block: AtomicBool::new(true), + } + } + + pub fn mark_block_execution_start( + &self, + state_view: &impl StateView, + previous_block_id: Option, + ) -> Result<(), VMStatus> { + let recorded_previous_block_id = { + // Acquire a lock, and check if we are ready to execute the next block. + let previous_block_id = self.previous_block_id.lock(); + if !self.ready_for_next_block.load(Ordering::SeqCst) { + return Err(invariant_violation("Trying to execute blocks concurrently over shared global state, which is not safe")); + } + + // Prepare for execution. Set the flag as not ready to ensure that blocks are not + // executed concurrently using the same cache. + self.ready_for_next_block.store(false, Ordering::SeqCst); + *previous_block_id + }; + + // From here, we perform checks if we need to flush the global caches. If so, this variable + // is set to true. + let mut flush_all_caches = false; + + // Check 1: We must be executing on top of the state we have seen just before. + use BlockId::*; + match (recorded_previous_block_id, previous_block_id) { + // We execute on top of empty state, everything is ok. + (Unset, None) | (Unset, Some(_)) => {}, + + // We execute on top of different (maybe also unspecified) state. In this case, caches + // need to be reset. + (Set(None), None) | (Set(None), Some(_)) | (Set(Some(_)), None) => { + flush_all_caches = true; + }, + + // Otherwise, just check if block hashes do not match. + (Set(Some(recorded_hash)), Some(hash)) => { + if recorded_hash != hash { + flush_all_caches = true; + }; + }, + }; + + // Check 2: Reset global environment if it has changed. If so, caches needs to be flushed. + let new_environment = + AptosEnvironment::new_with_delayed_field_optimization_enabled(state_view); + let mut previous_environment = self.previous_environment.lock(); + match previous_environment.as_ref() { + Some(environment) => { + if environment != &new_environment { + *previous_environment = Some(new_environment); + flush_all_caches = true; + } + }, + None => { + // If the environment is not yet set, set it. + debug_assert!(self.previous_block_id.lock().is_unset()); + *previous_environment = Some(new_environment); + }, + } + + // Check 3: At this point, environment is set to the most-up-to-date value. Check the size + // of caches is within bounds. + let environment = self.previous_environment.lock(); + let runtime_environment = environment + .as_ref() + .expect("Environment has to be set") + .runtime_environment(); + let struct_name_index_map_size = runtime_environment + .struct_name_index_map_size() + .map_err(|err| err.finish(Location::Undefined).into_vm_status())?; + if struct_name_index_map_size > self.config.struct_name_index_map_capacity { + flush_all_caches = true; + } + + if self.module_cache.size() > self.config.module_cache_capacity { + flush_all_caches = true; + } + + if flush_all_caches { + runtime_environment.flush_struct_name_and_info_caches(); + self.module_cache.flush_unchecked(); + } + + Ok(()) + } + + pub fn mark_block_execution_end( + &self, + executed_block_id: Option, + ) -> Result<(), VMStatus> { + // We are done executing a block, reset the previous block id. Do everything under lock to + // ensure it is not possible to execute blocks concurrently. + let mut previous_block_id = self.previous_block_id.lock(); + if self.ready_for_next_block.load(Ordering::SeqCst) { + return Err(invariant_violation("Should not be possible to mark execution end for execution-ready global cache, check if blocks are executed concurrently")); + } + *previous_block_id = BlockId::Set(executed_block_id); + + // Set the flag that the global cache is ready for next execution. + self.ready_for_next_block.store(true, Ordering::SeqCst); + + Ok(()) + } + + pub fn environment(&self) -> Result { + self.previous_environment.lock().clone().ok_or_else(|| { + invariant_violation("Environment must always be set at block execution start") + }) + } + + pub fn module_cache( + &self, + ) -> Arc> { + self.module_cache.clone() + } +} + +#[cfg(test)] +mod test { + // use super::*; + // use aptos_language_e2e_tests::data_store::FakeDataStore; + // use aptos_types::on_chain_config::{FeatureFlag, Features}; + // use aptos_vm_environment::environment::AptosEnvironment; + // use claims::assert_ok; + // use move_vm_types::code::mock_verified_code; + // + // #[test] + // fn test_cross_block_module_cache_flush() { + // let global_module_cache = ReadOnlyModuleCache::empty(); + // + // global_module_cache.insert(0, mock_verified_code(0, None)); + // assert_eq!(global_module_cache.size(), 1); + // + // global_module_cache.flush_unchecked(); + // assert_eq!(global_module_cache.size(), 0); + // + // // Now check that cache is flushed when the environment is flushed. + // let mut state_view = FakeDataStore::default(); + // let env_old = AptosEnvironment::new_with_delayed_field_optimization_enabled(&state_view); + // + // for i in 0..10 { + // global_module_cache.insert(i, mock_verified_code(i, None)); + // } + // assert_eq!(global_module_cache.size(), 10); + // + // let mut features = Features::default(); + // features.disable(FeatureFlag::KEYLESS_ACCOUNTS); + // state_view.set_features(features); + // + // // New environment means we need to also flush global caches - to invalidate struct name + // // indices. + // let env_new = assert_ok!(get_environment_with_delayed_field_optimization_enabled( + // &state_view, + // &global_module_cache, + // )); + // assert!(env_old != env_new); + // assert_eq!(global_module_cache.size(), 0); + // } +} diff --git a/aptos-move/aptos-transaction-benchmarks/Cargo.toml b/aptos-move/aptos-transaction-benchmarks/Cargo.toml index 3fe147d12d47af..43674345b07326 100644 --- a/aptos-move/aptos-transaction-benchmarks/Cargo.toml +++ b/aptos-move/aptos-transaction-benchmarks/Cargo.toml @@ -17,6 +17,7 @@ aptos-bitvec = { workspace = true } aptos-block-executor = { workspace = true } aptos-block-partitioner = { workspace = true } aptos-crypto = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-language-e2e-tests = { workspace = true } aptos-logger = { workspace = true } aptos-metrics-core = { workspace = true } diff --git a/aptos-move/aptos-transaction-benchmarks/src/transaction_bench_state.rs b/aptos-move/aptos-transaction-benchmarks/src/transaction_bench_state.rs index d3a71a1d228626..5a78d2dac8a410 100644 --- a/aptos-move/aptos-transaction-benchmarks/src/transaction_bench_state.rs +++ b/aptos-move/aptos-transaction-benchmarks/src/transaction_bench_state.rs @@ -8,6 +8,7 @@ use aptos_block_partitioner::{ v2::config::PartitionerV2Config, BlockPartitioner, PartitionerConfig, }; use aptos_crypto::HashValue; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_language_e2e_tests::{ account_universe::{AUTransactionGen, AccountPickStyle, AccountUniverse, AccountUniverseGen}, data_store::FakeDataStore, @@ -211,6 +212,11 @@ where maybe_block_gas_limit: Option, ) -> (Vec, usize) { let block_size = transactions.len(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(self.state_view.as_ref(), None) + .unwrap(); + let timer = Instant::now(); let output = BlockAptosVM::execute_block::< _, @@ -218,12 +224,14 @@ where >( transactions, self.state_view.as_ref(), + &global_cache_manager, BlockExecutorConfig::new_maybe_block_limit(1, maybe_block_gas_limit), None, ) .expect("VM should not fail to start") .into_transaction_outputs_forced(); let exec_time = timer.elapsed().as_millis(); + global_cache_manager.mark_block_execution_end(None).unwrap(); (output, block_size * 1000 / exec_time as usize) } @@ -259,6 +267,11 @@ where maybe_block_gas_limit: Option, ) -> (Vec, usize) { let block_size = transactions.len(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(self.state_view.as_ref(), None) + .unwrap(); + let timer = Instant::now(); let output = BlockAptosVM::execute_block::< _, @@ -266,6 +279,7 @@ where >( transactions, self.state_view.as_ref(), + &global_cache_manager, BlockExecutorConfig::new_maybe_block_limit( concurrency_level_per_shard, maybe_block_gas_limit, @@ -276,6 +290,8 @@ where .into_transaction_outputs_forced(); let exec_time = timer.elapsed().as_millis(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + (output, block_size * 1000 / exec_time as usize) } diff --git a/aptos-move/aptos-transactional-test-harness/Cargo.toml b/aptos-move/aptos-transactional-test-harness/Cargo.toml index c0e44b746718dc..af966204112783 100644 --- a/aptos-move/aptos-transactional-test-harness/Cargo.toml +++ b/aptos-move/aptos-transactional-test-harness/Cargo.toml @@ -19,6 +19,7 @@ aptos-cached-packages = { workspace = true } aptos-crypto = { workspace = true } aptos-framework = { workspace = true } aptos-gas-schedule = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-language-e2e-tests = { workspace = true } aptos-resource-viewer = { workspace = true } aptos-storage-interface = { workspace = true } diff --git a/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs b/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs index 28911678a6bd4b..ff6c75317d18f4 100644 --- a/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs +++ b/aptos-move/aptos-transactional-test-harness/src/aptos_test_harness.rs @@ -10,15 +10,14 @@ use aptos_crypto::{ ValidCryptoMaterialStringExt, }; use aptos_gas_schedule::{InitialGasSchedule, TransactionGasParameters}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_language_e2e_tests::data_store::{FakeDataStore, GENESIS_CHANGE_SET_HEAD}; use aptos_resource_viewer::{AnnotatedMoveValue, AptosValueAnnotator}; use aptos_types::{ account_config::{aptos_test_root_address, AccountResource, CoinStoreResource}, - block_executor::config::BlockExecutorConfigFromOnchain, block_metadata::BlockMetadata, chain_id::ChainId, contract_event::ContractEvent, - on_chain_config::BlockGasLimitType, state_store::{state_key::StateKey, table::TableHandle, TStateView}, transaction::{ signature_verified_transaction::into_signature_verified_block, @@ -515,17 +514,19 @@ impl<'a> AptosTestAdapter<'a> { /// Should error if the transaction ends up being discarded, or having a status other than /// EXECUTED. fn run_transaction(&mut self, txn: Transaction) -> Result { - let txn_block = vec![txn]; - let sig_verified_block = into_signature_verified_block(txn_block); - let onchain_config = BlockExecutorConfigFromOnchain { - // TODO fetch values from state? - // Or should we just use execute_block_no_limit ? - block_gas_limit_type: BlockGasLimitType::Limit(30000), - }; - let (mut outputs, _) = - AptosVM::execute_block(&sig_verified_block, &self.storage.clone(), onchain_config)? - .into_inner(); + let sig_verified_block = into_signature_verified_block(vec![txn]); + let state_view = self.storage.clone(); + + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&state_view, None)?; + let result = AptosVM::execute_block_no_limit( + &sig_verified_block, + &state_view, + &global_cache_manager, + ); + global_cache_manager.mark_block_execution_end(None)?; + let mut outputs = result?; assert_eq!(outputs.len(), 1); let output = outputs.pop().unwrap(); diff --git a/aptos-move/aptos-vm-environment/src/environment.rs b/aptos-move/aptos-vm-environment/src/environment.rs index 151dc19247ef92..8e7600ad39619e 100644 --- a/aptos-move/aptos-vm-environment/src/environment.rs +++ b/aptos-move/aptos-vm-environment/src/environment.rs @@ -15,7 +15,8 @@ use aptos_native_interface::SafeNativeBuilder; use aptos_types::{ chain_id::ChainId, on_chain_config::{ - ConfigurationResource, Features, OnChainConfig, TimedFeatures, TimedFeaturesBuilder, + ConfigurationResource, FeatureFlag, Features, OnChainConfig, TimedFeatures, + TimedFeaturesBuilder, }, state_store::StateView, }; @@ -175,8 +176,9 @@ impl Environment { ) -> Self { // We compute and store a hash of configs in order to distinguish different environments. let mut sha3_256 = Sha3_256::new(); - let features = + let mut features = fetch_config_and_update_hash::(&mut sha3_256, state_view).unwrap_or_default(); + features.enable(FeatureFlag::ENABLE_LOADER_V2); // If no chain ID is in storage, we assume we are in a testing environment. let chain_id = fetch_config_and_update_hash::(&mut sha3_256, state_view) diff --git a/aptos-move/aptos-vm-profiling/Cargo.toml b/aptos-move/aptos-vm-profiling/Cargo.toml index 68bfadfcd39eab..dcb4c5701e4c5d 100644 --- a/aptos-move/aptos-vm-profiling/Cargo.toml +++ b/aptos-move/aptos-vm-profiling/Cargo.toml @@ -19,6 +19,7 @@ smallvec = { workspace = true } aptos-cached-packages = { workspace = true } aptos-gas-schedule = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-language-e2e-tests = { workspace = true } aptos-move-stdlib = { workspace = true } aptos-native-interface = { workspace = true } diff --git a/aptos-move/aptos-vm-profiling/src/bins/run_aptos_p2p.rs b/aptos-move/aptos-vm-profiling/src/bins/run_aptos_p2p.rs index 1be873120f43f1..896f9726ca5e36 100644 --- a/aptos-move/aptos-vm-profiling/src/bins/run_aptos_p2p.rs +++ b/aptos-move/aptos-vm-profiling/src/bins/run_aptos_p2p.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use anyhow::Result; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_language_e2e_tests::{account::AccountData, data_store::FakeDataStore}; use aptos_types::{ transaction::{signature_verified_transaction::SignatureVerifiedTransaction, Transaction}, @@ -48,9 +49,17 @@ fn main() -> Result<()> { }) .collect(); - let res = AptosVM::execute_block_no_limit(&txns, &state_store)?; + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&state_store, None)?; + let result = AptosVM::execute_block_no_limit(&txns, &state_store, &global_cache_manager); + global_cache_manager.mark_block_execution_end(None)?; + for i in 0..NUM_TXNS { - assert!(res[i as usize].status().status().unwrap().is_success()); + assert!(result.as_ref().unwrap()[i as usize] + .status() + .status() + .unwrap() + .is_success()); } Ok(()) diff --git a/aptos-move/aptos-vm/Cargo.toml b/aptos-move/aptos-vm/Cargo.toml index a3458288716d27..abae28d9434ef3 100644 --- a/aptos-move/aptos-vm/Cargo.toml +++ b/aptos-move/aptos-vm/Cargo.toml @@ -24,6 +24,7 @@ aptos-framework = { workspace = true } aptos-gas-algebra = { workspace = true } aptos-gas-meter = { workspace = true } aptos-gas-schedule = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-infallible = { workspace = true } aptos-logger = { workspace = true } aptos-memory-usage-tracker = { workspace = true } diff --git a/aptos-move/aptos-vm/src/aptos_vm.rs b/aptos-move/aptos-vm/src/aptos_vm.rs index 798b1eadbb2c82..dc94e07a9650a3 100644 --- a/aptos-move/aptos-vm/src/aptos_vm.rs +++ b/aptos-move/aptos-vm/src/aptos_vm.rs @@ -36,6 +36,7 @@ use aptos_framework::{ use aptos_gas_algebra::{Gas, GasQuantity, NumBytes, Octa}; use aptos_gas_meter::{AptosGasMeter, GasAlgebra}; use aptos_gas_schedule::{AptosGasParameters, VMGasParameters}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_logger::{enabled, prelude::*, Level}; use aptos_metrics_core::TimerHelper; #[cfg(any(test, feature = "testing"))] @@ -2776,6 +2777,7 @@ impl VMExecutor for AptosVM { fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &(impl StateView + Sync), + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus> { fail_point!("move_adapter::execute_block", |_| { @@ -2798,6 +2800,7 @@ impl VMExecutor for AptosVM { >( transactions, state_view, + global_cache_manager, BlockExecutorConfig { local: BlockExecutorLocalConfig { concurrency_level: Self::get_concurrency_level(), diff --git a/aptos-move/aptos-vm/src/block_executor/mod.rs b/aptos-move/aptos-vm/src/block_executor/mod.rs index 29093463d0de83..76d60f3bd9881b 100644 --- a/aptos-move/aptos-vm/src/block_executor/mod.rs +++ b/aptos-move/aptos-vm/src/block_executor/mod.rs @@ -16,6 +16,7 @@ use aptos_block_executor::{ task::TransactionOutput as BlockExecutorTransactionOutput, txn_commit_hook::TransactionCommitHook, types::InputOutputKey, }; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_infallible::Mutex; use aptos_types::{ block_executor::config::BlockExecutorConfig, @@ -23,34 +24,27 @@ use aptos_types::{ error::PanicError, executable::ExecutableTestType, fee_statement::FeeStatement, - read_only_module_cache::ReadOnlyModuleCache, state_store::{state_key::StateKey, state_value::StateValueMetadata, StateView, StateViewId}, transaction::{ signature_verified_transaction::SignatureVerifiedTransaction, BlockOutput, TransactionOutput, TransactionStatus, }, - vm::modules::AptosModuleExtension, write_set::WriteOp, }; -use aptos_vm_environment::environment::AptosEnvironment; use aptos_vm_logging::{flush_speculative_logs, init_speculative_logs}; use aptos_vm_types::{ abstract_write_op::AbstractResourceWriteOp, module_write_set::ModuleWrite, output::VMOutput, resolver::ResourceGroupSize, }; -use move_binary_format::{errors::Location, CompiledModule}; use move_core_types::{ - language_storage::{ModuleId, StructTag}, + language_storage::StructTag, value::MoveTypeLayout, vm_status::{StatusCode, VMStatus}, }; -use move_vm_runtime::{Module, WithRuntimeEnvironment}; use move_vm_types::delayed_values::delayed_field_id::DelayedFieldID; use once_cell::sync::{Lazy, OnceCell}; use std::{ collections::{BTreeMap, HashSet}, - hash::Hash, - ops::Deref, sync::Arc, }; @@ -64,60 +58,6 @@ static RAYON_EXEC_POOL: Lazy> = Lazy::new(|| { ) }); -/// Immutable global module cache that can be shared across multiple block executions. The size of -/// the cache is fixed within a single block (modules are not inserted or removed) and it is only -/// mutated at the block boundaries. Do not use if multiple blocks are executed concurrently. -static GLOBAL_MODULE_CACHE: Lazy< - Arc>, -> = Lazy::new(|| Arc::new(ReadOnlyModuleCache::empty())); - -/// The maximum size of struct name index map in runtime environment. Checked at block boundaries -/// only. -const MAX_STRUCT_NAME_INDEX_MAP_SIZE: usize = 100_000; - -/// A cached environment that can be persisted globally across blocks. -static GLOBAL_ENVIRONMENT: Lazy>> = Lazy::new(|| Mutex::new(None)); - -/// Returns the cached environment if it exists and has the same configuration as if it was -/// created based on the current state, or creates a new one and caches it. Should only be -/// called at the block boundaries. -fn get_environment_with_delayed_field_optimization_enabled( - state_view: &impl StateView, - global_module_cache: &ReadOnlyModuleCache, -) -> Result -where - K: Hash + Eq + Clone, - VC: Deref>, -{ - // Create a new environment. - let current_env = AptosEnvironment::new_with_delayed_field_optimization_enabled(state_view); - - // Lock the cache, and check if the environment is the same. - let mut global_environment = GLOBAL_ENVIRONMENT.lock(); - if let Some(previous_env) = global_environment.as_ref() { - if ¤t_env == previous_env { - let runtime_env = previous_env.runtime_environment(); - let struct_name_index_map_size = runtime_env - .struct_name_index_map_size() - .map_err(|e| e.finish(Location::Undefined).into_vm_status())?; - if struct_name_index_map_size > MAX_STRUCT_NAME_INDEX_MAP_SIZE { - // Cache is too large, flush it. Also flush the module cache. - runtime_env.flush_struct_name_and_info_caches(); - global_module_cache.flush_unchecked(); - } - return Ok(previous_env.clone()); - } - } - - // It is not cached or has changed, so we have to reset it. As a result, we need to flush - // the cross-block cache because we need to reload all modules with new configs. - *global_environment = Some(current_env.clone()); - drop(global_environment); - global_module_cache.flush_unchecked(); - - Ok(current_env) -} - /// Output type wrapper used by block executor. VM output is stored first, then /// transformed into TransactionOutput type that is returned. #[derive(Debug)] @@ -456,9 +396,7 @@ impl BlockAptosVM { executor_thread_pool: Arc, signature_verified_block: &[SignatureVerifiedTransaction], state_view: &S, - global_module_cache: Arc< - ReadOnlyModuleCache, - >, + global_cache_manager: &GlobalCacheManager, config: BlockExecutorConfig, transaction_commit_listener: Option, ) -> Result, VMStatus> { @@ -472,11 +410,6 @@ impl BlockAptosVM { BLOCK_EXECUTOR_CONCURRENCY.set(config.local.concurrency_level as i64); - let environment = get_environment_with_delayed_field_optimization_enabled( - state_view, - global_module_cache.as_ref(), - )?; - let executor = BlockExecutor::< SignatureVerifiedTransaction, AptosExecutorTask, @@ -486,10 +419,11 @@ impl BlockAptosVM { >::new( config, executor_thread_pool, - global_module_cache, + global_cache_manager.module_cache(), transaction_commit_listener, ); + let environment = global_cache_manager.environment()?; let ret = executor.execute_block(environment, signature_verified_block, state_view); match ret { Ok(block_output) => { @@ -521,7 +455,7 @@ impl BlockAptosVM { } } - pub fn execute_block_on_thread_pool_without_global_module_cache< + pub fn execute_block_on_thread_pool_without_global_caches< S: StateView + Sync, L: TransactionCommitHook, >( @@ -531,23 +465,29 @@ impl BlockAptosVM { config: BlockExecutorConfig, transaction_commit_listener: Option, ) -> Result, VMStatus> { - Self::execute_block_on_thread_pool::( + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(state_view, None)?; + + let result = Self::execute_block_on_thread_pool::( executor_thread_pool, signature_verified_block, state_view, - Arc::new(ReadOnlyModuleCache::empty()), + &global_cache_manager, config, transaction_commit_listener, - ) + ); + global_cache_manager.mark_block_execution_end(None)?; + result } - /// Uses shared thread pool and shared global module cache to execute blocks. + /// Uses shared thread pool to execute blocks. pub fn execute_block< S: StateView + Sync, L: TransactionCommitHook, >( signature_verified_block: &[SignatureVerifiedTransaction], state_view: &S, + global_cache_manager: &GlobalCacheManager, config: BlockExecutorConfig, transaction_commit_listener: Option, ) -> Result, VMStatus> { @@ -555,52 +495,9 @@ impl BlockAptosVM { Arc::clone(&RAYON_EXEC_POOL), signature_verified_block, state_view, - Arc::clone(&GLOBAL_MODULE_CACHE), + global_cache_manager, config, transaction_commit_listener, ) } } - -#[cfg(test)] -mod test { - use super::*; - use aptos_language_e2e_tests::data_store::FakeDataStore; - use aptos_types::on_chain_config::{FeatureFlag, Features}; - use aptos_vm_environment::environment::AptosEnvironment; - use claims::assert_ok; - use move_vm_types::code::mock_verified_code; - - #[test] - fn test_cross_block_module_cache_flush() { - let global_module_cache = ReadOnlyModuleCache::empty(); - - global_module_cache.insert(0, mock_verified_code(0, None)); - assert_eq!(global_module_cache.size(), 1); - - global_module_cache.flush_unchecked(); - assert_eq!(global_module_cache.size(), 0); - - // Now check that cache is flushed when the environment is flushed. - let mut state_view = FakeDataStore::default(); - let env_old = AptosEnvironment::new_with_delayed_field_optimization_enabled(&state_view); - - for i in 0..10 { - global_module_cache.insert(i, mock_verified_code(i, None)); - } - assert_eq!(global_module_cache.size(), 10); - - let mut features = Features::default(); - features.disable(FeatureFlag::KEYLESS_ACCOUNTS); - state_view.set_features(features); - - // New environment means we need to also flush global caches - to invalidate struct name - // indices. - let env_new = assert_ok!(get_environment_with_delayed_field_optimization_enabled( - &state_view, - &global_module_cache, - )); - assert!(env_old != env_new); - assert_eq!(global_module_cache.size(), 0); - } -} diff --git a/aptos-move/aptos-vm/src/lib.rs b/aptos-move/aptos-vm/src/lib.rs index 61d665bb52e54c..14e1f7754e793b 100644 --- a/aptos-move/aptos-vm/src/lib.rs +++ b/aptos-move/aptos-vm/src/lib.rs @@ -126,6 +126,7 @@ pub mod verifier; pub use crate::aptos_vm::{AptosSimulationVM, AptosVM}; use crate::sharded_block_executor::{executor_client::ExecutorClient, ShardedBlockExecutor}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_types::{ block_executor::{ config::BlockExecutorConfigFromOnchain, partitioner::PartitionedTransactions, @@ -154,27 +155,25 @@ pub trait VMValidator { /// This trait describes the VM's execution interface. pub trait VMExecutor: Send + Sync { - // NOTE: At the moment there are no persistent caches that live past the end of a block (that's - // why execute_block doesn't take &self.) - // There are some cache invalidation issues around transactions publishing code that need to be - // sorted out before that's possible. - /// Executes a block of transactions and returns output for each one of them. fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &(impl StateView + Sync), + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus>; - /// Executes a block of transactions and returns output for each one of them, - /// Without applying any block limit + /// Executes a block of transactions and returns output for each one of them, without applying + /// any block limit. fn execute_block_no_limit( transactions: &[SignatureVerifiedTransaction], state_view: &(impl StateView + Sync), + global_cache_manager: &GlobalCacheManager, ) -> Result, VMStatus> { Self::execute_block( transactions, state_view, + global_cache_manager, BlockExecutorConfigFromOnchain::new_no_block_limit(), ) .map(BlockOutput::into_transaction_outputs_forced) diff --git a/aptos-move/aptos-vm/src/sharded_block_executor/sharded_executor_service.rs b/aptos-move/aptos-vm/src/sharded_block_executor/sharded_executor_service.rs index efe860c37103e4..5ad1dc5e602f61 100644 --- a/aptos-move/aptos-vm/src/sharded_block_executor/sharded_executor_service.rs +++ b/aptos-move/aptos-vm/src/sharded_block_executor/sharded_executor_service.rs @@ -135,7 +135,7 @@ impl ShardedExecutorService { ); }); s.spawn(move |_| { - let ret = BlockAptosVM::execute_block_on_thread_pool_without_global_module_cache( + let ret = BlockAptosVM::execute_block_on_thread_pool_without_global_caches( executor_thread_pool, &signature_verified_transactions, aggr_overridden_state_view.as_ref(), diff --git a/aptos-move/aptos-vm/tests/sharded_block_executor.rs b/aptos-move/aptos-vm/tests/sharded_block_executor.rs index a50834319851db..3973b653e38238 100644 --- a/aptos-move/aptos-vm/tests/sharded_block_executor.rs +++ b/aptos-move/aptos-vm/tests/sharded_block_executor.rs @@ -187,6 +187,7 @@ fn test_partitioner_v2_connected_component_sharded_block_executor_with_random_tr mod test_utils { use aptos_block_partitioner::BlockPartitioner; + use aptos_global_cache_manager::GlobalCacheManager; use aptos_language_e2e_tests::{ account::AccountData, common_transactions::peer_to_peer_txn, data_store::FakeDataStore, executor::FakeExecutor, @@ -307,8 +308,19 @@ mod test_utils { .into_iter() .map(|t| t.into_txn()) .collect(); - let unsharded_txn_output = - AptosVM::execute_block_no_limit(&ordered_txns, executor.data_store()).unwrap(); + + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(executor.data_store(), None) + .unwrap(); + let unsharded_txn_output = AptosVM::execute_block_no_limit( + &ordered_txns, + executor.data_store(), + &global_cache_manager, + ) + .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + compare_txn_outputs(unsharded_txn_output, sharded_txn_output); } @@ -356,9 +368,18 @@ mod test_utils { ) .unwrap(); - let unsharded_txn_output = - AptosVM::execute_block_no_limit(&execution_ordered_txns, executor.data_store()) - .unwrap(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(executor.data_store(), None) + .unwrap(); + let unsharded_txn_output = AptosVM::execute_block_no_limit( + &execution_ordered_txns, + executor.data_store(), + &global_cache_manager, + ) + .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + compare_txn_outputs(unsharded_txn_output, sharded_txn_output); } @@ -410,9 +431,18 @@ mod test_utils { ) .unwrap(); - let unsharded_txn_output = - AptosVM::execute_block_no_limit(&execution_ordered_txns, executor.data_store()) - .unwrap(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(executor.data_store(), None) + .unwrap(); + let unsharded_txn_output = AptosVM::execute_block_no_limit( + &execution_ordered_txns, + executor.data_store(), + &global_cache_manager, + ) + .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + compare_txn_outputs(unsharded_txn_output, sharded_txn_output); } } diff --git a/aptos-move/e2e-tests/src/executor.rs b/aptos-move/e2e-tests/src/executor.rs index 4c44a7e585c634..936b302ae76e82 100644 --- a/aptos-move/e2e-tests/src/executor.rs +++ b/aptos-move/e2e-tests/src/executor.rs @@ -636,7 +636,7 @@ impl FakeExecutor { }, onchain: onchain_config, }; - BlockAptosVM::execute_block_on_thread_pool_without_global_module_cache::< + BlockAptosVM::execute_block_on_thread_pool_without_global_caches::< _, NoOpTransactionCommitHook, >( diff --git a/execution/executor-benchmark/Cargo.toml b/execution/executor-benchmark/Cargo.toml index 4f99fe0a772683..6c572c0b7d3292 100644 --- a/execution/executor-benchmark/Cargo.toml +++ b/execution/executor-benchmark/Cargo.toml @@ -25,6 +25,7 @@ aptos-executor-types = { workspace = true } aptos-experimental-ptx-executor = { workspace = true } aptos-experimental-runtimes = { workspace = true } aptos-genesis = { workspace = true, features = ["testing"] } +aptos-global-cache-manager = { workspace = true } aptos-jellyfish-merkle = { workspace = true } aptos-logger = { workspace = true } aptos-metrics-core = { workspace = true } diff --git a/execution/executor-benchmark/src/native_executor.rs b/execution/executor-benchmark/src/native_executor.rs index 00b725936e1be7..5e2f0c2b7106d7 100644 --- a/execution/executor-benchmark/src/native_executor.rs +++ b/execution/executor-benchmark/src/native_executor.rs @@ -12,6 +12,7 @@ use aptos_executor::{ workflow::do_get_execution_output::DoGetExecutionOutput, }; use aptos_executor_types::execution_output::ExecutionOutput; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_storage_interface::cached_state_view::CachedStateView; use aptos_types::{ account_address::AccountAddress, @@ -361,6 +362,7 @@ impl VMExecutor for NativeExecutor { fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &(impl StateView + Sync), + _global_cache_manager: &GlobalCacheManager, _onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus> { let transaction_outputs = NATIVE_EXECUTOR_POOL @@ -452,12 +454,14 @@ impl TransactionBlockExecutor for NativeExecutor { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { DoGetExecutionOutput::by_transaction_execution::( transactions, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, ) diff --git a/execution/executor-service/Cargo.toml b/execution/executor-service/Cargo.toml index e590b54912c698..5d631700f1af29 100644 --- a/execution/executor-service/Cargo.toml +++ b/execution/executor-service/Cargo.toml @@ -15,6 +15,7 @@ rust-version = { workspace = true } [dependencies] aptos-block-partitioner = { workspace = true } aptos-config = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-infallible = { workspace = true } aptos-language-e2e-tests = { workspace = true } aptos-logger = { workspace = true } diff --git a/execution/executor-service/src/test_utils.rs b/execution/executor-service/src/test_utils.rs index 5a65075b74b4ae..74fc3d074d1a7e 100644 --- a/execution/executor-service/src/test_utils.rs +++ b/execution/executor-service/src/test_utils.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use aptos_block_partitioner::{v2::config::PartitionerV2Config, PartitionerConfig}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_language_e2e_tests::{ account::AccountData, common_transactions::peer_to_peer_txn, data_store::FakeDataStore, executor::FakeExecutor, @@ -136,8 +137,16 @@ pub fn test_sharded_block_executor_no_conflict> .into_iter() .map(|t| t.into_txn()) .collect(); + + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(executor.data_store(), None) + .unwrap(); let unsharded_txn_output = - AptosVM::execute_block_no_limit(&txns, executor.data_store()).unwrap(); + AptosVM::execute_block_no_limit(&txns, executor.data_store(), &global_cache_manager) + .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + compare_txn_outputs(unsharded_txn_output, sharded_txn_output); sharded_block_executor.shutdown(); } @@ -190,8 +199,18 @@ pub fn sharded_block_executor_with_conflict>( ) .unwrap(); - let unsharded_txn_output = - AptosVM::execute_block_no_limit(&execution_ordered_txns, executor.data_store()).unwrap(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(executor.data_store(), None) + .unwrap(); + let unsharded_txn_output = AptosVM::execute_block_no_limit( + &execution_ordered_txns, + executor.data_store(), + &global_cache_manager, + ) + .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + compare_txn_outputs(unsharded_txn_output, sharded_txn_output); sharded_block_executor.shutdown(); } diff --git a/execution/executor/Cargo.toml b/execution/executor/Cargo.toml index fcc3213c594bbe..3c433b3d582011 100644 --- a/execution/executor/Cargo.toml +++ b/execution/executor/Cargo.toml @@ -20,6 +20,7 @@ aptos-drop-helper = { workspace = true } aptos-executor-service = { workspace = true } aptos-executor-types = { workspace = true } aptos-experimental-runtimes = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-indexer-grpc-table-info = { workspace = true } aptos-infallible = { workspace = true } aptos-logger = { workspace = true } diff --git a/execution/executor/src/block_executor/mod.rs b/execution/executor/src/block_executor/mod.rs index 2ef3b126ce34f8..1d4fc122958cb8 100644 --- a/execution/executor/src/block_executor/mod.rs +++ b/execution/executor/src/block_executor/mod.rs @@ -23,6 +23,7 @@ use aptos_executor_types::{ BlockExecutorTrait, ExecutorError, ExecutorResult, }; use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_infallible::RwLock; use aptos_logger::prelude::*; use aptos_metrics_core::{IntGaugeHelper, TimerHelper}; @@ -48,6 +49,7 @@ pub trait TransactionBlockExecutor: Send + Sync { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result; @@ -57,12 +59,14 @@ impl TransactionBlockExecutor for AptosVM { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { DoGetExecutionOutput::by_transaction_execution::( transactions, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, ) @@ -176,6 +180,7 @@ where struct BlockExecutorInner { db: DbReaderWriter, block_tree: BlockTree, + global_cache_manager: GlobalCacheManager, phantom: PhantomData, } @@ -188,6 +193,7 @@ where Ok(Self { db, block_tree, + global_cache_manager: GlobalCacheManager::new(), phantom: PhantomData, }) } @@ -259,12 +265,34 @@ where "Injected error in vm_execute_block" ))) }); - V::execute_transaction_block( + + self.global_cache_manager + .mark_block_execution_start(&state_view, Some(parent_block_id)) + .map_err(|err| { + error!( + "Unexpected error for block {:?} when starting block execution: {:?}", + block_id, err + ); + ExecutorError::internal_err(format!("{err:?}")) + })?; + let result = V::execute_transaction_block( transactions, state_view, + &self.global_cache_manager, onchain_config.clone(), Some(block_id), - )? + ); + self.global_cache_manager + .mark_block_execution_end(Some(block_id)) + .map_err(|err| { + error!( + "Unexpected error for block {:?} when ending block execution: {:?}", + block_id, err + ); + ExecutorError::internal_err(format!("{err:?}")) + })?; + + result? }; let _timer = OTHER_TIMERS.timer_with(&["state_checkpoint"]); diff --git a/execution/executor/src/chunk_executor/mod.rs b/execution/executor/src/chunk_executor/mod.rs index c489131b44c699..22cf75c3249ccf 100644 --- a/execution/executor/src/chunk_executor/mod.rs +++ b/execution/executor/src/chunk_executor/mod.rs @@ -20,6 +20,7 @@ use aptos_executor_types::{ ChunkCommitNotification, ChunkExecutorTrait, TransactionReplayer, VerifyExecutionMode, }; use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_infallible::{Mutex, RwLock}; use aptos_logger::prelude::*; use aptos_metrics_core::{IntGaugeHelper, TimerHelper}; @@ -597,13 +598,21 @@ impl ChunkExecutorInner { .map(|t| t.into()) .collect::>(); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&state_view, None)?; + // State sync executor shouldn't have block gas limit. - let execution_output = DoGetExecutionOutput::by_transaction_execution::( + let result = DoGetExecutionOutput::by_transaction_execution::( txns.into(), state_view, + &global_cache_manager, BlockExecutorConfigFromOnchain::new_no_block_limit(), None, - )?; + ); + + global_cache_manager.mark_block_execution_end(None)?; + let execution_output = result?; + // not `zip_eq`, deliberately for (version, txn_out, txn_info, write_set, events) in multizip(( begin_version..end_version, diff --git a/execution/executor/src/chunk_executor/transaction_chunk.rs b/execution/executor/src/chunk_executor/transaction_chunk.rs index 1e3533a0b94914..af7baa73163349 100644 --- a/execution/executor/src/chunk_executor/transaction_chunk.rs +++ b/execution/executor/src/chunk_executor/transaction_chunk.rs @@ -8,6 +8,7 @@ use crate::{ use anyhow::Result; use aptos_executor_types::execution_output::ExecutionOutput; use aptos_experimental_runtimes::thread_manager::optimal_min_len; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_metrics_core::TimerHelper; use aptos_storage_interface::cached_state_view::CachedStateView; use aptos_types::{ @@ -76,13 +77,21 @@ impl TransactionChunk for ChunkToExecute { }) }; - let _timer = VM_EXECUTE_CHUNK.start_timer(); - DoGetExecutionOutput::by_transaction_execution::( + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&state_view, None)?; + + let timer = VM_EXECUTE_CHUNK.start_timer(); + let result = DoGetExecutionOutput::by_transaction_execution::( sig_verified_txns.into(), state_view, + &global_cache_manager, BlockExecutorConfigFromOnchain::new_no_block_limit(), None, - ) + ); + drop(timer); + + global_cache_manager.mark_block_execution_end(None)?; + result } } diff --git a/execution/executor/src/db_bootstrapper/mod.rs b/execution/executor/src/db_bootstrapper/mod.rs index dcf1b04690c0f5..6ceb4d42d62a1d 100644 --- a/execution/executor/src/db_bootstrapper/mod.rs +++ b/execution/executor/src/db_bootstrapper/mod.rs @@ -10,6 +10,7 @@ use crate::{ }; use anyhow::{anyhow, ensure, format_err, Result}; use aptos_crypto::HashValue; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_logger::prelude::*; use aptos_storage_interface::{ async_proof_fetcher::AsyncProofFetcher, cached_state_view::CachedStateView, DbReaderWriter, @@ -131,12 +132,19 @@ pub fn calculate_genesis( get_state_epoch(&base_state_view)? }; - let execution_output = DoGetExecutionOutput::by_transaction_execution::( + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&base_state_view, None)?; + + let result = DoGetExecutionOutput::by_transaction_execution::( vec![genesis_txn.clone().into()].into(), base_state_view, + &global_cache_manager, BlockExecutorConfigFromOnchain::new_no_block_limit(), None, - )?; + ); + global_cache_manager.mark_block_execution_end(None)?; + + let execution_output = result?; ensure!( execution_output.num_transactions_to_commit() != 0, "Genesis txn execution failed." diff --git a/execution/executor/src/fuzzing.rs b/execution/executor/src/fuzzing.rs index 0430a7706d4425..38b588482f9513 100644 --- a/execution/executor/src/fuzzing.rs +++ b/execution/executor/src/fuzzing.rs @@ -9,6 +9,7 @@ use crate::{ use anyhow::Result; use aptos_crypto::{hash::SPARSE_MERKLE_PLACEHOLDER_HASH, HashValue}; use aptos_executor_types::{execution_output::ExecutionOutput, BlockExecutorTrait}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_storage_interface::{ cached_state_view::CachedStateView, chunk_to_commit::ChunkToCommit, DbReader, DbReaderWriter, DbWriter, @@ -71,12 +72,14 @@ impl TransactionBlockExecutor for FakeVM { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { DoGetExecutionOutput::by_transaction_execution::( transactions, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, ) @@ -96,6 +99,7 @@ impl VMExecutor for FakeVM { fn execute_block( _transactions: &[SignatureVerifiedTransaction], _state_view: &impl StateView, + _global_cache_manager: &GlobalCacheManager, _onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus> { Ok(BlockOutput::new(vec![], None)) diff --git a/execution/executor/src/tests/mock_vm/mock_vm_test.rs b/execution/executor/src/tests/mock_vm/mock_vm_test.rs index 3e54400c4c8660..40eab7a972f142 100644 --- a/execution/executor/src/tests/mock_vm/mock_vm_test.rs +++ b/execution/executor/src/tests/mock_vm/mock_vm_test.rs @@ -3,6 +3,7 @@ // SPDX-License-Identifier: Apache-2.0 use super::{balance_ap, encode_mint_transaction, encode_transfer_transaction, seqnum_ap, MockVM}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_types::{ account_address::AccountAddress, bytes::NumToBytes, @@ -42,11 +43,17 @@ fn test_mock_vm_different_senders() { txns.push(encode_mint_transaction(gen_address(i), amount)); } + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(&MockStateView, None) + .unwrap(); let outputs = MockVM::execute_block_no_limit( &into_signature_verified_block(txns.clone()), &MockStateView, + &global_cache_manager, ) .expect("MockVM should not fail to start"); + global_cache_manager.mark_block_execution_end(None).unwrap(); for (output, txn) in itertools::zip_eq(outputs.iter(), txns.iter()) { let sender = txn.try_as_signed_user_txn().unwrap().sender(); @@ -81,9 +88,17 @@ fn test_mock_vm_same_sender() { txns.push(encode_mint_transaction(sender, amount)); } - let outputs = - MockVM::execute_block_no_limit(&into_signature_verified_block(txns), &MockStateView) - .expect("MockVM should not fail to start"); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(&MockStateView, None) + .unwrap(); + let outputs = MockVM::execute_block_no_limit( + &into_signature_verified_block(txns), + &MockStateView, + &global_cache_manager, + ) + .expect("MockVM should not fail to start"); + global_cache_manager.mark_block_execution_end(None).unwrap(); for (i, output) in outputs.iter().enumerate() { assert_eq!( @@ -116,9 +131,17 @@ fn test_mock_vm_payment() { encode_transfer_transaction(gen_address(0), gen_address(1), 50), ]; - let output = - MockVM::execute_block_no_limit(&into_signature_verified_block(txns), &MockStateView) - .expect("MockVM should not fail to start"); + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager + .mark_block_execution_start(&MockStateView, None) + .unwrap(); + let output = MockVM::execute_block_no_limit( + &into_signature_verified_block(txns), + &MockStateView, + &global_cache_manager, + ) + .expect("MockVM should not fail to start"); + global_cache_manager.mark_block_execution_end(None).unwrap(); let mut output_iter = output.iter(); output_iter.next(); diff --git a/execution/executor/src/tests/mock_vm/mod.rs b/execution/executor/src/tests/mock_vm/mod.rs index 4bfc0a525c99dc..c0a17fe190def0 100644 --- a/execution/executor/src/tests/mock_vm/mod.rs +++ b/execution/executor/src/tests/mock_vm/mod.rs @@ -12,6 +12,7 @@ use crate::{ use anyhow::Result; use aptos_crypto::{ed25519::Ed25519PrivateKey, HashValue, PrivateKey, Uniform}; use aptos_executor_types::execution_output::ExecutionOutput; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_storage_interface::cached_state_view::CachedStateView; use aptos_types::{ account_address::AccountAddress, @@ -69,12 +70,14 @@ impl TransactionBlockExecutor for MockVM { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { DoGetExecutionOutput::by_transaction_execution::( transactions, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, ) @@ -85,6 +88,7 @@ impl VMExecutor for MockVM { fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &impl StateView, + _global_cache_manager: &GlobalCacheManager, _onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus> { // output_cache is used to store the output of transactions so they are visible to later diff --git a/execution/executor/src/tests/mod.rs b/execution/executor/src/tests/mod.rs index e57d7e67582ae8..4de8f0707330ee 100644 --- a/execution/executor/src/tests/mod.rs +++ b/execution/executor/src/tests/mod.rs @@ -12,6 +12,7 @@ use aptos_db::AptosDB; use aptos_executor_types::{ BlockExecutorTrait, ChunkExecutorTrait, TransactionReplayer, VerifyExecutionMode, }; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_storage_interface::{ async_proof_fetcher::AsyncProofFetcher, DbReaderWriter, ExecutedTrees, Result, }; @@ -674,22 +675,31 @@ fn run_transactions_naive( ) -> HashValue { let executor = TestExecutor::new(); let db = &executor.db; + let global_cache_manager = GlobalCacheManager::new(); for txn in transactions { let ledger_view: ExecutedTrees = db.reader.get_latest_executed_trees().unwrap(); + let state_view = ledger_view + .verified_state_view( + StateViewId::Miscellaneous, + Arc::clone(&db.reader), + Arc::new(AsyncProofFetcher::new(db.reader.clone())), + ) + .unwrap(); + + global_cache_manager + .mark_block_execution_start(&state_view, None) + .unwrap(); let out = DoGetExecutionOutput::by_transaction_execution::( vec![txn].into(), - ledger_view - .verified_state_view( - StateViewId::Miscellaneous, - Arc::clone(&db.reader), - Arc::new(AsyncProofFetcher::new(db.reader.clone())), - ) - .unwrap(), + state_view, + &global_cache_manager, block_executor_onchain_config.clone(), None, ) .unwrap(); + global_cache_manager.mark_block_execution_end(None).unwrap(); + let output = ApplyExecutionOutput::run(out, &ledger_view).unwrap(); db.writer .save_transactions( diff --git a/execution/executor/src/workflow/do_get_execution_output.rs b/execution/executor/src/workflow/do_get_execution_output.rs index c2c34a0d4e0f78..fbdfc83064cc90 100644 --- a/execution/executor/src/workflow/do_get_execution_output.rs +++ b/execution/executor/src/workflow/do_get_execution_output.rs @@ -16,6 +16,7 @@ use aptos_executor_types::{ transactions_with_output::TransactionsWithOutput, }; use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_logger::prelude::*; use aptos_metrics_core::TimerHelper; use aptos_storage_interface::cached_state_view::{CachedStateView, StateCache}; @@ -47,6 +48,7 @@ impl DoGetExecutionOutput { pub fn by_transaction_execution( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { @@ -55,6 +57,7 @@ impl DoGetExecutionOutput { Self::by_transaction_execution_unsharded::( txns, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, )? @@ -85,10 +88,16 @@ impl DoGetExecutionOutput { fn by_transaction_execution_unsharded( transactions: Vec, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> Result { - let block_output = Self::execute_block::(&transactions, &state_view, onchain_config)?; + let block_output = Self::execute_block::( + &transactions, + &state_view, + global_cache_manager, + onchain_config, + )?; let (transaction_outputs, block_end_info) = block_output.into_inner(); Parser::parse( @@ -196,20 +205,27 @@ impl DoGetExecutionOutput { fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, ) -> Result> { let _timer = OTHER_TIMERS.timer_with(&["vm_execute_block"]); - Ok(V::execute_block(transactions, state_view, onchain_config)?) + Ok(V::execute_block( + transactions, + state_view, + global_cache_manager, + onchain_config, + )?) } /// In consensus-only mode, executes the block of [Transaction]s using the - /// [VMExecutor] only if its a genesis block. In all other cases, this + /// [VMExecutor] only if it is a genesis block. In all other cases, this /// method returns an [TransactionOutput] with an empty [WriteSet], constant /// gas and a [ExecutionStatus::Success] for each of the [Transaction]s. #[cfg(feature = "consensus-only-perf-test")] fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, ) -> Result> { use aptos_types::{ @@ -220,9 +236,12 @@ impl DoGetExecutionOutput { let transaction_outputs = match state_view.id() { // this state view ID implies a genesis block in non-test cases. - StateViewId::Miscellaneous => { - V::execute_block(transactions, state_view, onchain_config)? - }, + StateViewId::Miscellaneous => V::execute_block( + transactions, + state_view, + global_cache_manager, + onchain_config, + )?, _ => BlockOutput::new( transactions .iter() diff --git a/experimental/execution/ptx-executor/Cargo.toml b/experimental/execution/ptx-executor/Cargo.toml index b7dc674ee3fe17..acfae5c2c0b2ff 100644 --- a/experimental/execution/ptx-executor/Cargo.toml +++ b/experimental/execution/ptx-executor/Cargo.toml @@ -18,6 +18,7 @@ aptos-crypto = { workspace = true } aptos-executor = { workspace = true } aptos-executor-types = { workspace = true } aptos-experimental-runtimes = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-infallible = { workspace = true } aptos-logger = { workspace = true } aptos-metrics-core = { workspace = true } diff --git a/experimental/execution/ptx-executor/src/lib.rs b/experimental/execution/ptx-executor/src/lib.rs index 84172a4f86f088..ac6f46805f7ab7 100644 --- a/experimental/execution/ptx-executor/src/lib.rs +++ b/experimental/execution/ptx-executor/src/lib.rs @@ -28,6 +28,7 @@ use aptos_executor::{ }; use aptos_executor_types::execution_output::ExecutionOutput; use aptos_experimental_runtimes::thread_manager::THREAD_MANAGER; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_infallible::Mutex; use aptos_metrics_core::TimerHelper; use aptos_storage_interface::cached_state_view::CachedStateView; @@ -55,6 +56,7 @@ impl VMExecutor for PtxBlockExecutor { fn execute_block( transactions: &[SignatureVerifiedTransaction], state_view: &(impl StateView + Sync), + _global_cache_manager: &GlobalCacheManager, _onchain_config: BlockExecutorConfigFromOnchain, ) -> Result, VMStatus> { let _timer = TIMER.timer_with(&["block_total"]); @@ -121,12 +123,14 @@ impl TransactionBlockExecutor for PtxBlockExecutor { fn execute_transaction_block( transactions: ExecutableTransactions, state_view: CachedStateView, + global_cache_manager: &GlobalCacheManager, onchain_config: BlockExecutorConfigFromOnchain, append_state_checkpoint_to_block: Option, ) -> anyhow::Result { DoGetExecutionOutput::by_transaction_execution::( transactions, state_view, + global_cache_manager, onchain_config, append_state_checkpoint_to_block, ) diff --git a/storage/db-tool/Cargo.toml b/storage/db-tool/Cargo.toml index b2feeb952750dc..0f9f772776d003 100644 --- a/storage/db-tool/Cargo.toml +++ b/storage/db-tool/Cargo.toml @@ -18,6 +18,7 @@ aptos-config = { workspace = true } aptos-db = { workspace = true, features = ["db-debugger"] } aptos-executor = { workspace = true } aptos-executor-types = { workspace = true } +aptos-global-cache-manager = { workspace = true } aptos-logger = { workspace = true } aptos-storage-interface = { workspace = true } aptos-temppath = { workspace = true } diff --git a/storage/db-tool/src/replay_on_archive.rs b/storage/db-tool/src/replay_on_archive.rs index 0b87bf8f91e1c5..54aef27cb1336e 100644 --- a/storage/db-tool/src/replay_on_archive.rs +++ b/storage/db-tool/src/replay_on_archive.rs @@ -9,6 +9,7 @@ use aptos_config::config::{ NO_OP_STORAGE_PRUNER_CONFIG, }; use aptos_db::{backup::backup_handler::BackupHandler, AptosDB}; +use aptos_global_cache_manager::GlobalCacheManager; use aptos_logger::{error, info}; use aptos_storage_interface::{state_view::DbStateViewAtVersion, AptosDbError, DbReader}; use aptos_types::{ @@ -29,6 +30,7 @@ use std::{ sync::{atomic::AtomicU64, Arc}, time::Instant, }; + // Replay Verify controller is responsible for providing legit range with start and end versions. #[derive(Parser)] pub struct Opt { @@ -270,17 +272,25 @@ impl Verifier { expected_epoch_events: &Vec>, expected_epoch_writesets: &Vec, ) -> Result> { - let executed_outputs = AptosVM::execute_block_no_limit( + let state_view = self + .arc_db + .state_view_at_version(start_version.checked_sub(1))?; + + // Currently, we do not cache modules across different chunks. + let global_cache_manager = GlobalCacheManager::new(); + global_cache_manager.mark_block_execution_start(&state_view, None)?; + let result = AptosVM::execute_block_no_limit( cur_txns .iter() .map(|txn| SignatureVerifiedTransaction::from(txn.clone())) .collect::>() .as_slice(), - &self - .arc_db - .state_view_at_version(start_version.checked_sub(1))?, - )?; + &state_view, + &global_cache_manager, + ); + global_cache_manager.mark_block_execution_end(None)?; + let executed_outputs = result?; let mut failed_txns = Vec::new(); let mut version = start_version; for (idx, (expected_txn_info, expected_events, expected_writeset, executed_output)) in diff --git a/types/src/on_chain_config/aptos_features.rs b/types/src/on_chain_config/aptos_features.rs index b5e6bfe0ea3f85..3f08d5ae468d5f 100644 --- a/types/src/on_chain_config/aptos_features.rs +++ b/types/src/on_chain_config/aptos_features.rs @@ -195,6 +195,9 @@ impl Default for Features { for feature in FeatureFlag::default_features() { features.enable(feature); } + + features.enable(FeatureFlag::ENABLE_LOADER_V2); + features } } diff --git a/types/src/read_only_module_cache.rs b/types/src/read_only_module_cache.rs index c6b18615e945b8..bb7feb0d76132d 100644 --- a/types/src/read_only_module_cache.rs +++ b/types/src/read_only_module_cache.rs @@ -70,9 +70,6 @@ where pub struct ReadOnlyModuleCache { /// Module cache containing the verified code. module_cache: ExplicitSyncWrapper>>, - /// Maximum cache size. If the size is greater than this limit, the cache is flushed. Note that - /// this can only be done at block boundaries. - capacity: usize, } impl ReadOnlyModuleCache @@ -80,17 +77,10 @@ where K: Hash + Eq + Clone, VC: Deref>, { - /// Returns new empty module cache with default capacity. + /// Returns new empty module cache. pub fn empty() -> Self { - let default_capacity = 100_000; - Self::with_capacity(default_capacity) - } - - /// Returns new empty module cache with specified capacity. - fn with_capacity(capacity: usize) -> Self { Self { module_cache: ExplicitSyncWrapper::new(HashMap::new()), - capacity, } } @@ -136,8 +126,6 @@ where /// 2. Versions of inserted modules are set to [None] (storage version). /// 3. Valid modules should not be removed, and new modules should have unique ownership. If /// these constraints are violated, a panic error is returned. - /// 4. If the cache size exceeds its capacity after all verified modules have been inserted, - /// the cache is flushed. pub fn insert_verified_unchecked( &self, modules: impl Iterator>>)>, @@ -168,11 +156,6 @@ where assert!(prev.is_none()) } } - - if module_cache.len() > self.capacity { - module_cache.clear(); - } - Ok(()) } @@ -241,27 +224,23 @@ mod test { #[test] fn test_insert_verified_for_read_only_module_cache() { - let capacity = 10; - let global_cache = ReadOnlyModuleCache::with_capacity(capacity); + let global_cache = ReadOnlyModuleCache::empty(); let mut new_modules = vec![]; - for i in 0..capacity { + for i in 0..10 { new_modules.push((i, mock_verified_code(i, Some(i as u32)))); } let result = global_cache.insert_verified_unchecked(new_modules.into_iter()); assert!(result.is_ok()); - assert_eq!(global_cache.size(), capacity); + assert_eq!(global_cache.size(), 10); // Versions should be set to storage. - for key in 0..capacity { + for key in 0..10 { let code = assert_some!(global_cache.get(&key)); assert!(code.version().is_none()) } - // Too many modules added, the cache should be flushed. - let new_modules = vec![(11, mock_verified_code(11, None))]; - let result = global_cache.insert_verified_unchecked(new_modules.into_iter()); - assert!(result.is_ok()); + global_cache.flush_unchecked(); assert_eq!(global_cache.size(), 0); // Should not add deserialized code.