/ vm / gid / types.rs
types.rs
  1  // Copyright (c) 2025-2026 ACDC Network
  2  // This file is part of the alphavm 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  //! Governor Identity (GID) type definitions.
 20  //!
 21  //! This module defines the core types used by the GID program:
 22  //! - [`GovernorStatus`] - The status of a governor (Active, Suspended, Removed)
 23  //! - [`GovernorRecord`] - Complete record for a registered governor
 24  //!
 25  //! ## Type Aliases
 26  //!
 27  //! - `Address` - Reuses the address type from credits module
 28  //! - `EncryptedMetadata` - Encrypted blob containing governor identity verification data
 29  
 30  use crate::{credits::types::Address, types::AxAmount};
 31  use serde::{Deserialize, Serialize};
 32  
 33  /// Encrypted metadata blob for governor identity verification.
 34  ///
 35  /// In Phase 1, this is stored as raw bytes. The encryption scheme
 36  /// and metadata format will be defined in later phases.
 37  pub type EncryptedMetadata = Vec<u8>;
 38  
 39  /// The status of a governor in the registry.
 40  ///
 41  /// Governors can transition through these states:
 42  /// - `Active` -> `Suspended`: Governor privileges temporarily revoked
 43  /// - `Suspended` -> `Active`: Governor privileges restored
 44  /// - `Active` -> `Removed`: Governor permanently removed
 45  /// - `Suspended` -> `Removed`: Governor permanently removed
 46  ///
 47  /// Note: Removal is permanent and cannot be reversed.
 48  #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
 49  pub enum GovernorStatus {
 50      /// Governor is active and can perform mint operations.
 51      #[default]
 52      Active,
 53  
 54      /// Governor is temporarily suspended and cannot mint.
 55      ///
 56      /// Suspension may be used during audits or investigations.
 57      /// A suspended governor can be restored to Active status.
 58      Suspended,
 59  
 60      /// Governor has been permanently removed from the registry.
 61      ///
 62      /// Removal is irreversible. The governor's historical records
 63      /// are retained for audit purposes, but they cannot perform
 64      /// any operations.
 65      Removed,
 66  }
 67  
 68  impl GovernorStatus {
 69      /// Returns true if the governor can perform mint operations.
 70      pub fn can_mint(&self) -> bool {
 71          matches!(self, Self::Active)
 72      }
 73  
 74      /// Returns true if this status allows restoration to Active.
 75      pub fn can_restore(&self) -> bool {
 76          matches!(self, Self::Suspended)
 77      }
 78  
 79      /// Returns a human-readable name for the status.
 80      pub fn name(&self) -> &'static str {
 81          match self {
 82              Self::Active => "active",
 83              Self::Suspended => "suspended",
 84              Self::Removed => "removed",
 85          }
 86      }
 87  }
 88  
 89  impl core::fmt::Display for GovernorStatus {
 90      fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
 91          write!(f, "{}", self.name())
 92      }
 93  }
 94  
 95  /// A complete record for a registered governor.
 96  ///
 97  /// Governor records track all information about a governor including
 98  /// their identity, registration time, current status, and cumulative
 99  /// mint/burn statistics for audit purposes.
