From d78bb497e4cd14d8f79c587b60792851dfad046b Mon Sep 17 00:00:00 2001 From: Victor Gao Date: Mon, 26 Jun 2023 23:24:05 +0000 Subject: [PATCH 1/4] [gas] abstract gas algebra part 1 -- instructions & operations --- Cargo.lock | 2 + aptos-move/aptos-debugger/src/lib.rs | 17 +- .../aptos-gas-profiling/src/profiler.rs | 53 +- aptos-move/aptos-gas/Cargo.toml | 2 + aptos-move/aptos-gas/src/abstract_algebra.rs | 359 ++++++++++ aptos-move/aptos-gas/src/gas_meter.rs | 666 +++++++++++------- aptos-move/aptos-gas/src/instr.rs | 67 +- aptos-move/aptos-gas/src/lib.rs | 7 +- aptos-move/aptos-gas/src/misc.rs | 1 + aptos-move/aptos-gas/src/params.rs | 61 +- aptos-move/aptos-gas/src/transaction/mod.rs | 31 +- .../aptos-gas/src/transaction/storage.rs | 76 +- .../aptos-memory-usage-tracker/src/lib.rs | 29 +- aptos-move/aptos-vm/src/aptos_vm.rs | 46 +- aptos-move/aptos-vm/src/aptos_vm_impl.rs | 8 +- .../src/account_universe/bad_transaction.rs | 11 +- aptos-move/e2e-tests/src/executor.rs | 17 +- .../src/tests/failed_transaction_tests.rs | 7 +- .../move/move-core/types/src/gas_algebra.rs | 12 + 19 files changed, 1004 insertions(+), 468 deletions(-) create mode 100644 aptos-move/aptos-gas/src/abstract_algebra.rs diff --git a/Cargo.lock b/Cargo.lock index 04e8f76c7264c..5ed1cef2bf5af 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1540,11 +1540,13 @@ dependencies = [ "aptos-vm-types", "bcs 0.1.4", "clap 4.3.5", + "either", "move-binary-format", "move-core-types", "move-model", "move-table-extension", "move-vm-types", + "paste", "tempfile", ] diff --git a/aptos-move/aptos-debugger/src/lib.rs b/aptos-move/aptos-debugger/src/lib.rs index 7fbd9a6517922..028d9c6791319 100644 --- a/aptos-move/aptos-debugger/src/lib.rs +++ b/aptos-move/aptos-debugger/src/lib.rs @@ -3,8 +3,8 @@ use anyhow::{format_err, Result}; use aptos_gas::{ - AbstractValueSizeGasParameters, ChangeSetConfigs, NativeGasParameters, StandardGasMeter, - LATEST_GAS_FEATURE_VERSION, + AbstractValueSizeGasParameters, ChangeSetConfigs, NativeGasParameters, StandardGasAlgebra, + StandardGasMeter, LATEST_GAS_FEATURE_VERSION, }; use aptos_gas_profiling::{GasProfiler, TransactionGasLog}; use aptos_memory_usage_tracker::MemoryTrackedGasMeter; @@ -80,12 +80,13 @@ impl AptosDebugger { &txn, &log_context, |gas_feature_version, gas_params, storage_gas_params, balance| { - let gas_meter = MemoryTrackedGasMeter::new(StandardGasMeter::new( - gas_feature_version, - gas_params, - storage_gas_params, - balance, - )); + let gas_meter = + MemoryTrackedGasMeter::new(StandardGasMeter::new(StandardGasAlgebra::new( + gas_feature_version, + gas_params, + storage_gas_params, + balance, + ))); let gas_profiler = match txn.payload() { TransactionPayload::Script(_) => GasProfiler::new_script(gas_meter), TransactionPayload::EntryFunction(entry_func) => GasProfiler::new_function( diff --git a/aptos-move/aptos-gas-profiling/src/profiler.rs b/aptos-move/aptos-gas-profiling/src/profiler.rs index c0ec30250ef9a..b13a6cdabee5e 100644 --- a/aptos-move/aptos-gas-profiling/src/profiler.rs +++ b/aptos-move/aptos-gas-profiling/src/profiler.rs @@ -5,7 +5,7 @@ use crate::log::{ CallFrame, EventStorage, ExecutionAndIOCosts, ExecutionGasEvent, FrameName, StorageFees, TransactionGasLog, WriteOpType, WriteStorage, WriteTransient, }; -use aptos_gas::{AptosGasMeter, AptosGasParameters, Fee, Gas, GasScalingFactor}; +use aptos_gas::{AptosGasMeter, Fee}; use aptos_types::{ contract_event::ContractEvent, state_store::state_key::StateKey, write_set::WriteOp, }; @@ -474,16 +474,10 @@ impl AptosGasMeter for GasProfiler where G: AptosGasMeter, { - delegate! { - fn feature_version(&self) -> u64; - - fn gas_params(&self) -> &AptosGasParameters; - - fn balance(&self) -> Gas; + type Algebra = G::Algebra; - fn gas_unit_scaling_factor(&self) -> GasScalingFactor; - - fn io_gas_per_write(&self, key: &StateKey, op: &WriteOp) -> InternalGas; + delegate! { + fn algebra(&self) -> &Self::Algebra; fn storage_fee_per_write(&self, key: &StateKey, op: &WriteOp) -> Fee; @@ -492,20 +486,10 @@ where fn storage_discount_for_events(&self, total_cost: Fee) -> Fee; fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee; - - fn execution_gas_used(&self) -> Gas; - - fn io_gas_used(&self) -> Gas; - - fn storage_fee_used_in_gas_units(&self) -> Gas; - - fn storage_fee_used(&self) -> Fee; } delegate_mut! { - fn charge_execution(&mut self, amount: InternalGas) -> PartialVMResult<()>; - - fn charge_io(&mut self, amount: InternalGas) -> PartialVMResult<()>; + fn algebra_mut(&mut self) -> &mut Self::Algebra; fn charge_storage_fee( &mut self, @@ -514,22 +498,17 @@ where ) -> PartialVMResult<()>; } - fn charge_io_gas_for_write_set<'a>( - &mut self, - ops: impl IntoIterator, - ) -> VMResult<()> { - for (key, op) in ops { - let cost = self.io_gas_per_write(key, op); - self.total_exec_io += cost; - self.write_set_transient.push(WriteTransient { - key: key.clone(), - cost, - op_type: write_op_type(op), - }); - self.charge_io(cost) - .map_err(|e| e.finish(Location::Undefined))?; - } - Ok(()) + fn charge_io_gas_for_write(&mut self, key: &StateKey, op: &WriteOp) -> VMResult<()> { + let (cost, res) = self.delegate_charge(|base| base.charge_io_gas_for_write(key, op)); + + self.total_exec_io += cost; + self.write_set_transient.push(WriteTransient { + key: key.clone(), + cost, + op_type: write_op_type(op), + }); + + res } fn charge_storage_fee_for_all<'a>( diff --git a/aptos-move/aptos-gas/Cargo.toml b/aptos-move/aptos-gas/Cargo.toml index 1747b41664da9..f58f07037a36a 100644 --- a/aptos-move/aptos-gas/Cargo.toml +++ b/aptos-move/aptos-gas/Cargo.toml @@ -24,11 +24,13 @@ aptos-types = { workspace = true } aptos-vm-types = { workspace = true } bcs = { workspace = true } clap = { workspace = true } +either = { workspace = true } move-binary-format = { workspace = true } move-core-types = { workspace = true } move-model = { workspace = true } move-table-extension = { workspace = true } move-vm-types = { workspace = true } +paste = { workspace = true } [dev-dependencies] tempfile = { workspace = true } diff --git a/aptos-move/aptos-gas/src/abstract_algebra.rs b/aptos-move/aptos-gas/src/abstract_algebra.rs new file mode 100644 index 0000000000000..bff698ba7f5fe --- /dev/null +++ b/aptos-move/aptos-gas/src/abstract_algebra.rs @@ -0,0 +1,359 @@ +use crate::{AptosGasParameters, Fee, FeePerGasUnit, Octa, StorageGasParameters}; +use either::Either; +use move_binary_format::errors::PartialVMResult; +use move_core_types::gas_algebra::{GasQuantity, InternalGas, InternalGasUnit}; +use std::ops::{Add, Mul}; + +pub trait GasExpressionVisitor { + fn add(&mut self); + + fn mul(&mut self); + + fn gas_param

(&mut self); + + fn quantity(&mut self, quantity: GasQuantity); +} + +/// Abstraction over a gas expression. +pub trait GasExpression { + type Unit; + + fn materialize( + &self, + feature_version: u64, + gas_params: &AptosGasParameters, + ) -> GasQuantity; + + fn visit(&self, visitor: &mut impl GasExpressionVisitor); +} + +pub trait GasAlgebra { + fn feature_version(&self) -> u64; + + fn gas_params(&self) -> &AptosGasParameters; + + fn storage_gas_params(&self) -> &StorageGasParameters; + + fn balance_internal(&self) -> InternalGas; + + fn charge_execution( + &mut self, + abstract_amount: impl GasExpression, + ) -> PartialVMResult<()>; + + fn charge_io( + &mut self, + abstract_amount: impl GasExpression, + ) -> PartialVMResult<()>; + + fn charge_storage_fee( + &mut self, + abstract_amount: impl GasExpression, + gas_unit_price: FeePerGasUnit, + ) -> PartialVMResult<()>; + + fn execution_gas_used(&self) -> InternalGas; + + fn io_gas_used(&self) -> InternalGas; + + fn storage_fee_used_in_gas_units(&self) -> InternalGas; + + fn storage_fee_used(&self) -> Fee; +} + +pub struct GasAdd { + pub left: L, + pub right: R, +} + +pub struct GasMul { + pub left: L, + pub right: R, +} + +pub struct GasOptional { + pub predicate: F, + pub exp: E, +} + +impl GasExpression for GasAdd +where + L: GasExpression, + R: GasExpression, +{ + type Unit = U; + + #[inline] + fn materialize( + &self, + feature_version: u64, + gas_params: &AptosGasParameters, + ) -> GasQuantity { + self.left.materialize(feature_version, gas_params) + + self.right.materialize(feature_version, gas_params) + } + + #[inline] + fn visit(&self, visitor: &mut impl GasExpressionVisitor) { + self.left.visit(visitor); + self.right.visit(visitor); + visitor.add(); + } +} + +impl GasExpression for GasMul +where + L: GasExpression, + R: GasExpression, + GasQuantity