1//! EVM gas calculation utilities.
23mod calc;
4mod constants;
56pub use calc::*;
7pub use constants::*;
89/// 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.
14limit: u64,
15/// The remaining gas.
16remaining: u64,
17/// Refunded gas. This is used only at the end of execution.
18refunded: i64,
19}
2021impl Gas {
22/// Creates a new `Gas` struct with the given gas limit.
23#[inline]
24pub const fn new(limit: u64) -> Self {
25Self {
26 limit,
27 remaining: limit,
28 refunded: 0,
29 }
30 }
3132/// Creates a new `Gas` struct with the given gas limit, but without any gas remaining.
33#[inline]
34pub const fn new_spent(limit: u64) -> Self {
35Self {
36 limit,
37 remaining: 0,
38 refunded: 0,
39 }
40 }
4142/// Returns the gas limit.
43#[inline]
44pub const fn limit(&self) -> u64 {
45self.limit
46 }
4748/// 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)]
53pub const fn memory(&self) -> u64 {
540
55}
5657/// Returns the total amount of gas that was refunded.
58#[inline]
59pub const fn refunded(&self) -> i64 {
60self.refunded
61 }
6263/// Returns the total amount of gas spent.
64#[inline]
65pub const fn spent(&self) -> u64 {
66self.limit - self.remaining
67 }
6869/// Returns the amount of gas remaining.
70#[inline]
71pub const fn remaining(&self) -> u64 {
72self.remaining
73 }
7475/// Return remaining gas after subtracting 63/64 parts.
76pub const fn remaining_63_of_64_parts(&self) -> u64 {
77self.remaining - self.remaining / 64
78}
7980/// Erases a gas cost from the totals.
81#[inline]
82pub fn erase_cost(&mut self, returned: u64) {
83self.remaining += returned;
84 }
8586/// Spends all remaining gas.
87#[inline]
88pub fn spend_all(&mut self) {
89self.remaining = 0;
90 }
9192/// 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]
97pub fn record_refund(&mut self, refund: i64) {
98self.refunded += refund;
99 }
100101/// 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]
107pub fn set_final_refund(&mut self, is_london: bool) {
108let max_refund_quotient = if is_london { 5 } else { 2 };
109self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
110 }
111112/// Set a refund value. This overrides the current refund value.
113#[inline]
114pub fn set_refund(&mut self, refund: i64) {
115self.refunded = refund;
116 }
117118/// 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"]
123pub fn record_cost(&mut self, cost: u64) -> bool {
124let (remaining, overflow) = self.remaining.overflowing_sub(cost);
125let success = !overflow;
126if success {
127self.remaining = remaining;
128 }
129 success
130 }
131}