100  ///
101  /// ## Privacy
102  ///
103  /// The `metadata` field contains encrypted identity verification data.
104  /// In ZK mode, this data remains private and is only accessible to
105  /// authorized auditors with the appropriate decryption keys.
106  #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107  pub struct GovernorRecord {
108      /// The blockchain address that identifies this governor.
109      ///
110      /// This is the public key / address used for signing mint operations.
111      pub address: Address,
112  
113      /// Encrypted metadata blob containing identity verification data.
114      ///
115      /// This may include:
116      /// - KYC/AML verification hashes
117      /// - Organizational identifiers
118      /// - Authorization documentation references
119      ///
120      /// The encryption ensures privacy while allowing authorized audits.
121      pub metadata: EncryptedMetadata,
122  
123      /// The block height at which this governor was registered.
124      ///
125      /// Used for audit trails and determining governor seniority.
126      pub registration_block: u64,
127  
128      /// The current status of this governor.
129      pub status: GovernorStatus,
130  
131      /// Cumulative amount of credits minted by this governor.
132      ///
133      /// This is a running total for audit purposes. It represents
134      /// all credits ever minted, not the current circulating amount.
135      pub cumulative_mint: AxAmount,
136  
137      /// Cumulative amount of credits burned under this governor's authority.
138      ///
139      /// This tracks burns that were attributed to this governor,
140      /// useful for auditing net credit creation per governor.
141      pub cumulative_burn: AxAmount,
142  }
143  
144  impl GovernorRecord {
145      /// Creates a new governor record with default values.
146      ///
147      /// The new governor is created in `Active` status with zero
148      /// cumulative mint/burn values.
149      ///
150      /// # Arguments
151      ///
152      /// * `address` - The blockchain address for this governor
153      /// * `metadata` - Encrypted identity verification data
154      /// * `registration_block` - The block height of registration
155      pub fn new(address: Address, metadata: EncryptedMetadata, registration_block: u64) -> Self {
156          Self {
157              address,
158              metadata,
159              registration_block,
160              status: GovernorStatus::Active,
161              cumulative_mint: AxAmount::ZERO,
162              cumulative_burn: AxAmount::ZERO,
163          }
164      }
165  
166      /// Returns true if this governor can perform mint operations.
167      pub fn can_mint(&self) -> bool {
168          self.status.can_mint()
169      }
170  
171      /// Returns the net credits created by this governor.
172      ///
173      /// This is `cumulative_mint - cumulative_burn`, representing
174      /// the net contribution to circulating supply.
175      ///
176      /// Returns `None` if cumulative_burn exceeds cumulative_mint
177      /// (which should not happen in normal operation).
178      pub fn net_mint(&self) -> Option<AxAmount> {
179          self.cumulative_mint.checked_sub(self.cumulative_burn)
180      }
181  
182      /// Records a mint operation, updating cumulative_mint.
183      ///
184      /// Returns the new cumulative mint value, or `None` on overflow.
185      ///
186      /// # Arguments
187      ///
188      /// * `amount` - The amount minted in this operation
189      pub fn record_mint(&mut self, amount: AxAmount) -> Option<AxAmount> {
190          let new_total = self.cumulative_mint.checked_add(amount)?;
191          self.cumulative_mint = new_total;
192          Some(new_total)
193      }
194  
195      /// Records a burn operation, updating cumulative_burn.
196      ///
197      /// Returns the new cumulative burn value, or `None` on overflow.
198      ///
199      /// # Arguments
200      ///
201      /// * `amount` - The amount burned in this operation
202      pub fn record_burn(&mut self, amount: AxAmount) -> Option<AxAmount> {
203          let new_total = self.cumulative_burn.checked_add(amount)?;
204          self.cumulative_burn = new_total;
205          Some(new_total)
206      }
207  
208      /// Suspends this governor.
209      ///
210      /// Returns `true` if the suspension was successful (governor was Active).
211      /// Returns `false` if the governor was already Suspended or Removed.
212      pub fn suspend(&mut self) -> bool {
213          if self.status == GovernorStatus::Active {
214              self.status = GovernorStatus::Suspended;
215              true
216          } else {
217              false
218          }
219      }
220  
221      /// Restores this governor to Active status.
222      ///
223      /// Returns `true` if the restoration was successful (governor was Suspended).
224      /// Returns `false` if the governor was Active or Removed.
225      pub fn restore(&mut self) -> bool {
226          if self.status.can_restore() {
227              self.status = GovernorStatus::Active;
228              true
229          } else {
230              false
231          }
232      }
233  
234      /// Permanently removes this governor.
235      ///
236      /// Returns `true` if the removal was successful (governor was not already Removed).
237      /// Returns `false` if the governor was already Removed.
238      pub fn remove(&mut self) -> bool {
239          if self.status != GovernorStatus::Removed {
240              self.status = GovernorStatus::Removed;
241              true
242          } else {
243              false
244          }
245      }
246  }
247  
248  impl Default for GovernorRecord {
249      fn default() -> Self {
250          Self {
251              address: String::new(),
252              metadata: Vec::new(),
253              registration_block: 0,
254              status: GovernorStatus::default(),
255              cumulative_mint: AxAmount::ZERO,
256              cumulative_burn: AxAmount::ZERO,
257          }
258      }
259  }
260  
261  #[cfg(test)]
262  mod tests {
263      use super::*;
264  
265      #[test]
266      fn test_governor_status_can_mint() {
267          assert!(GovernorStatus::Active.can_mint());
268          assert!(!GovernorStatus::Suspended.can_mint());
269          assert!(!GovernorStatus::Removed.can_mint());
270      }
271  
272      #[test]
273      fn test_governor_status_can_restore() {
274          assert!(!GovernorStatus::Active.can_restore());
275          assert!(GovernorStatus::Suspended.can_restore());
276          assert!(!GovernorStatus::Removed.can_restore());
277      }
278  
279      #[test]
280      fn test_governor_status_name() {
281          assert_eq!(GovernorStatus::Active.name(), "active");
282          assert_eq!(GovernorStatus::Suspended.name(), "suspended");
283          assert_eq!(GovernorStatus::Removed.name(), "removed");
284      }
285  
286      #[test]
287      fn test_governor_status_display() {
288          assert_eq!(format!("{}", GovernorStatus::Active), "active");
289          assert_eq!(format!("{}", GovernorStatus::Suspended), "suspended");
290          assert_eq!(format!("{}", GovernorStatus::Removed), "removed");
291      }
292  
293      #[test]
294      fn test_governor_record_new() {
295          let record = GovernorRecord::new("gov_addr_123".to_string(), vec![0x01, 0x02, 0x03], 1000);
296  
297          assert_eq!(record.address, "gov_addr_123");
298          assert_eq!(record.metadata, vec![0x01, 0x02, 0x03]);
299          assert_eq!(record.registration_block, 1000);
300          assert_eq!(record.status, GovernorStatus::Active);
301          assert!(record.cumulative_mint.is_zero());
302          assert!(record.cumulative_burn.is_zero());
303          assert!(record.can_mint());
304      }
305  
306      #[test]
307      fn test_governor_record_default() {
308          let record = GovernorRecord::default();
309          assert!(record.address.is_empty());
310          assert!(record.metadata.is_empty());
311          assert_eq!(record.registration_block, 0);
312          assert_eq!(record.status, GovernorStatus::Active);
313      }
314  
315      #[test]
316      fn test_governor_record_mint_operations() {
317          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
318  
319          // Record first mint
320          let result = record.record_mint(AxAmount::from_microcredits(50_000));
321          assert_eq!(result, Some(AxAmount::from_microcredits(50_000)));
322          assert_eq!(record.cumulative_mint.to_microcredits(), 50_000);
323  
324          // Record second mint
325          let result = record.record_mint(AxAmount::from_microcredits(30_000));
326          assert_eq!(result, Some(AxAmount::from_microcredits(80_000)));
327          assert_eq!(record.cumulative_mint.to_microcredits(), 80_000);
328      }
329  
330      #[test]
331      fn test_governor_record_burn_operations() {
332          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
333  
334          // Record mint first
335          record.record_mint(AxAmount::from_microcredits(100_000));
336  
337          // Record burn
338          let result = record.record_burn(AxAmount::from_microcredits(20_000));
339          assert_eq!(result, Some(AxAmount::from_microcredits(20_000)));
340          assert_eq!(record.cumulative_burn.to_microcredits(), 20_000);
341  
342          // Check net mint
343          assert_eq!(record.net_mint(), Some(AxAmount::from_microcredits(80_000)));
344      }
345  
346      #[test]
347      fn test_governor_record_suspend_restore() {
348          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
349  
350          // Initially active
351          assert!(record.can_mint());
352  
353          // Suspend
354          assert!(record.suspend());
355          assert!(!record.can_mint());
356          assert_eq!(record.status, GovernorStatus::Suspended);
357  
358          // Cannot suspend again
359          assert!(!record.suspend());
360  
361          // Restore
362          assert!(record.restore());
363          assert!(record.can_mint());
364          assert_eq!(record.status, GovernorStatus::Active);
365  
366          // Cannot restore when active
367          assert!(!record.restore());
368      }
369  
370      #[test]
371      fn test_governor_record_remove() {
372          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
373  
374          // Remove from active
375          assert!(record.remove());
376          assert!(!record.can_mint());
377          assert_eq!(record.status, GovernorStatus::Removed);
378  
379          // Cannot remove again
380          assert!(!record.remove());
381  
382          // Cannot restore after removal
383          assert!(!record.restore());
384      }
385  
386      #[test]
387      fn test_governor_record_remove_from_suspended() {
388          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
389  
390          record.suspend();
391          assert!(record.remove());
392          assert_eq!(record.status, GovernorStatus::Removed);
393      }
394  
395      #[test]
396      fn test_governor_record_serde() {
397          let record = GovernorRecord::new("gov_addr".to_string(), vec![0xAB, 0xCD], 500);
398  
399          let json = serde_json::to_string(&record).unwrap();
400          let deserialized: GovernorRecord = serde_json::from_str(&json).unwrap();
401  
402          assert_eq!(record, deserialized);
403      }
404  
405      #[test]
406      fn test_governor_record_net_mint_underflow() {
407          let mut record = GovernorRecord::new("gov".to_string(), vec![], 100);
408  
409          // Simulate edge case where burn exceeds mint (shouldn't happen normally)
410          record.cumulative_mint = AxAmount::from_microcredits(50);
411          record.cumulative_burn = AxAmount::from_microcredits(100);
412  
413          assert!(record.net_mint().is_none());
414      }
415  }