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}