1mod calc;
4mod constants;
5pub mod params;
6
7pub use calc::*;
8pub use constants::*;
9
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct Gas {
14 limit: u64,
16 remaining: u64,
18 refunded: i64,
20 memory: MemoryGas,
22}
23
24impl Gas {
25 #[inline]
27 pub const fn new(limit: u64) -> Self {
28 Self {
29 limit,
30 remaining: limit,
31 refunded: 0,
32 memory: MemoryGas::new(),
33 }
34 }
35
36 #[inline]
38 pub const fn new_spent(limit: u64) -> Self {
39 Self {
40 limit,
41 remaining: 0,
42 refunded: 0,
43 memory: MemoryGas::new(),
44 }
45 }
46
47 #[inline]
49 pub const fn limit(&self) -> u64 {
50 self.limit
51 }
52
53 #[inline]
55 pub fn memory(&self) -> &MemoryGas {
56 &self.memory
57 }
58
59 #[inline]
61 pub fn memory_mut(&mut self) -> &mut MemoryGas {
62 &mut self.memory
63 }
64
65 #[inline]
67 pub const fn refunded(&self) -> i64 {
68 self.refunded
69 }
70
71 #[inline]
73 pub const fn spent(&self) -> u64 {
74 self.limit - self.remaining
75 }
76
77 #[inline]
79 pub const fn used(&self) -> u64 {
80 self.spent().saturating_sub(self.refunded() as u64)
81 }
82
83 #[inline]
85 pub const fn spent_sub_refunded(&self) -> u64 {
86 self.spent().saturating_sub(self.refunded as u64)
87 }
88
89 #[inline]
91 pub const fn remaining(&self) -> u64 {
92 self.remaining
93 }
94
95 #[inline]
97 pub fn erase_cost(&mut self, returned: u64) {
98 self.remaining += returned;
99 }
100
101 #[inline]
103 pub fn spend_all(&mut self) {
104 self.remaining = 0;
105 }
106
107 #[inline]
112 pub fn record_refund(&mut self, refund: i64) {
113 self.refunded += refund;
114 }
115
116 #[inline]
122 pub fn set_final_refund(&mut self, is_london: bool) {
123 let max_refund_quotient = if is_london { 5 } else { 2 };
124 self.refunded = (self.refunded() as u64).min(self.spent() / max_refund_quotient) as i64;
125 }
126
127 #[inline]
129 pub fn set_refund(&mut self, refund: i64) {
130 self.refunded = refund;
131 }
132
133 #[inline]
135 pub fn set_spent(&mut self, spent: u64) {
136 self.remaining = self.limit.saturating_sub(spent);
137 }
138
139 #[inline]
143 #[must_use = "prefer using `gas!` instead to return an out-of-gas error on failure"]
144 pub fn record_cost(&mut self, cost: u64) -> bool {
145 if let Some(new_remaining) = self.remaining.checked_sub(cost) {
146 self.remaining = new_remaining;
147 return true;
148 }
149 false
150 }
151
152 #[inline(always)]
156 #[must_use = "In case of not enough gas, the interpreter should halt with an out-of-gas error"]
157 pub fn record_cost_unsafe(&mut self, cost: u64) -> bool {
158 let oog = self.remaining < cost;
159 self.remaining = self.remaining.wrapping_sub(cost);
160 oog
161 }
162}
163
164#[derive(Debug)]
166pub enum MemoryExtensionResult {
167 Extended,
169 Same,
171 OutOfGas,
173}
174
175#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
180#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
181pub struct MemoryGas {
182 pub words_num: usize,
184 pub expansion_cost: u64,
186}
187
188impl MemoryGas {
189 #[inline]
191 pub const fn new() -> Self {
192 Self {
193 words_num: 0,
194 expansion_cost: 0,
195 }
196 }
197
198 #[inline]
202 pub fn set_words_num(&mut self, words_num: usize, mut expansion_cost: u64) -> Option<u64> {
203 self.words_num = words_num;
204 core::mem::swap(&mut self.expansion_cost, &mut expansion_cost);
205 self.expansion_cost.checked_sub(expansion_cost)
206 }
207
208 #[inline]
211 pub fn record_new_len(
212 &mut self,
213 new_num: usize,
214 linear_cost: u64,
215 quadratic_cost: u64,
216 ) -> Option<u64> {
217 if new_num <= self.words_num {
218 return None;
219 }
220 self.words_num = new_num;
221 let mut cost = crate::gas::calc::memory_gas(new_num, linear_cost, quadratic_cost);
222 core::mem::swap(&mut self.expansion_cost, &mut cost);
223 Some(self.expansion_cost - cost)
226 }
227}