// 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>, } 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 { 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); } }