274 lines
7.9 KiB
Rust
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);
|
|
}
|
|
}
|