NAC_Blockchain/nac-cbpp-l0/src/params/mod.rs

274 lines
7.9 KiB
Rust

// NAC CBPP L0 - Consensus Parameters Storage
// 共识参数存储模块
use serde::{Deserialize, Serialize};
use std::sync::{Arc, RwLock};
use nac_udm::primitives::Hash;
/// Block height type
pub type BlockHeight = u64;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ParamsError {
#[error("Parameter not found: {0}")]
ParameterNotFound(String),
#[error("Invalid parameter value")]
InvalidValue,
#[error("Parameter update failed: {0}")]
UpdateFailed(String),
}
/// CBPP Consensus Parameters
///
/// These parameters control the behavior of the fluid block model
/// and are stored in the L0 system state tree.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CBPPParams {
/// Current epoch number
pub epoch_number: u64,
/// Dynamic gas limit for blocks
pub gas_limit: u64,
/// Minimum time interval between blocks (milliseconds)
pub delta_t_min: u64,
/// Maximum time interval before producing empty block (milliseconds)
pub delta_t_max: u64,
/// Target block utilization (0.0 - 1.0)
pub target_utilization: f64,
/// Gas limit adjustment factor (0.0 - 1.0)
pub adjust_factor: f64,
/// Minimum gas limit
pub gas_limit_min: u64,
/// Maximum gas limit
pub gas_limit_max: u64,
/// Constitutional hash (current version)
pub constitutional_hash: Hash,
/// Last update height
pub last_update_height: BlockHeight,
}
impl Default for CBPPParams {
fn default() -> Self {
Self {
epoch_number: 0,
gas_limit: 10_000_000, // 10M gas
delta_t_min: 100, // 100ms
delta_t_max: 2000, // 2s
target_utilization: 0.7, // 70%
adjust_factor: 0.125, // 12.5%
gas_limit_min: 1_000_000, // 1M gas
gas_limit_max: 100_000_000, // 100M gas
constitutional_hash: Hash::zero(),
last_update_height: 0,
}
}
}
impl CBPPParams {
/// Adjust gas limit based on previous epoch statistics
///
/// Algorithm from CBPP whitepaper Section 5.2
pub fn adjust_gas_limit(&mut self, avg_block_size: u64) {
let current_limit = self.gas_limit as f64;
let target_size = self.target_utilization * current_limit;
let avg_size = avg_block_size as f64;
let new_limit = if avg_size > target_size {
// Too congested, increase limit
let adjustment = (avg_size / target_size) - 1.0;
current_limit * (1.0 + adjustment * self.adjust_factor)
} else {
// Too empty, decrease limit
let adjustment = 1.0 - (avg_size / target_size);
current_limit * (1.0 - adjustment * self.adjust_factor)
};
// Clamp to ±12.5% change
let clamped = new_limit.clamp(
current_limit * 0.875,
current_limit * 1.125,
);
// Apply absolute limits
self.gas_limit = (clamped as u64).clamp(
self.gas_limit_min,
self.gas_limit_max,
);
}
/// Check if parameters are valid
pub fn validate(&self) -> Result<(), ParamsError> {
if self.delta_t_min >= self.delta_t_max {
return Err(ParamsError::InvalidValue);
}
if self.target_utilization <= 0.0 || self.target_utilization >= 1.0 {
return Err(ParamsError::InvalidValue);
}
if self.adjust_factor <= 0.0 || self.adjust_factor >= 1.0 {
return Err(ParamsError::InvalidValue);
}
if self.gas_limit < self.gas_limit_min || self.gas_limit > self.gas_limit_max {
return Err(ParamsError::InvalidValue);
}
Ok(())
}
}
/// CBPP Parameters Manager
///
/// Manages consensus parameters with thread-safe access
pub struct ParamsManager {
params: Arc<RwLock<CBPPParams>>,
}
impl ParamsManager {
/// Create a new params manager with default parameters
pub fn new() -> Self {
Self {
params: Arc::new(RwLock::new(CBPPParams::default())),
}
}
/// Create a new params manager with custom parameters
pub fn with_params(params: CBPPParams) -> Result<Self, ParamsError> {
params.validate()?;
Ok(Self {
params: Arc::new(RwLock::new(params)),
})
}
/// Get current parameters (read-only)
pub fn get(&self) -> CBPPParams {
self.params.read().expect("rwlock not poisoned").clone()
}
/// Update parameters
pub fn update(&self, new_params: CBPPParams) -> Result<(), ParamsError> {
new_params.validate()?;
let mut params = self.params.write().expect("rwlock not poisoned");
*params = new_params;
Ok(())
}
/// Update gas limit based on epoch statistics
pub fn update_gas_limit(&self, avg_block_size: u64) {
let mut params = self.params.write().expect("rwlock not poisoned");
params.adjust_gas_limit(avg_block_size);
}
/// Start new epoch
pub fn start_new_epoch(&self, new_epoch: u64, constitutional_hash: Hash) {
let mut params = self.params.write().expect("rwlock not poisoned");
params.epoch_number = new_epoch;
params.constitutional_hash = constitutional_hash;
}
/// Get specific parameter
pub fn get_gas_limit(&self) -> u64 {
self.params.read().expect("rwlock not poisoned").gas_limit
}
pub fn get_delta_t_min(&self) -> u64 {
self.params.read().expect("rwlock not poisoned").delta_t_min
}
pub fn get_delta_t_max(&self) -> u64 {
self.params.read().expect("rwlock not poisoned").delta_t_max
}
pub fn get_constitutional_hash(&self) -> Hash {
self.params.read().expect("rwlock not poisoned").constitutional_hash
}
}
impl Default for ParamsManager {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_params() {
let params = CBPPParams::default();
assert!(params.validate().is_ok());
assert_eq!(params.delta_t_min, 100);
assert_eq!(params.delta_t_max, 2000);
}
#[test]
fn test_gas_limit_adjustment_increase() {
let mut params = CBPPParams::default();
let initial_limit = params.gas_limit;
// Simulate high utilization (90% of target)
let avg_block_size = (params.gas_limit as f64 * 0.9) as u64;
params.adjust_gas_limit(avg_block_size);
// Gas limit should increase
assert!(params.gas_limit > initial_limit);
}
#[test]
fn test_gas_limit_adjustment_decrease() {
let mut params = CBPPParams::default();
let initial_limit = params.gas_limit;
// Simulate low utilization (30% of target)
let avg_block_size = (params.gas_limit as f64 * 0.3) as u64;
params.adjust_gas_limit(avg_block_size);
// Gas limit should decrease
assert!(params.gas_limit < initial_limit);
}
#[test]
fn test_gas_limit_clamping() {
let mut params = CBPPParams::default();
let initial_limit = params.gas_limit;
// Simulate extreme high utilization
let avg_block_size = params.gas_limit * 10;
params.adjust_gas_limit(avg_block_size);
// Should be clamped to max 12.5% increase
assert!(params.gas_limit <= (initial_limit as f64 * 1.125) as u64);
}
#[test]
fn test_params_manager() {
let manager = ParamsManager::new();
assert_eq!(manager.get_delta_t_min(), 100);
assert_eq!(manager.get_delta_t_max(), 2000);
// Test update
let mut new_params = manager.get();
new_params.delta_t_min = 200;
manager.update(new_params).expect("FIX-006: unexpected None/Err");
assert_eq!(manager.get_delta_t_min(), 200);
}
}