types.rs
1 // Copyright (c) 2025-2026 ACDC Network 2 // This file is part of the alphaos library. 3 // 4 // Alpha Chain | Delta Chain Protocol 5 // International Monetary Graphite. 6 // 7 // Derived from Aleo (https://aleo.org) and ProvableHQ (https://provable.com). 8 // They built world-class ZK infrastructure. We installed the EASY button. 9 // Their cryptography: elegant. Our modifications: bureaucracy-compatible. 10 // Original brilliance: theirs. Robert's Rules: ours. Bugs: definitely ours. 11 // 12 // Original Aleo/ProvableHQ code subject to Apache 2.0 https://www.apache.org/licenses/LICENSE-2.0 13 // All modifications and new work: CC0 1.0 Universal Public Domain Dedication. 14 // No rights reserved. No permission required. No warranty. No refunds. 15 // 16 // https://creativecommons.org/publicdomain/zero/1.0/ 17 // SPDX-License-Identifier: CC0-1.0 18 19 //! CLP type definitions. 20 21 use serde::{Deserialize, Serialize}; 22 use std::time::Duration; 23 24 /// CLP configuration parameters. 25 #[derive(Debug, Clone, Serialize, Deserialize)] 26 pub struct ClpConfig { 27 /// Interval between challenges in seconds. 28 pub interval_secs: u64, 29 /// Response window in seconds. 30 pub response_window_secs: u64, 31 /// Number of missed challenges before counting against rate. 32 pub grace_period: u32, 33 /// Number of consecutive failing epochs before ejection. 34 pub disqualification_epochs: u32, 35 /// Slash amount in basis points for failure. 36 pub failure_slash_bps: u16, 37 } 38 39 impl Default for ClpConfig { 40 fn default() -> Self { 41 Self { 42 interval_secs: 60, 43 response_window_secs: 30, 44 grace_period: 2, 45 disqualification_epochs: 3, 46 failure_slash_bps: 100, // 1% 47 } 48 } 49 } 50 51 impl ClpConfig { 52 /// Get the challenge interval as a Duration. 53 pub fn interval(&self) -> Duration { 54 Duration::from_secs(self.interval_secs) 55 } 56 57 /// Get the response window as a Duration. 58 pub fn response_window(&self) -> Duration { 59 Duration::from_secs(self.response_window_secs) 60 } 61 } 62 63 /// A CLP challenge issued to validators. 64 #[derive(Debug, Clone, Serialize, Deserialize)] 65 pub struct ClpChallenge { 66 /// Unique challenge identifier. 67 pub id: ChallengeId, 68 /// The challenge value to sign. 69 pub value: [u8; 32], 70 /// Block height when challenge was issued. 71 pub issued_at_block: u64, 72 /// Epoch number. 73 pub epoch: u64, 74 /// Round number within epoch. 75 pub round: u64, 76 /// Deadline block height for responses. 77 pub deadline_block: u64, 78 } 79 80 /// Unique identifier for a challenge. 81 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] 82 pub struct ChallengeId(pub [u8; 32]); 83 84 impl std::fmt::Display for ChallengeId { 85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 86 write!(f, "{}", hex_encode(&self.0[..8])) 87 } 88 } 89 90 /// A validator's response to a challenge. 91 #[derive(Debug, Clone, Serialize, Deserialize)] 92 pub struct ClpResponse { 93 /// The challenge being responded to. 94 pub challenge_id: ChallengeId, 95 /// Validator's address. 96 pub validator: ValidatorAddress, 97 /// Signature over (challenge_value || timestamp). 98 pub signature: Signature, 99 /// Block height when response was created. 100 pub response_block: u64, 101 } 102 103 /// Validator address type (placeholder - will use network's actual type). 104 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] 105 pub struct ValidatorAddress(pub [u8; 32]); 106 107 impl std::fmt::Display for ValidatorAddress { 108 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 109 write!(f, "ax1{}", hex_encode(&self.0[..8])) 110 } 111 } 112 113 /// Signature type (placeholder). 114 #[derive(Debug, Clone, Serialize, Deserialize)] 115 pub struct Signature(pub Vec<u8>); 116 117 /// Response rate thresholds for penalty evaluation. 118 #[derive(Debug, Clone, Copy)] 119 pub enum ResponseRateThreshold { 120 /// Good standing (>= 95%). 121 Good, 122 /// Warning (90-95%). 123 Warning, 124 /// Minor penalty (80-90%). 125 MinorPenalty, 126 /// Major penalty (< 80%). 127 MajorPenalty, 128 } 129 130 impl ResponseRateThreshold { 131 /// Get the threshold from a response rate. 132 pub fn from_rate(rate: f64) -> Self { 133 if rate >= 0.95 { 134 Self::Good 135 } else if rate >= 0.90 { 136 Self::Warning 137 } else if rate >= 0.80 { 138 Self::MinorPenalty 139 } else { 140 Self::MajorPenalty 141 } 142 } 143 144 /// Get the slash amount in basis points. 145 pub fn slash_bps(&self) -> u16 { 146 match self { 147 Self::Good => 0, 148 Self::Warning => 0, 149 Self::MinorPenalty => 50, // 0.5% 150 Self::MajorPenalty => 100, // 1% 151 } 152 } 153 } 154 155 /// Validator's CLP status for an epoch. 156 #[derive(Debug, Clone, Default, Serialize, Deserialize)] 157 pub struct ValidatorClpStatus { 158 /// Total challenges issued this epoch. 159 pub total_challenges: u32, 160 /// Challenges responded to. 161 pub responses: u32, 162 /// Missed challenges (after grace period). 163 pub missed: u32, 164 /// Consecutive failing epochs. 165 pub consecutive_failures: u32, 166 } 167 168 impl ValidatorClpStatus { 169 /// Calculate the response rate. 170 pub fn response_rate(&self) -> f64 { 171 if self.total_challenges == 0 { 172 1.0 // No challenges yet, assume good 173 } else { 174 self.responses as f64 / self.total_challenges as f64 175 } 176 } 177 178 /// Check if this validator should be ejected. 179 pub fn should_eject(&self, config: &ClpConfig) -> bool { 180 self.consecutive_failures >= config.disqualification_epochs 181 } 182 } 183 184 /// Result of CLP evaluation at epoch end. 185 #[derive(Debug, Clone, Serialize, Deserialize)] 186 pub struct ClpEpochResult { 187 /// Epoch number. 188 pub epoch: u64, 189 /// Validators that passed. 190 pub passed: Vec<ValidatorAddress>, 191 /// Validators that received warnings. 192 pub warned: Vec<ValidatorAddress>, 193 /// Validators that were slashed. 194 pub slashed: Vec<(ValidatorAddress, u16)>, // (address, slash_bps) 195 /// Validators that were ejected. 196 pub ejected: Vec<ValidatorAddress>, 197 } 198 199 /// Helper function for hex encoding. 200 fn hex_encode(bytes: &[u8]) -> String { 201 bytes.iter().map(|b| format!("{:02x}", b)).collect() 202 }