diff --git a/aptos-move/aptos-vm/src/block_executor/mod.rs b/aptos-move/aptos-vm/src/block_executor/mod.rs index de16c676676b69..25d5d97d7d5234 100644 --- a/aptos-move/aptos-vm/src/block_executor/mod.rs +++ b/aptos-move/aptos-vm/src/block_executor/mod.rs @@ -127,7 +127,7 @@ pub struct AptosTransactionOutput { } impl AptosTransactionOutput { - pub(crate) fn new(output: VMOutput) -> Self { + pub fn new(output: VMOutput) -> Self { Self { vm_output: Mutex::new(Some(output)), committed_output: OnceCell::new(), @@ -138,7 +138,7 @@ impl AptosTransactionOutput { self.committed_output.get().unwrap() } - fn take_output(mut self) -> TransactionOutput { + pub fn take_output(mut self) -> TransactionOutput { match self.committed_output.take() { Some(output) => output, // TODO: revisit whether we should always get it via committed, or o.w. create a diff --git a/aptos-move/framework/aptos-framework/doc/fungible_asset.md b/aptos-move/framework/aptos-framework/doc/fungible_asset.md index a7fd696d9d8fe8..17ee3056667dad 100644 --- a/aptos-move/framework/aptos-framework/doc/fungible_asset.md +++ b/aptos-move/framework/aptos-framework/doc/fungible_asset.md @@ -3468,25 +3468,23 @@ Decrease the supply of a fungible asset by burning. }; let metadata_address = object::object_address(metadata); - if (amount == 0) { - if (exists<ConcurrentSupply>(metadata_address)) { - let supply = borrow_global_mut<ConcurrentSupply>(metadata_address); + if (exists<ConcurrentSupply>(metadata_address)) { + let supply = borrow_global_mut<ConcurrentSupply>(metadata_address); - assert!( - aggregator_v2::try_sub(&mut supply.current, (amount as u128)), - error::out_of_range(ESUPPLY_UNDERFLOW) - ); - } else if (exists<Supply>(metadata_address)) { - assert!(exists<Supply>(metadata_address), error::not_found(ESUPPLY_NOT_FOUND)); - let supply = borrow_global_mut<Supply>(metadata_address); - assert!( - supply.current >= (amount as u128), - error::invalid_state(ESUPPLY_UNDERFLOW) - ); - supply.current = supply.current - (amount as u128); - } else { - assert!(false, error::not_found(ESUPPLY_NOT_FOUND)); - } + assert!( + aggregator_v2::try_sub(&mut supply.current, (amount as u128)), + error::out_of_range(ESUPPLY_UNDERFLOW) + ); + } else if (exists<Supply>(metadata_address)) { + assert!(exists<Supply>(metadata_address), error::not_found(ESUPPLY_NOT_FOUND)); + let supply = borrow_global_mut<Supply>(metadata_address); + assert!( + supply.current >= (amount as u128), + error::invalid_state(ESUPPLY_UNDERFLOW) + ); + supply.current = supply.current - (amount as u128); + } else { + assert!(false, error::not_found(ESUPPLY_NOT_FOUND)); } } diff --git a/execution/executor-benchmark/src/db_access.rs b/execution/executor-benchmark/src/db_access.rs index 5a475bcfc0509c..ec645db4fab900 100644 --- a/execution/executor-benchmark/src/db_access.rs +++ b/execution/executor-benchmark/src/db_access.rs @@ -6,13 +6,14 @@ use aptos_types::{ account_address::AccountAddress, account_config::{ AccountResource, CoinInfoResource, CoinStoreResource, ConcurrentSupplyResource, - FungibleStoreResource, ObjectCoreResource, ObjectGroupResource, + FungibleStoreResource, ObjectCoreResource, ObjectGroupResource, TypeInfoResource, }, event::{EventHandle, EventKey}, state_store::{state_key::StateKey, StateView}, write_set::TOTAL_SUPPLY_STATE_KEY, AptosCoinType, CoinType, }; +use itertools::Itertools; use move_core_types::{ identifier::Identifier, language_storage::{StructTag, TypeTag}, @@ -168,4 +169,28 @@ impl DbAccessUtil { pub fn new_object_core(address: AccountAddress, owner: AccountAddress) -> ObjectCoreResource { ObjectCoreResource::new(owner, false, EventHandle::new(EventKey::new(1, address), 0)) } + + pub fn new_type_info_resource() -> anyhow::Result { + let struct_tag = T::struct_tag(); + Ok(TypeInfoResource { + account_address: struct_tag.address, + module_name: bcs::to_bytes(&struct_tag.module.to_string())?, + struct_name: bcs::to_bytes( + &if struct_tag.type_args.is_empty() { + struct_tag.name.to_string() + } else { + format!( + "{}<{}>", + struct_tag.name, + struct_tag + .type_args + .iter() + .map(|v| v.to_string()) + .join(", ") + ) + .to_string() + }, + )?, + }) + } } diff --git a/execution/executor-benchmark/src/lib.rs b/execution/executor-benchmark/src/lib.rs index 8a6285424c38ee..c4892381ba4780 100644 --- a/execution/executor-benchmark/src/lib.rs +++ b/execution/executor-benchmark/src/lib.rs @@ -907,7 +907,7 @@ mod tests { }; let other_db = init_db(&config); - let other_executor = BlockExecutor::::new(other_db.clone()); + let other_executor = BlockExecutor::::new(other_db.clone()); let parent_block_id = other_executor.committed_block_id(); let block_id = HashValue::random(); diff --git a/execution/executor-benchmark/src/native/native_vm.rs b/execution/executor-benchmark/src/native/native_vm.rs index 7264af09085099..7d032db683a5c9 100644 --- a/execution/executor-benchmark/src/native/native_vm.rs +++ b/execution/executor-benchmark/src/native/native_vm.rs @@ -28,7 +28,7 @@ use aptos_types::{ account_config::{ primary_apt_store, AccountResource, CoinDeposit, CoinInfoResource, CoinRegister, CoinStoreResource, CoinWithdraw, ConcurrentSupplyResource, DepositFAEvent, - FungibleStoreResource, TypeInfoResource, WithdrawFAEvent, + FungibleStoreResource, WithdrawFAEvent, }, block_executor::config::{ BlockExecutorConfig, BlockExecutorConfigFromOnchain, BlockExecutorLocalConfig, @@ -825,7 +825,7 @@ impl NativeVMExecutorTask { events.push(( CoinRegister { account: AccountAddress::ONE, - type_info: TypeInfoResource::new::() + type_info: DbAccessUtil::new_type_info_resource::() .map_err(hide_error)?, } .create_event_v2(), diff --git a/execution/executor-benchmark/src/native/parallel_uncoordinated_block_executor.rs b/execution/executor-benchmark/src/native/parallel_uncoordinated_block_executor.rs index dc8198844c5db1..585539a51d36f0 100644 --- a/execution/executor-benchmark/src/native/parallel_uncoordinated_block_executor.rs +++ b/execution/executor-benchmark/src/native/parallel_uncoordinated_block_executor.rs @@ -13,7 +13,7 @@ use aptos_types::{ account_config::{ primary_apt_store, AccountResource, CoinDeposit, CoinInfoResource, CoinRegister, CoinStoreResource, CoinWithdraw, ConcurrentSupplyResource, DepositFAEvent, - FungibleStoreResource, TypeInfoResource, WithdrawFAEvent, + FungibleStoreResource, WithdrawFAEvent, }, block_executor::config::BlockExecutorConfigFromOnchain, contract_event::ContractEvent, @@ -30,14 +30,12 @@ use aptos_types::{ AptosCoinType, }; use aptos_vm::VMBlockExecutor; -use dashmap::{mapref::one::RefMut, DashMap}; +use dashmap::{mapref::one::{Ref, RefMut}, DashMap}; use once_cell::sync::OnceCell; use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator}; +use thread_local::ThreadLocal; use std::{ - collections::{BTreeMap, HashMap}, - hash::RandomState, - sync::atomic::{AtomicU64, Ordering}, - u64, + cell::Cell, collections::{BTreeMap, HashMap}, hash::RandomState, sync::atomic::{AtomicU64, Ordering}, u64 }; /// Executes transactions fully, and produces TransactionOutput (with final WriteSet) @@ -697,7 +695,7 @@ impl CommonNativeRawTransactionExecutor for NativeRawTransactionExecutor { output.events.push( CoinRegister { account: AccountAddress::ONE, - type_info: TypeInfoResource::new::()?, + type_info: DbAccessUtil::new_type_info_resource::()?, } .create_event_v2(), ); @@ -789,8 +787,15 @@ fn compute_deltas_for_batch( deltas } +const USE_THREAD_LOCAL_SUPPLY: bool = true; + struct CoinSupply { - total_supply: u128, + pub total_supply: u128, +} + +struct SupplyWithDecrement { + pub base: u128, + pub decrement: ThreadLocal>, } enum CachedResource { @@ -800,6 +805,7 @@ enum CachedResource { AptCoinStore(CoinStoreResource), AptCoinInfo(CoinInfoResource), AptCoinSupply(CoinSupply), + SupplyDecrement(SupplyWithDecrement), } pub struct NativeValueCacheRawTransactionExecutor { @@ -876,37 +882,37 @@ impl CommonNativeRawTransactionExecutor for NativeValueCacheRawTransactionExecut state_view: &(impl StateView + Sync), _output: &mut IncrementalOutput, ) -> Result<()> { - let concurrent_supply_rg_tag = &self.db_util.common.concurrent_supply; - let cache_key = StateKey::resource(&AccountAddress::TEN, concurrent_supply_rg_tag).unwrap(); - - let mut entry = self.cache.entry(cache_key).or_insert_with(|| { - let apt_metadata_object_state_key = self - .db_util - .new_state_key_object_resource_group(&AccountAddress::TEN); - - let mut apt_metadata_object = - DbAccessUtil::get_resource_group(&apt_metadata_object_state_key, state_view) - .unwrap() - .unwrap(); - - CachedResource::FungibleSupply( - bcs::from_bytes::( - &apt_metadata_object - .remove(concurrent_supply_rg_tag) - .unwrap(), - ) - .unwrap(), - ) - }); - - match entry.value_mut() { - CachedResource::FungibleSupply(fungible_supply) => { - fungible_supply - .current - .set(fungible_supply.current.get() - gas as u128); - }, - _ => panic!("wrong type"), - }; + let cache_key = StateKey::resource(&AccountAddress::TEN, &self.db_util.common.concurrent_supply).unwrap(); + + if USE_THREAD_LOCAL_SUPPLY { + let entry = self.cache_get_or_init(&cache_key, |_key| { + let concurrent_supply = self.fetch_concurrent_supply(state_view); + CachedResource::SupplyDecrement(SupplyWithDecrement { + base: *concurrent_supply.current.get(), + decrement: ThreadLocal::new(), + }) + }); + match entry.value() { + CachedResource::SupplyDecrement(SupplyWithDecrement { decrement, .. }) => { + let decrement_cell = decrement.get_or_default(); + decrement_cell.set(decrement_cell.get() + gas as u128); + }, + _ => panic!("wrong type"), + } + } else { + let mut entry = self.cache_get_mut_or_init(&cache_key, |_key| { + let concurrent_supply = self.fetch_concurrent_supply(state_view); + CachedResource::FungibleSupply(concurrent_supply) + }); + match entry.value_mut() { + CachedResource::FungibleSupply(fungible_supply) => { + fungible_supply + .current + .set(fungible_supply.current.get() - gas as u128); + }, + _ => panic!("wrong type"), + }; + } Ok(()) } @@ -934,20 +940,40 @@ impl CommonNativeRawTransactionExecutor for NativeValueCacheRawTransactionExecut total_supply_state_key }); - let mut total_supply_entry = self.cache_get_mut_or_init(total_supply_state_key, |key| { - CachedResource::AptCoinSupply(CoinSupply { - total_supply: DbAccessUtil::get_value::(key, state_view) - .unwrap() - .unwrap(), - }) - }); + if USE_THREAD_LOCAL_SUPPLY { + let total_supply_entry = self.cache_get_or_init(total_supply_state_key, |key| { + CachedResource::SupplyDecrement(SupplyWithDecrement { + base: DbAccessUtil::get_value::(key, state_view) + .unwrap() + .unwrap(), + decrement: ThreadLocal::new() + }) + }); + match total_supply_entry.value() { + CachedResource::SupplyDecrement(SupplyWithDecrement { decrement, .. }) => { + let decrement_cell = decrement.get_or_default(); + decrement_cell.set(decrement_cell.get() + gas as u128); + }, + _ => panic!("wrong type"), + } + } else { + let mut total_supply_entry = self.cache_get_mut_or_init(total_supply_state_key, |key| { + CachedResource::AptCoinSupply(CoinSupply { + total_supply: DbAccessUtil::get_value::(key, state_view) + .unwrap() + .unwrap(), + }) + }); + + match total_supply_entry.value_mut() { + CachedResource::AptCoinSupply(coin_supply) => { + coin_supply.total_supply -= gas as u128; + }, + _ => panic!("wrong type"), + }; + } + - match total_supply_entry.value_mut() { - CachedResource::AptCoinSupply(coin_supply) => { - coin_supply.total_supply -= gas as u128; - }, - _ => panic!("wrong type"), - }; Ok(()) } @@ -1003,6 +1029,19 @@ impl CommonNativeRawTransactionExecutor for NativeValueCacheRawTransactionExecut } impl NativeValueCacheRawTransactionExecutor { + fn cache_get_or_init<'a>( + &'a self, + key: &StateKey, + init_value: impl FnOnce(&StateKey) -> CachedResource, + ) -> Ref<'a, StateKey, CachedResource, RandomState> { + // Data in cache is going to be the hot path, so short-circuit here to avoid cloning the key. + if let Some(ref_mut) = self.cache.get(key) { + return ref_mut; + } + + self.cache.entry(key.clone()).or_insert(init_value(key)).downgrade() + } + fn cache_get_mut_or_init<'a>( &'a self, key: &StateKey, @@ -1016,6 +1055,27 @@ impl NativeValueCacheRawTransactionExecutor { self.cache.entry(key.clone()).or_insert(init_value(key)) } + fn fetch_concurrent_supply(&self, state_view: &(impl StateView + Sync)) -> ConcurrentSupplyResource { + let concurrent_supply_rg_tag = &self.db_util.common.concurrent_supply; + + let apt_metadata_object_state_key = self + .db_util + .new_state_key_object_resource_group(&AccountAddress::TEN); + + let mut apt_metadata_object = + DbAccessUtil::get_resource_group(&apt_metadata_object_state_key, state_view) + .unwrap() + .unwrap(); + + let concurrent_supply = bcs::from_bytes::( + &apt_metadata_object + .remove(concurrent_supply_rg_tag) + .unwrap(), + ) + .unwrap(); + concurrent_supply + } + fn update_fa_balance( &self, account: AccountAddress, @@ -1094,6 +1154,7 @@ impl NativeValueCacheRawTransactionExecutor { pub struct NativeNoStorageRawTransactionExecutor { seq_nums: DashMap, balances: DashMap, + total_supply_decrement: ThreadLocal>, total_supply: AtomicU64, } @@ -1186,6 +1247,7 @@ impl RawTransactionExecutor for NativeNoStorageRawTransactionExecutor { Self { seq_nums: DashMap::new(), balances: DashMap::new(), + total_supply_decrement: ThreadLocal::new(), total_supply: AtomicU64::new(u64::MAX), } } @@ -1200,7 +1262,13 @@ impl RawTransactionExecutor for NativeNoStorageRawTransactionExecutor { ) -> Result { let gas_units = 4; let gas = gas_units * 100; - self.total_supply.fetch_sub(gas, Ordering::Relaxed); + + if USE_THREAD_LOCAL_SUPPLY { + let decrement_cell = self.total_supply_decrement.get_or_default(); + decrement_cell.set(decrement_cell.get() + gas as u128); + } else { + self.total_supply.fetch_sub(gas, Ordering::Relaxed); + } let output = IncrementalOutput::new(); let (sender, sequence_number) = match txn { @@ -1244,7 +1312,6 @@ impl RawTransactionExecutor for NativeNoStorageRawTransactionExecutor { amounts, .. } => { - let mut deltas = compute_deltas_for_batch(recipients, amounts, sender); let amount_from_sender = -deltas.remove(&sender).unwrap_or(0); @@ -1266,7 +1333,6 @@ impl RawTransactionExecutor for NativeNoStorageRawTransactionExecutor { }; self.seq_nums.insert(sender, sequence_number); - account.sequence_number = sequence_number + 1; output.into_success_output(gas) } } diff --git a/types/src/lib.rs b/types/src/lib.rs index 95d59f1232060c..9081b6c0f0a4d0 100644 --- a/types/src/lib.rs +++ b/types/src/lib.rs @@ -25,7 +25,6 @@ pub mod jwks; pub mod ledger_info; pub mod mempool_status; pub mod move_any; -pub mod move_event_v2; pub mod move_fixed_point; pub mod move_utils; pub mod network_address; diff --git a/types/src/move_event_v2.rs b/types/src/move_event_v2.rs deleted file mode 100644 index bd6b2c2cd6de22..00000000000000 --- a/types/src/move_event_v2.rs +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright © Aptos Foundation -// SPDX-License-Identifier: Apache-2.0 - -use crate::contract_event::ContractEvent; -use move_core_types::{language_storage::TypeTag, move_resource::MoveStructType}; -use serde::Serialize; - -pub trait MoveEventV2: MoveStructType + Serialize { - fn create_event_v2(&self) -> ContractEvent { - ContractEvent::new_v2( - TypeTag::Struct(Box::new(Self::struct_tag())), - bcs::to_bytes(self).unwrap(), - ) - } -}