1pub use context_interface::cfg::gas::*;
4
5#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
7#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
8pub struct Gas {
9 limit: u64,
11 remaining: u64,
13 refunded: i64,
15 memory: MemoryGas,
17}
18
19impl Gas {
20 #[inline]
22 pub const fn new(limit: u64) -> Self {
23 Self {
24 limit,
25 remaining: limit,
26 refunded: 0,
27 memory: MemoryGas::new(),
28 }
29 }
30
31 #[inline]
33 pub const fn new_spent(limit: u64) -> Self {
34 Self {
35 limit,
36 remaining: 0,
37 refunded: 0,
38 memory: MemoryGas::new(),
39 }
40 }
41
42 #[inline]
44 pub const fn limit(&self) -> u64 {
45 self.limit
46 }
47
48 #[inline]
50 pub fn memory(&self) -> &MemoryGas {
51 &self.memory
52 }
53
54 #[inline]
56 pub fn memory_mut(&mut self) -> &mut MemoryGas {
57 &mut self.memory
58 }
59
60 #[inline]
62 pub const fn refunded(&self) -> i64 {
63 self.refunded
64 }
65
66 #[inline]
68 pub const fn spent(&self) -> u64 {
69 self.limit - self.remaining
70 }
71
72 #[inline]
74 pub const fn used(&self) -> u64 {
75 self.spent().saturating_sub(self.refunded() as u64)
76 }
77
78 #[inline]
80 pub const fn spent_sub_refunded(&self) -> u64 {
81 self.spent().saturating_sub(self.refunded as u64)
82 }
83
84 #[inline]
86 pub const fn remaining(&self) -> u64 {
87 self.remaining
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(always)]
151 #[must_use = "In case of not enough gas, the interpreter should halt with an out-of-gas error"]
152 pub fn record_cost_unsafe(&mut self, cost: u64) -> bool {
153 let oog = self.remaining < cost;
154 self.remaining = self.remaining.wrapping_sub(cost);
155 oog
156 }
157}
158
159#[derive(Debug)]
161pub enum MemoryExtensionResult {
162 Extended,
164 Same,
166 OutOfGas,
168}
169
170#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)]
175#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
176pub struct MemoryGas {
177 pub words_num: usize,
179 pub expansion_cost: u64,
181}
182
183impl MemoryGas {
184 #[inline]
186 pub const fn new() -> Self {
187 Self {
188 words_num: 0,
189 expansion_cost: 0,
190 }
191 }
192
193 #[inline]
197 pub fn set_words_num(&mut self, words_num: usize, mut expansion_cost: u64) -> Option<u64> {
198 self.words_num = words_num;
199 core::mem::swap(&mut self.expansion_cost, &mut expansion_cost);
200 self.expansion_cost.checked_sub(expansion_cost)
201 }
202
203 #[inline]
206 pub fn record_new_len(
207 &mut self,
208 new_num: usize,
209 linear_cost: u64,
210 quadratic_cost: u64,
211 ) -> Option<u64> {
212 if new_num <= self.words_num {
213 return None;
214 }
215 self.words_num = new_num;
216 let mut cost = memory_gas(new_num, linear_cost, quadratic_cost);
217 core::mem::swap(&mut self.expansion_cost, &mut cost);
218 Some(self.expansion_cost - cost)
221 }
222}
223
224#[inline]
226pub const fn memory_gas(num_words: usize, linear_cost: u64, quadratic_cost: u64) -> u64 {
227 let num_words = num_words as u64;
228 linear_cost
229 .saturating_mul(num_words)
230 .saturating_add(num_words.saturating_mul(num_words) / quadratic_cost)
231}