iota_sdk_types/gas.rs
1// Copyright (c) Mysten Labs, Inc.
2// Modifications Copyright (c) 2025 IOTA Stiftung
3// SPDX-License-Identifier: Apache-2.0
4
5/// Summary of gas charges.
6///
7/// Storage is charged independently of computation.
8/// There are 3 parts to the storage charges:
9/// `storage_cost`: it is the charge of storage at the time the transaction is
10/// executed. The cost of storage is the number of bytes of the
11/// objects being mutated multiplied by a variable storage cost
12/// per byte `storage_rebate`: this is the amount a user gets back when
13/// manipulating an object. The `storage_rebate` is the
14/// `storage_cost` for an object minus fees. `non_refundable_storage_fee`: not
15/// all the value of the object storage cost is
16/// given back to user and there is a small fraction that
17/// is kept by the system. This value tracks that charge.
18///
19/// When looking at a gas cost summary the amount charged to the user is
20/// `computation_cost + storage_cost - storage_rebate`
21/// and that is the amount that is deducted from the gas coins.
22/// `non_refundable_storage_fee` is collected from the objects being
23/// mutated/deleted and it is tracked by the system in storage funds.
24///
25/// Objects deleted, including the older versions of objects mutated, have the
26/// storage field on the objects added up to a pool of "potential rebate". This
27/// rebate then is reduced by the "nonrefundable rate" such that:
28/// `potential_rebate(storage cost of deleted/mutated objects) =
29/// storage_rebate + non_refundable_storage_fee`
30///
31/// # BCS
32///
33/// The BCS serialized form for this type is defined by the following ABNF:
34///
35/// ```text
36/// gas-cost-summary = u64 ; computation-cost
37/// u64 ; storage-cost
38/// u64 ; storage-rebate
39/// u64 ; non-refundable-storage-fee
40/// ```
41#[derive(Clone, Debug, Default, PartialEq, Eq)]
42#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
43#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
44#[cfg_attr(feature = "proptest", derive(test_strategy::Arbitrary))]
45pub struct GasCostSummary {
46 /// Cost of computation/execution
47 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
48 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
49 pub computation_cost: u64,
50 /// The burned component of the computation/execution costs
51 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
52 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
53 pub computation_cost_burned: u64,
54 /// Storage cost, it's the sum of all storage cost for all objects created
55 /// or mutated.
56 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
57 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
58 pub storage_cost: u64,
59 /// The amount of storage cost refunded to the user for all objects deleted
60 /// or mutated in the transaction.
61 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
62 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
63 pub storage_rebate: u64,
64 /// The fee for the rebate. The portion of the storage rebate kept by the
65 /// system.
66 #[cfg_attr(feature = "serde", serde(with = "crate::_serde::ReadableDisplay"))]
67 #[cfg_attr(feature = "schemars", schemars(with = "crate::_schemars::U64"))]
68 pub non_refundable_storage_fee: u64,
69}
70
71impl GasCostSummary {
72 /// Create a new gas cost summary.
73 ///
74 /// # Arguments
75 /// * `computation_cost` - Cost of computation cost/execution.
76 /// * `storage_cost` - Storage cost, it's the sum of all storage cost for
77 /// all objects created or mutated.
78 /// * `storage_rebate` - The amount of storage cost refunded to the user for
79 /// all objects deleted or mutated in the transaction.
80 /// * `non_refundable_storage_fee` - The fee for the rebate. The portion of
81 /// the storage rebate kept by the system.
82 pub fn new(
83 computation_cost: u64,
84 computation_cost_burned: u64,
85 storage_cost: u64,
86 storage_rebate: u64,
87 non_refundable_storage_fee: u64,
88 ) -> GasCostSummary {
89 GasCostSummary {
90 computation_cost,
91 computation_cost_burned,
92 storage_cost,
93 storage_rebate,
94 non_refundable_storage_fee,
95 }
96 }
97
98 /// The total gas used, which is the sum of computation and storage costs.
99 pub fn gas_used(&self) -> u64 {
100 self.computation_cost + self.storage_cost
101 }
102
103 /// The net gas usage, which is the total gas used minus the storage rebate.
104 /// A positive number means used gas; negative number means refund.
105 pub fn net_gas_usage(&self) -> i64 {
106 self.gas_used() as i64 - self.storage_rebate as i64
107 }
108}
109
110impl std::fmt::Display for GasCostSummary {
111 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
112 write!(f, "computation_cost: {}, ", self.computation_cost)?;
113 write!(f, "storage_cost: {}, ", self.storage_cost)?;
114 write!(f, "storage_rebate: {}, ", self.storage_rebate)?;
115 write!(
116 f,
117 "non_refundable_storage_fee: {}",
118 self.non_refundable_storage_fee
119 )
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 #[cfg(target_arch = "wasm32")]
126 use wasm_bindgen_test::wasm_bindgen_test as test;
127
128 use super::*;
129
130 #[test]
131 #[cfg(feature = "serde")]
132 fn formats() {
133 let actual = GasCostSummary {
134 computation_cost: 42,
135 computation_cost_burned: 24,
136 storage_cost: u64::MAX,
137 storage_rebate: 0,
138 non_refundable_storage_fee: 9,
139 };
140
141 println!("{}", serde_json::to_string(&actual).unwrap());
142 println!("{:?}", bcs::to_bytes(&actual).unwrap());
143 }
144}