From 1b28cd6a1e2970f93db78bfafebc3d176ca1587d Mon Sep 17 00:00:00 2001 From: aldenhu Date: Fri, 8 Dec 2023 18:09:36 +0000 Subject: [PATCH] DiskSpacePricing --- .../aptos-abstract-gas-usage/src/algebra.rs | 6 +- aptos-move/aptos-gas-meter/src/algebra.rs | 8 +- aptos-move/aptos-gas-meter/src/meter.rs | 34 +---- aptos-move/aptos-gas-meter/src/traits.rs | 71 +++------ .../aptos-gas-profiling/src/profiler.rs | 48 ++---- .../src/gas_schedule/transaction.rs | 48 ------ .../aptos-memory-usage-tracker/src/lib.rs | 15 +- .../aptos-vm-types/src/abstract_write_op.rs | 5 +- .../aptos-vm-types/src/storage/io_pricing.rs | 4 +- aptos-move/aptos-vm-types/src/storage/mod.rs | 6 + .../src/storage/space_pricing.rs | 142 ++++++++++++++++++ types/src/write_set.rs | 17 +-- 12 files changed, 208 insertions(+), 196 deletions(-) create mode 100644 aptos-move/aptos-vm-types/src/storage/space_pricing.rs diff --git a/aptos-move/aptos-abstract-gas-usage/src/algebra.rs b/aptos-move/aptos-abstract-gas-usage/src/algebra.rs index c07768fec594a..b5ae2a0b0586b 100644 --- a/aptos-move/aptos-abstract-gas-usage/src/algebra.rs +++ b/aptos-move/aptos-abstract-gas-usage/src/algebra.rs @@ -6,7 +6,7 @@ use aptos_gas_algebra::{ }; use aptos_gas_meter::GasAlgebra; use aptos_gas_schedule::VMGasParameters; -use aptos_vm_types::storage::io_pricing::IoPricing; +use aptos_vm_types::storage::{io_pricing::IoPricing, space_pricing::DiskSpacePricing}; use move_binary_format::errors::PartialVMResult; use std::sync::{Arc, Mutex}; @@ -33,6 +33,10 @@ impl GasAlgebra for CalibrationAlgebra { self.base.io_pricing() } + fn disk_space_pricing(&self) -> &DiskSpacePricing { + self.base.disk_space_pricing() + } + fn balance_internal(&self) -> InternalGas { self.base.balance_internal() } diff --git a/aptos-move/aptos-gas-meter/src/algebra.rs b/aptos-move/aptos-gas-meter/src/algebra.rs index c33efe971b041..ad5085ea07bf1 100644 --- a/aptos-move/aptos-gas-meter/src/algebra.rs +++ b/aptos-move/aptos-gas-meter/src/algebra.rs @@ -5,7 +5,9 @@ use crate::traits::GasAlgebra; use aptos_gas_algebra::{Fee, FeePerGasUnit, Gas, GasExpression, Octa}; use aptos_gas_schedule::VMGasParameters; use aptos_logger::error; -use aptos_vm_types::storage::{io_pricing::IoPricing, StorageGasParameters}; +use aptos_vm_types::storage::{ + io_pricing::IoPricing, space_pricing::DiskSpacePricing, StorageGasParameters, +}; use move_binary_format::errors::{PartialVMError, PartialVMResult}; use move_core_types::{ gas_algebra::{InternalGas, InternalGasUnit}, @@ -87,6 +89,10 @@ impl GasAlgebra for StandardGasAlgebra { &self.storage_gas_params.io_pricing } + fn disk_space_pricing(&self) -> &DiskSpacePricing { + &self.storage_gas_params.space_pricing + } + fn balance_internal(&self) -> InternalGas { self.balance } diff --git a/aptos-move/aptos-gas-meter/src/meter.rs b/aptos-move/aptos-gas-meter/src/meter.rs index f55e38bf8dfd4..4dbf4f25d0856 100644 --- a/aptos-move/aptos-gas-meter/src/meter.rs +++ b/aptos-move/aptos-gas-meter/src/meter.rs @@ -4,9 +4,7 @@ use crate::traits::{AptosGasMeter, GasAlgebra}; use aptos_gas_algebra::{Fee, FeePerGasUnit}; use aptos_gas_schedule::gas_params::{instr::*, txn::*}; -use aptos_types::{ - contract_event::ContractEvent, state_store::state_key::StateKey, write_set::WriteOpSize, -}; +use aptos_types::{state_store::state_key::StateKey, write_set::WriteOpSize}; use move_binary_format::{ errors::{Location, PartialVMError, PartialVMResult, VMResult}, file_format::CodeOffset, @@ -495,36 +493,6 @@ where .map_err(|e| e.finish(Location::Undefined)) } - fn storage_fee_for_state_slot(&self, op_size: &WriteOpSize) -> Fee { - self.vm_gas_params().txn.storage_fee_for_slot(op_size) - } - - fn storage_fee_refund_for_state_slot(&self, op_size: &WriteOpSize) -> Fee { - self.vm_gas_params() - .txn - .storage_fee_refund_for_slot(op_size) - } - - fn storage_fee_for_state_bytes(&self, key: &StateKey, op_size: &WriteOpSize) -> Fee { - self.vm_gas_params().txn.storage_fee_for_bytes(key, op_size) - } - - fn storage_fee_per_event(&self, event: &ContractEvent) -> Fee { - self.vm_gas_params().txn.storage_fee_per_event(event) - } - - fn storage_discount_for_events(&self, total_cost: Fee) -> Fee { - self.vm_gas_params() - .txn - .storage_discount_for_events(total_cost) - } - - fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee { - self.vm_gas_params() - .txn - .storage_fee_for_transaction_storage(txn_size) - } - fn charge_intrinsic_gas_for_transaction(&mut self, txn_size: NumBytes) -> VMResult<()> { let excess = txn_size .checked_sub(self.vm_gas_params().txn.large_transaction_cutoff) diff --git a/aptos-move/aptos-gas-meter/src/traits.rs b/aptos-move/aptos-gas-meter/src/traits.rs index 1526f93d0d638..3068b3b939d9a 100644 --- a/aptos-move/aptos-gas-meter/src/traits.rs +++ b/aptos-move/aptos-gas-meter/src/traits.rs @@ -3,12 +3,14 @@ use aptos_gas_algebra::{Fee, FeePerGasUnit, Gas, GasExpression, GasScalingFactor, Octa}; use aptos_gas_schedule::VMGasParameters; -use aptos_types::{ - contract_event::ContractEvent, - state_store::{state_key::StateKey, state_value::StateValueMetadata}, - write_set::WriteOpSize, +use aptos_types::{state_store::state_key::StateKey, write_set::WriteOpSize}; +use aptos_vm_types::{ + change_set::VMChangeSet, + storage::{ + io_pricing::IoPricing, + space_pricing::{ChargeAndRefund, DiskSpacePricing}, + }, }; -use aptos_vm_types::{change_set::VMChangeSet, storage::io_pricing::IoPricing}; use move_binary_format::errors::{Location, PartialVMResult, VMResult}; use move_core_types::gas_algebra::{InternalGas, InternalGasUnit, NumBytes}; use move_vm_types::gas::GasMeter as MoveGasMeter; @@ -26,6 +28,9 @@ pub trait GasAlgebra { /// Returns the struct containing the storage-specific gas parameters. fn io_pricing(&self) -> &IoPricing; + /// Returns the disk space pricing strategy. + fn disk_space_pricing(&self) -> &DiskSpacePricing; + /// Returns the current balance, measured in internal gas units. fn balance_internal(&self) -> InternalGas; @@ -108,24 +113,6 @@ pub trait AptosGasMeter: MoveGasMeter { /// storage costs. fn charge_io_gas_for_write(&mut self, key: &StateKey, op: &WriteOpSize) -> VMResult<()>; - /// Calculates the storage fee for a state slot allocation. - fn storage_fee_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - /// Calculates the storage fee refund for a state slot deallocation. - fn storage_fee_refund_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - /// Calculates the storage fee for state byte. - fn storage_fee_for_state_bytes(&self, key: &StateKey, op: &WriteOpSize) -> Fee; - - /// Calculates the storage fee for an event. - fn storage_fee_per_event(&self, event: &ContractEvent) -> Fee; - - /// Calculates the discount applied to the event storage fees, based on a free quota. - fn storage_discount_for_events(&self, total_cost: Fee) -> Fee; - - /// Calculates the storage fee for the transaction. - fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee; - /// Charges the storage fees for writes, events & txn storage in a lump sum, minimizing the /// loss of precision. Refundable portion of the charge is recorded on the WriteOp itself, /// due to which mutable references are required on the parameter list wherever proper. @@ -152,31 +139,31 @@ pub trait AptosGasMeter: MoveGasMeter { return Ok(0.into()); } + let pricing = self.disk_space_pricing(); + let params = &self.vm_gas_params().txn; + // Calculate the storage fees. let mut write_fee = Fee::new(0); let mut total_refund = Fee::new(0); - for (key, op_size, op_creation_metadata) in change_set.write_set_iter_mut() { - let slot_fee = self.storage_fee_for_state_slot(&op_size); - let refund = self.storage_fee_refund_for_state_slot(&op_size); - let bytes_fee = self.storage_fee_for_state_bytes(key, &op_size); - - Self::maybe_record_storage_deposit(op_creation_metadata, slot_fee); + for (key, op_size, metadata_opt) in change_set.write_set_iter_mut() { + let ChargeAndRefund { charge, refund } = + pricing.charge_refund_write_op(params, key, &op_size, metadata_opt); total_refund += refund; - write_fee += slot_fee + bytes_fee; + write_fee += charge; } let event_fee = change_set .events() .iter() .fold(Fee::new(0), |acc, (event, _)| { - acc + self.storage_fee_per_event(event) + acc + pricing.storage_fee_per_event(params, event) }); - let event_discount = self.storage_discount_for_events(event_fee); + let event_discount = pricing.storage_discount_for_events(params, event_fee); let event_net_fee = event_fee .checked_sub(event_discount) .expect("discount should always be less than or equal to total amount"); - let txn_fee = self.storage_fee_for_transaction_storage(txn_size); + let txn_fee = pricing.storage_fee_for_transaction_storage(params, txn_size); let fee = write_fee + event_net_fee + txn_fee; self.charge_storage_fee(fee, gas_unit_price) @@ -185,19 +172,6 @@ pub trait AptosGasMeter: MoveGasMeter { Ok(total_refund) } - // The slot fee is refundable, we record it on the WriteOp itself and it'll end up in - // the state DB. - fn maybe_record_storage_deposit( - creation_metadata: Option<&mut StateValueMetadata>, - slot_fee: Fee, - ) { - if !slot_fee.is_zero() { - if let Some(metadata) = creation_metadata { - metadata.set_deposit(slot_fee.into()) - } - } - } - // Below are getters reexported from the gas algebra. // Gas meter instances should not reimplement these themselves. @@ -216,6 +190,11 @@ pub trait AptosGasMeter: MoveGasMeter { self.algebra().io_pricing() } + /// Returns the disk space pricing strategy. + fn disk_space_pricing(&self) -> &DiskSpacePricing { + self.algebra().disk_space_pricing() + } + /// Returns the remaining balance, measured in (external) gas units. /// /// The number should be rounded down when converting from internal to external gas units. diff --git a/aptos-move/aptos-gas-profiling/src/profiler.rs b/aptos-move/aptos-gas-profiling/src/profiler.rs index 46d7f03810b0e..cd87cd74b601f 100644 --- a/aptos-move/aptos-gas-profiling/src/profiler.rs +++ b/aptos-move/aptos-gas-profiling/src/profiler.rs @@ -7,10 +7,8 @@ use crate::log::{ }; use aptos_gas_algebra::{Fee, FeePerGasUnit, InternalGas, NumArgs, NumBytes}; use aptos_gas_meter::AptosGasMeter; -use aptos_types::{ - contract_event::ContractEvent, state_store::state_key::StateKey, write_set::WriteOpSize, -}; -use aptos_vm_types::change_set::VMChangeSet; +use aptos_types::{state_store::state_key::StateKey, write_set::WriteOpSize}; +use aptos_vm_types::{change_set::VMChangeSet, storage::space_pricing::ChargeAndRefund}; use move_binary_format::{ errors::{Location, PartialVMResult, VMResult}, file_format::CodeOffset, @@ -467,7 +465,7 @@ fn write_op_type(op: &WriteOpSize) -> WriteOpType { match op { O::Creation { .. } => T::Creation, O::Modification { .. } => T::Modification, - O::Deletion | O::DeletionWithDeposit { .. } => T::Deletion, + O::Deletion => T::Deletion, } } @@ -479,18 +477,6 @@ where delegate! { fn algebra(&self) -> &Self::Algebra; - - fn storage_fee_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - fn storage_fee_refund_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - fn storage_fee_for_state_bytes(&self, key: &StateKey, op: &WriteOpSize) -> Fee; - - fn storage_fee_per_event(&self, event: &ContractEvent) -> Fee; - - fn storage_discount_for_events(&self, total_cost: Fee) -> Fee; - - fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee; } delegate_mut! { @@ -534,47 +520,45 @@ where return Ok(0.into()); } + let pricing = self.disk_space_pricing(); + let params = &self.vm_gas_params().txn; + // Writes let mut write_fee = Fee::new(0); let mut write_set_storage = vec![]; let mut total_refund = Fee::new(0); - for (key, op_size, op_creation_metadata) in change_set.write_set_iter_mut() { - let slot_fee = self.storage_fee_for_state_slot(&op_size); - let slot_refund = self.storage_fee_refund_for_state_slot(&op_size); - let bytes_fee = self.storage_fee_for_state_bytes(key, &op_size); + for (key, op_size, metadata_opt) in change_set.write_set_iter_mut() { + let ChargeAndRefund { charge, refund } = + pricing.charge_refund_write_op(params, key, &op_size, metadata_opt); + write_fee += charge; + total_refund += refund; - Self::maybe_record_storage_deposit(op_creation_metadata, slot_fee); - total_refund += slot_refund; - - let fee = slot_fee + bytes_fee; write_set_storage.push(WriteStorage { key: key.clone(), op_type: write_op_type(&op_size), - cost: fee, - refund: slot_refund, + cost: charge, + refund, }); - // TODO(gas): track storage refund in the profiler - write_fee += fee; } // Events let mut event_fee = Fee::new(0); let mut event_fees = vec![]; for (event, _) in change_set.events().iter() { - let fee = self.storage_fee_per_event(event); + let fee = pricing.storage_fee_per_event(params, event); event_fees.push(EventStorage { ty: event.type_tag().clone(), cost: fee, }); event_fee += fee; } - let event_discount = self.storage_discount_for_events(event_fee); + let event_discount = pricing.storage_discount_for_events(params, event_fee); let event_fee_with_discount = event_fee .checked_sub(event_discount) .expect("discount should always be less than or equal to total amount"); // Txn - let txn_fee = self.storage_fee_for_transaction_storage(txn_size); + let txn_fee = pricing.storage_fee_for_transaction_storage(params, txn_size); self.storage_fees = Some(StorageFees { total: write_fee + event_fee + txn_fee, diff --git a/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs b/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs index f7206c4f42471..356f28513fdc9 100644 --- a/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs +++ b/aptos-move/aptos-gas-schedule/src/gas_schedule/transaction.rs @@ -9,9 +9,6 @@ use aptos_gas_algebra::{ AbstractValueSize, Fee, FeePerByte, FeePerGasUnit, FeePerSlot, Gas, GasExpression, GasScalingFactor, GasUnit, NumSlots, }; -use aptos_types::{ - contract_event::ContractEvent, state_store::state_key::StateKey, write_set::WriteOpSize, -}; use move_core_types::gas_algebra::{ InternalGas, InternalGasPerArg, InternalGasPerByte, InternalGasUnit, NumBytes, ToUnitWithParams, }; @@ -201,51 +198,6 @@ impl TransactionGasParameters { } } - pub fn storage_fee_for_slot(&self, op_size: &WriteOpSize) -> Fee { - use WriteOpSize::*; - - match op_size { - Creation { .. } => self.storage_fee_per_state_slot_create * NumSlots::new(1), - Modification { .. } | Deletion | DeletionWithDeposit { .. } => 0.into(), - } - } - - pub fn storage_fee_refund_for_slot(&self, op_size: &WriteOpSize) -> Fee { - op_size.deletion_deposit().map_or(0.into(), Fee::new) - } - - /// Maybe value size is None for deletion Ops. - pub fn storage_fee_for_bytes(&self, key: &StateKey, op_size: &WriteOpSize) -> Fee { - if let Some(value_size) = op_size.write_len() { - let size = NumBytes::new(key.size() as u64) + NumBytes::new(value_size); - if let Some(excess) = size.checked_sub(self.legacy_free_write_bytes_quota) { - return excess * self.storage_fee_per_excess_state_byte; - } - } - - 0.into() - } - - /// New formula to charge storage fee for an event, measured in APT. - pub fn storage_fee_per_event(&self, event: &ContractEvent) -> Fee { - NumBytes::new(event.size() as u64) * self.storage_fee_per_event_byte - } - - pub fn storage_discount_for_events(&self, total_cost: Fee) -> Fee { - std::cmp::min( - total_cost, - self.free_event_bytes_quota * self.storage_fee_per_event_byte, - ) - } - - /// New formula to charge storage fee for transaction, measured in APT. - pub fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee { - txn_size - .checked_sub(self.large_transaction_cutoff) - .unwrap_or(NumBytes::zero()) - * self.storage_fee_per_transaction_byte - } - /// Calculate the intrinsic gas for the transaction based upon its size in bytes. pub fn calculate_intrinsic_gas( &self, diff --git a/aptos-move/aptos-memory-usage-tracker/src/lib.rs b/aptos-move/aptos-memory-usage-tracker/src/lib.rs index e8ab4f6f44c15..3a4ac1895532c 100644 --- a/aptos-move/aptos-memory-usage-tracker/src/lib.rs +++ b/aptos-move/aptos-memory-usage-tracker/src/lib.rs @@ -4,8 +4,7 @@ use aptos_gas_algebra::{AbstractValueSize, Fee, FeePerGasUnit, InternalGas, NumArgs, NumBytes}; use aptos_gas_meter::AptosGasMeter; use aptos_types::{ - account_config::CORE_CODE_ADDRESS, contract_event::ContractEvent, - state_store::state_key::StateKey, write_set::WriteOpSize, + account_config::CORE_CODE_ADDRESS, state_store::state_key::StateKey, write_set::WriteOpSize, }; use move_binary_format::{ errors::{PartialVMError, PartialVMResult, VMResult}, @@ -462,18 +461,6 @@ where delegate! { fn algebra(&self) -> &Self::Algebra; - - fn storage_fee_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - fn storage_fee_refund_for_state_slot(&self, op: &WriteOpSize) -> Fee; - - fn storage_fee_for_state_bytes(&self, key: &StateKey, op: &WriteOpSize) -> Fee; - - fn storage_fee_per_event(&self, event: &ContractEvent) -> Fee; - - fn storage_discount_for_events(&self, total_cost: Fee) -> Fee; - - fn storage_fee_for_transaction_storage(&self, txn_size: NumBytes) -> Fee; } delegate_mut! { diff --git a/aptos-move/aptos-vm-types/src/abstract_write_op.rs b/aptos-move/aptos-vm-types/src/abstract_write_op.rs index e8d9dcc916e42..20bbcc113db5d 100644 --- a/aptos-move/aptos-vm-types/src/abstract_write_op.rs +++ b/aptos-move/aptos-vm-types/src/abstract_write_op.rs @@ -63,10 +63,7 @@ impl AbstractResourceWriteOp { write_len: materialized_size.expect("Modification must have size"), } }, - Deletion => WriteOpSize::Deletion, - DeletionWithMetadata { metadata } => WriteOpSize::DeletionWithDeposit { - deposit: metadata.deposit(), - }, + Deletion | DeletionWithMetadata { .. } => WriteOpSize::Deletion, } }, InPlaceDelayedFieldChange(InPlaceDelayedFieldChangeOp { diff --git a/aptos-move/aptos-vm-types/src/storage/io_pricing.rs b/aptos-move/aptos-vm-types/src/storage/io_pricing.rs index ec873e525455d..dd8c9a17d3f3c 100644 --- a/aptos-move/aptos-vm-types/src/storage/io_pricing.rs +++ b/aptos-move/aptos-vm-types/src/storage/io_pricing.rs @@ -75,7 +75,7 @@ impl IoPricingV1 { Modification { write_len } => { cost += self.write_data_per_byte_in_val * NumBytes::new(*write_len); }, - Deletion | DeletionWithDeposit { .. } => (), + Deletion => (), } cost @@ -158,7 +158,7 @@ impl IoPricingV2 { self.per_item_write * NumArgs::new(1) + self.write_op_size(key, *write_len) * self.per_byte_write }, - Deletion | DeletionWithDeposit { .. } => 0.into(), + Deletion => 0.into(), } } } diff --git a/aptos-move/aptos-vm-types/src/storage/mod.rs b/aptos-move/aptos-vm-types/src/storage/mod.rs index 68c4ced4a1e1c..d70336f052be4 100644 --- a/aptos-move/aptos-vm-types/src/storage/mod.rs +++ b/aptos-move/aptos-vm-types/src/storage/mod.rs @@ -4,6 +4,7 @@ use crate::storage::{ change_set_configs::ChangeSetConfigs, io_pricing::{IoPricing, IoPricingV3}, + space_pricing::DiskSpacePricing, }; use aptos_gas_schedule::{AptosGasParameters, LATEST_GAS_FEATURE_VERSION}; use aptos_types::on_chain_config::ConfigStorage; @@ -12,10 +13,12 @@ use std::fmt::Debug; pub mod change_set_configs; pub mod io_pricing; +pub mod space_pricing; #[derive(Clone, Debug)] pub struct StorageGasParameters { pub io_pricing: IoPricing, + pub space_pricing: DiskSpacePricing, pub change_set_configs: ChangeSetConfigs, } @@ -26,10 +29,12 @@ impl StorageGasParameters { config_storage: &impl ConfigStorage, ) -> Self { let io_pricing = IoPricing::new(feature_version, gas_params, config_storage); + let space_pricing = DiskSpacePricing::v1(); let change_set_configs = ChangeSetConfigs::new(feature_version, gas_params); Self { io_pricing, + space_pricing, change_set_configs, } } @@ -40,6 +45,7 @@ impl StorageGasParameters { feature_version: LATEST_GAS_FEATURE_VERSION, legacy_free_write_bytes_quota: free_write_bytes_quota, }), + space_pricing: DiskSpacePricing::v1(), change_set_configs: ChangeSetConfigs::unlimited_at_gas_feature_version( LATEST_GAS_FEATURE_VERSION, ), diff --git a/aptos-move/aptos-vm-types/src/storage/space_pricing.rs b/aptos-move/aptos-vm-types/src/storage/space_pricing.rs new file mode 100644 index 0000000000000..02e305a4102ec --- /dev/null +++ b/aptos-move/aptos-vm-types/src/storage/space_pricing.rs @@ -0,0 +1,142 @@ +// Copyright © Aptos Foundation +// SPDX-License-Identifier: Apache-2.0 + +use aptos_gas_algebra::{Fee, NumSlots}; +use aptos_gas_schedule::TransactionGasParameters; +use aptos_types::{ + contract_event::ContractEvent, + state_store::{state_key::StateKey, state_value::StateValueMetadata}, + write_set::WriteOpSize, +}; +use move_core_types::gas_algebra::NumBytes; +use std::fmt::Debug; + +pub struct ChargeAndRefund { + pub charge: Fee, + pub refund: Fee, +} + +#[derive(Clone, Debug)] +pub enum DiskSpacePricing { + /// With per state slot free write quota + V1, +} + +impl DiskSpacePricing { + pub fn v1() -> Self { + Self::V1 + } + + /// Calculates the storage fee for a state slot allocation. + pub fn charge_refund_write_op( + &self, + params: &TransactionGasParameters, + key: &StateKey, + op_size: &WriteOpSize, + metadata: Option<&mut StateValueMetadata>, + ) -> ChargeAndRefund { + match self { + Self::V1 => Self::charge_refund_write_op_v1(params, key, op_size, metadata), + } + } + + /// Calculates the storage fee for an event. + pub fn storage_fee_per_event( + &self, + params: &TransactionGasParameters, + event: &ContractEvent, + ) -> Fee { + match self { + Self::V1 => NumBytes::new(event.size() as u64) * params.storage_fee_per_event_byte, + } + } + + /// Calculates the discount applied to the event storage fees, based on a free quota. + pub fn storage_discount_for_events( + &self, + params: &TransactionGasParameters, + total_cost: Fee, + ) -> Fee { + match self { + Self::V1 => std::cmp::min( + total_cost, + params.free_event_bytes_quota * params.storage_fee_per_event_byte, + ), + } + } + + /// Calculates the storage fee for the transaction. + pub fn storage_fee_for_transaction_storage( + &self, + params: &TransactionGasParameters, + txn_size: NumBytes, + ) -> Fee { + match self { + Self::V1 => { + txn_size + .checked_sub(params.large_transaction_cutoff) + .unwrap_or(NumBytes::zero()) + * params.storage_fee_per_transaction_byte + }, + } + } + + // ----- private methods ----- + + fn discounted_write_op_size_for_v1( + params: &TransactionGasParameters, + key: &StateKey, + value_size: u64, + ) -> NumBytes { + let size = NumBytes::new(key.size() as u64) + NumBytes::new(value_size); + size.checked_sub(params.legacy_free_write_bytes_quota) + .unwrap_or(NumBytes::zero()) + } + + fn charge_refund_write_op_v1( + params: &TransactionGasParameters, + key: &StateKey, + op_size: &WriteOpSize, + metadata: Option<&mut StateValueMetadata>, + ) -> ChargeAndRefund { + use WriteOpSize::*; + + match op_size { + Creation { write_len } => { + let slot_fee = params.storage_fee_per_state_slot_create * NumSlots::new(1); + let bytes_fee = Self::discounted_write_op_size_for_v1(params, key, *write_len) + * params.storage_fee_per_excess_state_byte; + + if let Some(m) = metadata { + m.set_deposit(slot_fee.into()) + } + + ChargeAndRefund { + charge: slot_fee + bytes_fee, + refund: 0.into(), + } + }, + Modification { write_len } => { + let bytes_fee = Self::discounted_write_op_size_for_v1(params, key, *write_len) + * params.storage_fee_per_excess_state_byte; + + ChargeAndRefund { + charge: bytes_fee, + refund: 0.into(), + } + }, + Deletion => { + let refund = match metadata { + None => 0, + Some(m) => m.deposit(), + } + .into(); + + ChargeAndRefund { + charge: 0.into(), + refund, + } + }, + } + } +} diff --git a/types/src/write_set.rs b/types/src/write_set.rs index bcbea69208680..48db97d689a98 100644 --- a/types/src/write_set.rs +++ b/types/src/write_set.rs @@ -159,7 +159,6 @@ pub enum WriteOpSize { Creation { write_len: u64 }, Modification { write_len: u64 }, Deletion, - DeletionWithDeposit { deposit: u64 }, } impl From<&WriteOp> for WriteOpSize { @@ -174,10 +173,7 @@ impl From<&WriteOp> for WriteOpSize { write_len: data.len() as u64, } }, - Deletion => WriteOpSize::Deletion, - DeletionWithMetadata { metadata } => WriteOpSize::DeletionWithDeposit { - deposit: metadata.deposit(), - }, + Deletion | DeletionWithMetadata { .. } => WriteOpSize::Deletion, } } } @@ -188,16 +184,7 @@ impl WriteOpSize { WriteOpSize::Creation { write_len } | WriteOpSize::Modification { write_len } => { Some(*write_len) }, - WriteOpSize::Deletion | WriteOpSize::DeletionWithDeposit { .. } => None, - } - } - - pub fn deletion_deposit(&self) -> Option { - match self { - WriteOpSize::DeletionWithDeposit { deposit } => Some(*deposit), - WriteOpSize::Creation { .. } - | WriteOpSize::Modification { .. } - | WriteOpSize::Deletion => None, + WriteOpSize::Deletion => None, } } }