/ node / consensus / src / clp / types.rs
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  }