cfx_execute_helper/observer/
gasman.rsuse cfx_executor::{
    observer::{
        CallTracer, CheckpointTracer, DrainTrace, InternalTransferTracer,
        OpcodeTracer, SetAuthTracer, StorageTracer,
    },
    stack::FrameResult,
};
use cfx_parameters::{
    block::CROSS_SPACE_GAS_RATIO,
    internal_contract_addresses::CROSS_SPACE_CONTRACT_ADDRESS,
};
use cfx_types::U256;
use cfx_vm_types::ActionParams;
use typemap::ShareDebugMap;
const EVM_RATIO: (u64, u64) = (64, 63);
const CROSS_SPACE_RATIO: (u64, u64) = (CROSS_SPACE_GAS_RATIO, 1);
struct FrameGasInfo {
    init_gas: U256,
    gas_cost_in_subcall: U256,
    gas_limit_for_subcall: U256,
    cross_space_internal: bool,
}
impl FrameGasInfo {
    #[inline]
    fn gas_cost(&self, gas_left: &U256) -> U256 {
        self.init_gas.saturating_sub(*gas_left)
    }
    #[inline]
    fn gas_cost_this_level(&self, gas_left: &U256) -> U256 {
        self.gas_cost(gas_left)
            .saturating_sub(self.gas_cost_in_subcall)
    }
    #[inline]
    fn minimum_init_gas(&self, gas_left: &U256, ratio: (u64, u64)) -> U256 {
        let (numerator, denominator) = ratio;
        self.gas_cost_this_level(gas_left)
            + (self.gas_limit_for_subcall * numerator + denominator - 1)
                / denominator
    }
}
#[derive(Default)]
pub struct GasMan {
    gas_limit: U256,
    gas_record: Vec<FrameGasInfo>,
}
impl DrainTrace for GasMan {
    fn drain_trace(self, map: &mut ShareDebugMap) {
        map.insert::<GasLimitEstimation>(self.gas_required());
    }
}
pub struct GasLimitEstimation;
impl typemap::Key for GasLimitEstimation {
    type Value = U256;
}
impl GasMan {
    pub fn gas_required(&self) -> U256 { self.gas_limit }
    fn record_call_create(
        &mut self, gas_pass_in: &U256, cross_space_internal: bool,
    ) {
        self.gas_record.push(FrameGasInfo {
            init_gas: gas_pass_in.clone(),
            gas_cost_in_subcall: U256::zero(),
            gas_limit_for_subcall: U256::zero(),
            cross_space_internal,
        })
    }
    fn record_return(&mut self, gas_left: &U256) {
        let child_level = self.gas_record.pop().unwrap();
        let ratio = if child_level.cross_space_internal {
            CROSS_SPACE_RATIO
        } else {
            EVM_RATIO
        };
        if let Some(FrameGasInfo {
            gas_cost_in_subcall,
            gas_limit_for_subcall,
            ..
        }) = self.gas_record.last_mut()
        {
            *gas_cost_in_subcall += child_level.gas_cost(gas_left);
            *gas_limit_for_subcall +=
                child_level.minimum_init_gas(gas_left, ratio);
        } else {
            self.gas_limit = child_level.minimum_init_gas(gas_left, ratio);
        }
    }
}
impl CallTracer for GasMan {
    fn record_call(&mut self, params: &ActionParams) {
        let cross_space_internal =
            params.code_address == CROSS_SPACE_CONTRACT_ADDRESS;
        self.record_call_create(¶ms.gas, cross_space_internal);
    }
    fn record_call_result(&mut self, result: &FrameResult) {
        let gas_left =
            result.as_ref().map_or(U256::zero(), |r| r.gas_left.clone());
        self.record_return(&gas_left);
    }
    fn record_create(&mut self, params: &ActionParams) {
        self.record_call_create(¶ms.gas, false);
    }
    fn record_create_result(&mut self, result: &FrameResult) {
        let gas_left =
            result.as_ref().map_or(U256::zero(), |r| r.gas_left.clone());
        self.record_return(&gas_left);
    }
}
impl CheckpointTracer for GasMan {}
impl InternalTransferTracer for GasMan {}
impl StorageTracer for GasMan {}
impl OpcodeTracer for GasMan {}
impl SetAuthTracer for GasMan {}