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