rtvm_interpreter/
gas.rs

1//! EVM gas calculation utilities.
2
3mod calc;
4mod constants;
5
6pub use calc::*;
7pub use constants::*;
8
9/// Represents the state of gas during execution.
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Gas {
13    /// The initial gas limit. This is constant throughout execution.
14    limit: u64,
15    /// The remaining gas.
16    remaining: u64,
17    /// The remaining gas, without memory expansion.
18    remaining_nomem: u64,
19    /// The **last** memory expansion cost.
20    memory: u64,
21    /// Refunded gas. This is used only at the end of execution.
22    refunded: i64,
23}
24
25impl Gas {
26    /// Creates a new `Gas` struct with the given gas limit.
27    #[inline]
28    pub const fn new(limit: u64) -> Self {
29        Self {
30            limit,
31            remaining: limit,
32            remaining_nomem: limit,
33            memory: 0,
34            refunded: 0,
35        }
36    }
37
38    /// Returns the gas limit.
39    #[inline]
40    pub const fn limit(&self) -> u64 {
41        self.limit
42    }
43
44    /// Returns the **last** memory expansion cost.
45    #[inline]
46    pub const fn memory(&self) -> u64 {
47        self.memory
48    }
49
50    /// Returns the total amount of gas that was refunded.
51    #[inline]
52    pub const fn refunded(&self) -> i64 {
53        self.refunded
54    }
55
56    /// Returns the total amount of gas spent.
57    #[inline]
58    pub const fn spent(&self) -> u64 {
59        self.limit - self.remaining
60    }
61
62    #[doc(hidden)]
63    #[inline]
64    #[deprecated(note = "use `spent` instead")]
65    pub const fn spend(&self) -> u64 {
66        self.spent()
67    }
68
69    /// Returns the amount of gas remaining.
70    #[inline]
71    pub const fn remaining(&self) -> u64 {
72        self.remaining
73    }
74
75    /// Erases a gas cost from the totals.
76    #[inline]
77    pub fn erase_cost(&mut self, returned: u64) {
78        self.remaining_nomem += returned;
79        self.remaining += returned;
80    }
81
82    /// Records a refund value.
83    ///
84    /// `refund` can be negative but `self.refunded` should always be positive
85    /// at the end of transact.
86    #[inline]
87    pub fn record_refund(&mut self, refund: i64) {
88        self.refunded += refund;
89    }
90
91    /// Set a refund value for final refund.
92    ///
93    /// Max refund value is limited to Nth part (depending of fork) of gas spend.
94    ///
95    /// Related to EIP-3529: Reduction in refunds
96    #[inline]
97    pub fn set_final_refund(&mut self, is_london: bool) {
98        let max_refund_quotient = if is_london { 5 } else { 2 };
99        self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
100    }
101
102    /// Set a refund value. This overrides the current refund value.
103    #[inline]
104    pub fn set_refund(&mut self, refund: i64) {
105        self.refunded = refund;
106    }
107
108    /// Records an explicit cost.
109    ///
110    /// Returns `false` if the gas limit is exceeded.
111    #[inline]
112    pub fn record_cost(&mut self, cost: u64) -> bool {
113        let (remaining, overflow) = self.remaining.overflowing_sub(cost);
114        if overflow {
115            return false;
116        }
117
118        self.remaining_nomem -= cost;
119        self.remaining = remaining;
120        true
121    }
122
123    /// Records memory expansion gas.
124    ///
125    /// Used in [`resize_memory!`](crate::resize_memory).
126    #[inline]
127    pub fn record_memory(&mut self, gas_memory: u64) -> bool {
128        if gas_memory > self.memory {
129            let (remaining, overflow) = self.remaining_nomem.overflowing_sub(gas_memory);
130            if overflow {
131                return false;
132            }
133            self.memory = gas_memory;
134            self.remaining = remaining;
135        }
136        true
137    }
138}