177 lines
4.2 KiB
Rust
177 lines
4.2 KiB
Rust
//! 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);
|
|
}
|
|
}
|