206 lines
5.4 KiB
Rust
206 lines
5.4 KiB
Rust
// NVM-L1 Gas计量系统
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
/// Gas配置
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct GasConfig {
|
|
/// 基础交易Gas
|
|
pub base_tx_gas: u64,
|
|
/// 合约创建Gas
|
|
pub contract_creation_gas: u64,
|
|
/// 合约调用Gas
|
|
pub contract_call_gas: u64,
|
|
/// 存储写入Gas (每字节)
|
|
pub storage_write_gas_per_byte: u64,
|
|
/// 存储读取Gas (每字节)
|
|
pub storage_read_gas_per_byte: u64,
|
|
/// 计算Gas (每操作)
|
|
pub compute_gas_per_op: u64,
|
|
/// 内存扩展Gas (每字节)
|
|
pub memory_expansion_gas_per_byte: u64,
|
|
}
|
|
|
|
impl Default for GasConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
base_tx_gas: 21000,
|
|
contract_creation_gas: 53000,
|
|
contract_call_gas: 25000,
|
|
storage_write_gas_per_byte: 20,
|
|
storage_read_gas_per_byte: 5,
|
|
compute_gas_per_op: 3,
|
|
memory_expansion_gas_per_byte: 3,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Gas计量器
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct GasMeter {
|
|
/// Gas配置
|
|
config: GasConfig,
|
|
/// Gas限制
|
|
gas_limit: u64,
|
|
/// 已使用Gas
|
|
gas_used: u64,
|
|
}
|
|
|
|
/// Gas错误
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
pub enum GasError {
|
|
/// Gas不足
|
|
OutOfGas,
|
|
/// Gas限制过低
|
|
GasLimitTooLow,
|
|
/// 无效的Gas价格
|
|
InvalidGasPrice,
|
|
}
|
|
|
|
impl GasMeter {
|
|
/// 创建新的Gas计量器
|
|
pub fn new(gas_limit: u64) -> Self {
|
|
Self::with_config(gas_limit, GasConfig::default())
|
|
}
|
|
|
|
/// 使用自定义配置创建Gas计量器
|
|
pub fn with_config(gas_limit: u64, config: GasConfig) -> Self {
|
|
Self {
|
|
config,
|
|
gas_limit,
|
|
gas_used: 0,
|
|
}
|
|
}
|
|
|
|
/// 获取Gas限制
|
|
pub fn gas_limit(&self) -> u64 {
|
|
self.gas_limit
|
|
}
|
|
|
|
/// 获取已使用Gas
|
|
pub fn gas_used(&self) -> u64 {
|
|
self.gas_used
|
|
}
|
|
|
|
/// 获取剩余Gas
|
|
pub fn gas_remaining(&self) -> u64 {
|
|
self.gas_limit.saturating_sub(self.gas_used)
|
|
}
|
|
|
|
/// 消耗Gas
|
|
pub fn consume_gas(&mut self, amount: u64) -> Result<(), GasError> {
|
|
if self.gas_used + amount > self.gas_limit {
|
|
return Err(GasError::OutOfGas);
|
|
}
|
|
self.gas_used += amount;
|
|
Ok(())
|
|
}
|
|
|
|
/// 消耗基础交易Gas
|
|
pub fn consume_base_tx_gas(&mut self) -> Result<(), GasError> {
|
|
self.consume_gas(self.config.base_tx_gas)
|
|
}
|
|
|
|
/// 消耗合约创建Gas
|
|
pub fn consume_contract_creation_gas(&mut self) -> Result<(), GasError> {
|
|
self.consume_gas(self.config.contract_creation_gas)
|
|
}
|
|
|
|
/// 消耗合约调用Gas
|
|
pub fn consume_contract_call_gas(&mut self) -> Result<(), GasError> {
|
|
self.consume_gas(self.config.contract_call_gas)
|
|
}
|
|
|
|
/// 消耗存储写入Gas
|
|
pub fn consume_storage_write_gas(&mut self, bytes: usize) -> Result<(), GasError> {
|
|
let gas = self.config.storage_write_gas_per_byte * bytes as u64;
|
|
self.consume_gas(gas)
|
|
}
|
|
|
|
/// 消耗存储读取Gas
|
|
pub fn consume_storage_read_gas(&mut self, bytes: usize) -> Result<(), GasError> {
|
|
let gas = self.config.storage_read_gas_per_byte * bytes as u64;
|
|
self.consume_gas(gas)
|
|
}
|
|
|
|
/// 消耗计算Gas
|
|
pub fn consume_compute_gas(&mut self, ops: usize) -> Result<(), GasError> {
|
|
let gas = self.config.compute_gas_per_op * ops as u64;
|
|
self.consume_gas(gas)
|
|
}
|
|
|
|
/// 消耗内存扩展Gas
|
|
pub fn consume_memory_expansion_gas(&mut self, bytes: usize) -> Result<(), GasError> {
|
|
let gas = self.config.memory_expansion_gas_per_byte * bytes as u64;
|
|
self.consume_gas(gas)
|
|
}
|
|
|
|
/// 重置Gas计量器
|
|
pub fn reset(&mut self) {
|
|
self.gas_used = 0;
|
|
}
|
|
|
|
/// 检查是否有足够的Gas
|
|
pub fn has_gas(&self, amount: u64) -> bool {
|
|
self.gas_used + amount <= self.gas_limit
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_gas_meter_creation() {
|
|
let meter = GasMeter::new(100000);
|
|
assert_eq!(meter.gas_limit(), 100000);
|
|
assert_eq!(meter.gas_used(), 0);
|
|
assert_eq!(meter.gas_remaining(), 100000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_consume_gas() {
|
|
let mut meter = GasMeter::new(100000);
|
|
assert!(meter.consume_gas(50000).is_ok());
|
|
assert_eq!(meter.gas_used(), 50000);
|
|
assert_eq!(meter.gas_remaining(), 50000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_out_of_gas() {
|
|
let mut meter = GasMeter::new(100000);
|
|
assert!(meter.consume_gas(100001).is_err());
|
|
}
|
|
|
|
#[test]
|
|
fn test_consume_base_tx_gas() {
|
|
let mut meter = GasMeter::new(100000);
|
|
assert!(meter.consume_base_tx_gas().is_ok());
|
|
assert_eq!(meter.gas_used(), 21000);
|
|
}
|
|
|
|
#[test]
|
|
fn test_consume_storage_gas() {
|
|
let mut meter = GasMeter::new(100000);
|
|
assert!(meter.consume_storage_write_gas(100).is_ok());
|
|
assert_eq!(meter.gas_used(), 2000); // 20 * 100
|
|
}
|
|
|
|
#[test]
|
|
fn test_has_gas() {
|
|
let mut meter = GasMeter::new(100000);
|
|
meter.consume_gas(50000).unwrap();
|
|
assert!(meter.has_gas(50000));
|
|
assert!(!meter.has_gas(50001));
|
|
}
|
|
|
|
#[test]
|
|
fn test_reset() {
|
|
let mut meter = GasMeter::new(100000);
|
|
meter.consume_gas(50000).unwrap();
|
|
meter.reset();
|
|
assert_eq!(meter.gas_used(), 0);
|
|
assert_eq!(meter.gas_remaining(), 100000);
|
|
}
|
|
}
|