fuel_vm/interpreter/
gas.rs

1use super::Interpreter;
2use crate::{
3    constraints::reg_key::*,
4    error::SimpleResult,
5    prelude::{
6        Bug,
7        BugVariant,
8    },
9};
10
11use fuel_asm::{
12    PanicReason,
13    RegId,
14};
15use fuel_tx::DependentCost;
16use fuel_types::Word;
17
18#[cfg(test)]
19mod tests;
20
21impl<M, S, Tx, Ecal, V> Interpreter<M, S, Tx, Ecal, V> {
22    /// Global remaining gas amount
23    pub fn remaining_gas(&self) -> Word {
24        self.registers[RegId::GGAS]
25    }
26
27    /// Sets the amount of gas available for execution to both CGAS and GGAS.
28    /// Only useful in contexts where CGAS and GGAS are the same,
29    /// i.e. predicates and testing.
30    pub(crate) fn set_gas(&mut self, gas: Word) {
31        self.registers[RegId::GGAS] = gas;
32        self.registers[RegId::CGAS] = gas;
33    }
34
35    pub(crate) fn dependent_gas_charge(
36        &mut self,
37        gas_cost: DependentCost,
38        arg: Word,
39    ) -> SimpleResult<()> {
40        let SystemRegisters { ggas, cgas, .. } = split_registers(&mut self.registers).0;
41        dependent_gas_charge(cgas, ggas, gas_cost, arg)
42    }
43
44    pub(crate) fn dependent_gas_charge_without_base(
45        &mut self,
46        gas_cost: DependentCost,
47        arg: Word,
48    ) -> SimpleResult<()> {
49        let SystemRegisters { ggas, cgas, .. } = split_registers(&mut self.registers).0;
50        dependent_gas_charge_without_base(cgas, ggas, gas_cost, arg)
51    }
52
53    /// Do a gas charge with the given amount, panicing when running out of gas.
54    pub fn gas_charge(&mut self, gas: Word) -> SimpleResult<()> {
55        let SystemRegisters { ggas, cgas, .. } = split_registers(&mut self.registers).0;
56
57        gas_charge(cgas, ggas, gas)
58    }
59}
60
61pub(crate) fn dependent_gas_charge_without_base(
62    mut cgas: RegMut<CGAS>,
63    ggas: RegMut<GGAS>,
64    gas_cost: DependentCost,
65    arg: Word,
66) -> SimpleResult<()> {
67    let cost = gas_cost.resolve_without_base(arg);
68    gas_charge(cgas.as_mut(), ggas, cost)
69}
70
71pub(crate) fn dependent_gas_charge(
72    mut cgas: RegMut<CGAS>,
73    ggas: RegMut<GGAS>,
74    gas_cost: DependentCost,
75    arg: Word,
76) -> SimpleResult<()> {
77    let cost = gas_cost.resolve(arg);
78    gas_charge(cgas.as_mut(), ggas, cost)
79}
80
81pub(crate) fn gas_charge(
82    mut cgas: RegMut<CGAS>,
83    mut ggas: RegMut<GGAS>,
84    gas: Word,
85) -> SimpleResult<()> {
86    if *cgas > *ggas {
87        Err(Bug::new(BugVariant::GlobalGasLessThanContext).into())
88    } else if gas > *cgas {
89        *ggas = (*ggas)
90            .checked_sub(*cgas)
91            .ok_or_else(|| Bug::new(BugVariant::GlobalGasUnderflow))?;
92        *cgas = 0;
93
94        Err(PanicReason::OutOfGas.into())
95    } else {
96        *cgas = (*cgas)
97            .checked_sub(gas)
98            .ok_or_else(|| Bug::new(BugVariant::ContextGasUnderflow))?;
99        *ggas = (*ggas)
100            .checked_sub(gas)
101            .ok_or_else(|| Bug::new(BugVariant::GlobalGasUnderflow))?;
102
103        Ok(())
104    }
105}