1mod calc;
4mod constants;
5
6pub use calc::*;
7pub use constants::*;
8
9#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
11#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12pub struct Gas {
13 limit: u64,
15 remaining: u64,
17 refunded: i64,
19 memory: MemoryGas,
21}
22
23impl Gas {
24 #[inline]
26 pub const fn new(limit: u64) -> Self {
27 Self {
28 limit,
29 remaining: limit,
30 refunded: 0,
31 memory: MemoryGas::new(),
32 }
33 }
34
35 #[inline]
37 pub const fn new_spent(limit: u64) -> Self {
38 Self {
39 limit,
40 remaining: 0,
41 refunded: 0,
42 memory: MemoryGas::new(),
43 }
44 }
45
46 #[inline]
48 pub const fn limit(&self) -> u64 {
49 self.limit
50 }
51
52 #[inline]
54 pub fn memory(&self) -> &MemoryGas {
55 &self.memory
56 }
57
58 #[inline]
60 pub fn memory_mut(&mut self) -> &mut MemoryGas {
61 &mut self.memory
62 }
63
64 #[inline]
66 pub const fn refunded(&self) -> i64 {
67 self.refunded
68 }
69
70 #[inline]
72 pub const fn spent(&self) -> u64 {
73 self.limit - self.remaining
74 }
75
76 #[inline]
78 pub const fn used(&self) -> u64 {
79 self.spent().saturating_sub(self.refunded() as u64)
80 }
81
82 #[inline]
84 pub const fn spent_sub_refunded(&self) -> u64 {
85 self.spent().saturating_sub(self.refunded as u64)
86 }
87
88 #[inline]
90 pub const fn remaining(&self) -> u64 {
91 self.remaining
92 }
93
94 pub const fn remaining_63_of_64_parts(&self) -> u64 {
96 self.remaining - self.remaining / 64
97 }
98
99 #[inline]
101 pub fn erase_cost(&mut self, returned: u64) {
102 self.remaining += returned;
103 }
104
105 #[inline]
107 pub fn spend_all(&mut self) {
108 self.remaining = 0;
109 }
110
111 #[inline]
116 pub fn record_refund(&mut self, refund: i64) {
117 self.refunded += refund;
118 }
119
120 #[inline]
126 pub fn set_final_refund(&mut self, is_london: bool) {
127 let max_refund_quotient = if is_london { 5 } else { 2 };
128 self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
129 }
130
131 #[inline]
133 pub fn set_refund(&mut self, refund: i64) {
134 self.refunded = refund;
135 }
136
137 #[inline]
139 pub fn set_spent(&mut self, spent: u64) {
140 self.remaining = self.limit.saturating_sub(spent);
141 }
142
143 #[inline]
147 #[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"]
148 pub fn record_cost(&mut self, cost: u64) -> bool {
149 if let Some(new_remaining) = self.remaining.checked_sub(cost) {
150 self.remaining = new_remaining;
151 return true;
152 }
153 false
154 }
155
156 #[inline(always)]
160 #[must_use = "In case of not enough gas, the interpreter should halt with an out-of-gas error"]
161 pub fn record_cost_unsafe(&mut self, cost: u64) -> bool {
162 let oog = self.remaining < cost;
163 self.remaining = self.remaining.wrapping_sub(cost);
164 oog
165 }
166}
167
168#[derive(Debug)]
170pub enum MemoryExtensionResult {
171 Extended,
173 Same,
175 OutOfGas,
177}
178
179#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
184#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
185pub struct MemoryGas {
186 pub words_num: usize,
188 pub expansion_cost: u64,
190}
191
192impl MemoryGas {
193 #[inline]
195 pub const fn new() -> Self {
196 Self {
197 words_num: 0,
198 expansion_cost: 0,
199 }
200 }
201
202 #[inline]
205 pub fn record_new_len(&mut self, new_num: usize) -> Option<u64> {
206 if new_num <= self.words_num {
207 return None;
208 }
209 self.words_num = new_num;
210 let mut cost = crate::gas::calc::memory_gas(new_num);
211 core::mem::swap(&mut self.expansion_cost, &mut cost);
212 Some(self.expansion_cost - cost)
215 }
216}