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 #[deprecated = "memory expansion cost is not tracked anymore; \
55 calculate it using `SharedMemory::current_expansion_cost` instead"]
56 #[doc(hidden)]
57 pub const fn memory(&self) -> u64 {
58 0
59 }
60
61 #[inline]
63 pub const fn refunded(&self) -> i64 {
64 self.refunded
65 }
66
67 #[inline]
69 pub const fn spent(&self) -> u64 {
70 self.limit - self.remaining
71 }
72
73 #[inline]
75 pub const fn spent_sub_refunded(&self) -> u64 {
76 self.spent().saturating_sub(self.refunded as u64)
77 }
78
79 #[inline]
81 pub const fn remaining(&self) -> u64 {
82 self.remaining
83 }
84
85 pub const fn remaining_63_of_64_parts(&self) -> u64 {
87 self.remaining - self.remaining / 64
88 }
89
90 #[inline]
92 pub fn erase_cost(&mut self, returned: u64) {
93 self.remaining += returned;
94 }
95
96 #[inline]
98 pub fn spend_all(&mut self) {
99 self.remaining = 0;
100 }
101
102 #[inline]
107 pub fn record_refund(&mut self, refund: i64) {
108 self.refunded += refund;
109 }
110
111 #[inline]
117 pub fn set_final_refund(&mut self, is_london: bool) {
118 let max_refund_quotient = if is_london { 5 } else { 2 };
119 self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
120 }
121
122 #[inline]
124 pub fn set_refund(&mut self, refund: i64) {
125 self.refunded = refund;
126 }
127
128 #[inline]
130 pub fn set_spent(&mut self, spent: u64) {
131 self.remaining = self.limit.saturating_sub(spent);
132 }
133
134 #[inline]
138 #[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"]
139 pub fn record_cost(&mut self, cost: u64) -> bool {
140 if let Some(new_remaining) = self.remaining.checked_sub(cost) {
141 self.remaining = new_remaining;
142 return true;
143 }
144 false
145 }
146
147 #[inline]
149 #[must_use = "internally uses record_cost that flags out of gas error"]
150 pub fn record_memory_expansion(&mut self, new_len: usize) -> MemoryExtensionResult {
151 let Some(additional_cost) = self.memory.record_new_len(new_len) else {
152 return MemoryExtensionResult::Same;
153 };
154
155 if !self.record_cost(additional_cost) {
156 return MemoryExtensionResult::OutOfGas;
157 }
158
159 MemoryExtensionResult::Extended
160 }
161}
162
163pub enum MemoryExtensionResult {
164 Extended,
166 Same,
168 OutOfGas,
170}
171
172#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
177#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
178pub struct MemoryGas {
179 pub words_num: usize,
181 pub expansion_cost: u64,
183}
184
185impl MemoryGas {
186 pub const fn new() -> Self {
187 Self {
188 words_num: 0,
189 expansion_cost: 0,
190 }
191 }
192
193 #[inline]
194 pub fn record_new_len(&mut self, new_num: usize) -> Option<u64> {
195 if new_num <= self.words_num {
196 return None;
197 }
198 self.words_num = new_num;
199 let mut cost = crate::gas::calc::memory_gas(new_num);
200 core::mem::swap(&mut self.expansion_cost, &mut cost);
201 Some(self.expansion_cost - cost)
204 }
205}