//! Gas计量系统 use crate::bytecode::Opcode; use thiserror::Error; #[derive(Debug, Error)] pub enum GasError { #[error("Gas不足")] OutOfGas, #[error("Gas溢出")] GasOverflow, } /// Gas成本定义 pub struct GasCost; impl GasCost { /// 获取操作码的Gas成本 pub fn get(opcode: Opcode) -> u64 { match opcode { // 栈操作 - 低成本 Opcode::Push => 3, Opcode::Pop => 2, Opcode::Dup => 3, Opcode::Swap => 3, // 算术运算 - 中等成本 Opcode::Add => 5, Opcode::Sub => 5, Opcode::Mul => 8, Opcode::Div => 10, Opcode::Mod => 10, // 比较运算 - 低成本 Opcode::Eq => 3, Opcode::Ne => 3, Opcode::Lt => 3, Opcode::Le => 3, Opcode::Gt => 3, Opcode::Ge => 3, // 逻辑运算 - 低成本 Opcode::And => 3, Opcode::Or => 3, Opcode::Not => 3, // 内存操作 - 中等成本 Opcode::Load => 50, Opcode::Store => 100, // 控制流 - 中等成本 Opcode::Jump => 8, Opcode::JumpIf => 10, Opcode::Call => 100, Opcode::Return => 5, Opcode::Halt => 0, // 区块链操作 - 高成本 Opcode::GetBalance => 400, Opcode::Transfer => 9000, Opcode::GetCaller => 2, Opcode::GetTimestamp => 2, Opcode::GetBlockNumber => 2, // 加密操作 - 高成本 Opcode::Sha3 => 30, Opcode::VerifySignature => 3000, } } } /// Gas计量器 #[derive(Debug, Clone)] pub struct GasMetering { gas_limit: u64, gas_used: u64, } impl GasMetering { pub fn new(gas_limit: u64) -> Self { GasMetering { gas_limit, gas_used: 0, } } /// 消耗Gas pub fn consume(&mut self, amount: u64) -> Result<(), GasError> { let new_used = self.gas_used.checked_add(amount) .ok_or(GasError::GasOverflow)?; if new_used > self.gas_limit { return Err(GasError::OutOfGas); } self.gas_used = new_used; Ok(()) } /// 消耗操作码的Gas pub fn consume_opcode(&mut self, opcode: Opcode) -> Result<(), GasError> { let cost = GasCost::get(opcode); self.consume(cost) } /// 获取剩余Gas pub fn remaining(&self) -> u64 { self.gas_limit.saturating_sub(self.gas_used) } /// 获取已使用Gas pub fn used(&self) -> u64 { self.gas_used } /// 获取Gas限制 pub fn limit(&self) -> u64 { self.gas_limit } /// 重置Gas计量器 pub fn reset(&mut self) { self.gas_used = 0; } } #[cfg(test)] mod tests { use super::*; #[test] fn test_gas_consumption() { let mut gas = GasMetering::new(1000); assert!(gas.consume(100).is_ok()); assert_eq!(gas.used(), 100); assert_eq!(gas.remaining(), 900); } #[test] fn test_gas_out_of_gas() { let mut gas = GasMetering::new(100); assert!(gas.consume(50).is_ok()); assert!(gas.consume(60).is_err()); } #[test] fn test_gas_opcode_cost() { let mut gas = GasMetering::new(1000); assert!(gas.consume_opcode(Opcode::Push).is_ok()); assert_eq!(gas.used(), 3); assert!(gas.consume_opcode(Opcode::Add).is_ok()); assert_eq!(gas.used(), 8); } #[test] fn test_gas_reset() { let mut gas = GasMetering::new(1000); gas.consume(500).expect("FIX-006: unexpected None/Err"); assert_eq!(gas.used(), 500); gas.reset(); assert_eq!(gas.used(), 0); } #[test] fn test_gas_costs() { assert_eq!(GasCost::get(Opcode::Push), 3); assert_eq!(GasCost::get(Opcode::Transfer), 9000); assert_eq!(GasCost::get(Opcode::Sha3), 30); } }