revm_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    /// Refunded gas. This is used only at the end of execution.
18    refunded: i64,
19}
20
21impl Gas {
22    /// Creates a new `Gas` struct with the given gas limit.
23    #[inline]
24    pub const fn new(limit: u64) -> Self {
25        Self {
26            limit,
27            remaining: limit,
28            refunded: 0,
29        }
30    }
31
32    /// Creates a new `Gas` struct with the given gas limit, but without any gas remaining.
33    #[inline]
34    pub const fn new_spent(limit: u64) -> Self {
35        Self {
36            limit,
37            remaining: 0,
38            refunded: 0,
39        }
40    }
41
42    /// Returns the gas limit.
43    #[inline]
44    pub const fn limit(&self) -> u64 {
45        self.limit
46    }
47
48    /// Returns the **last** memory expansion cost.
49    #[inline]
50    #[deprecated = "memory expansion cost is not tracked anymore; \
51                    calculate it using `SharedMemory::current_expansion_cost` instead"]
52    #[doc(hidden)]
53    pub const fn memory(&self) -> u64 {
54        0
55    }
56
57    /// Returns the total amount of gas that was refunded.
58    #[inline]
59    pub const fn refunded(&self) -> i64 {
60        self.refunded
61    }
62
63    /// Returns the total amount of gas spent.
64    #[inline]
65    pub const fn spent(&self) -> u64 {
66        self.limit - self.remaining
67    }
68
69    /// Returns the amount of gas remaining.
70    #[inline]
71    pub const fn remaining(&self) -> u64 {
72        self.remaining
73    }
74
75    /// Return remaining gas after subtracting 63/64 parts.
76    pub const fn remaining_63_of_64_parts(&self) -> u64 {
77        self.remaining - self.remaining / 64
78    }
79
80    /// Erases a gas cost from the totals.
81    #[inline]
82    pub fn erase_cost(&mut self, returned: u64) {
83        self.remaining += returned;
84    }
85
86    /// Spends all remaining gas.
87    #[inline]
88    pub fn spend_all(&mut self) {
89        self.remaining = 0;
90    }
91
92    /// Records a refund value.
93    ///
94    /// `refund` can be negative but `self.refunded` should always be positive
95    /// at the end of transact.
96    #[inline]
97    pub fn record_refund(&mut self, refund: i64) {
98        self.refunded += refund;
99    }
100
101    /// Set a refund value for final refund.
102    ///
103    /// Max refund value is limited to Nth part (depending of fork) of gas spend.
104    ///
105    /// Related to EIP-3529: Reduction in refunds
106    #[inline]
107    pub fn set_final_refund(&mut self, is_london: bool) {
108        let max_refund_quotient = if is_london { 5 } else { 2 };
109        self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
110    }
111
112    /// Set a refund value. This overrides the current refund value.
113    #[inline]
114    pub fn set_refund(&mut self, refund: i64) {
115        self.refunded = refund;
116    }
117
118    /// Records an explicit cost.
119    ///
120    /// Returns `false` if the gas limit is exceeded.
121    #[inline]
122    #[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"]
123    pub fn record_cost(&mut self, cost: u64) -> bool {
124        let (remaining, overflow) = self.remaining.overflowing_sub(cost);
125        let success = !overflow;
126        if success {
127            self.remaining = remaining;
128        }
129        success
130    }
131}