guts_types/
lib.rs

1//! Common types used throughout `guts`.
2//!
3//! This crate provides the core types for the Guts decentralized
4//! code collaboration platform.
5
6mod identity;
7mod repository;
8
9pub use identity::{Identity, PublicKey, Signature};
10pub use repository::{Repository, RepositoryId};
11
12use commonware_utils::hex;
13
14/// The unique namespace prefix used in all signing operations to prevent signature replay attacks.
15pub const NAMESPACE: &[u8] = b"_GUTS";
16
17/// The epoch number used in consensus.
18///
19/// Because Guts does not yet implement reconfiguration (validator set changes),
20/// we hardcode the epoch to 0.
21pub const EPOCH: u64 = 0;
22
23/// The epoch length used in consensus.
24///
25/// Because Guts does not yet implement reconfiguration,
26/// we hardcode the epoch length to u64::MAX.
27pub const EPOCH_LENGTH: u64 = u64::MAX;
28
29/// Message types for the Guts protocol.
30#[repr(u8)]
31pub enum MessageKind {
32    /// Repository update announcement.
33    RepoUpdate = 0,
34    /// Pull request created.
35    PullRequest = 1,
36    /// Issue created.
37    Issue = 2,
38}
39
40impl MessageKind {
41    /// Converts a u8 to a MessageKind.
42    pub fn from_u8(value: u8) -> Option<Self> {
43        match value {
44            0 => Some(Self::RepoUpdate),
45            1 => Some(Self::PullRequest),
46            2 => Some(Self::Issue),
47            _ => None,
48        }
49    }
50
51    /// Converts the MessageKind to a hex string.
52    pub fn to_hex(&self) -> String {
53        match self {
54            Self::RepoUpdate => hex(&[0]),
55            Self::PullRequest => hex(&[1]),
56            Self::Issue => hex(&[2]),
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use super::*;
64
65    #[test]
66    fn test_message_kind_roundtrip() {
67        assert!(matches!(
68            MessageKind::from_u8(0),
69            Some(MessageKind::RepoUpdate)
70        ));
71        assert!(matches!(
72            MessageKind::from_u8(1),
73            Some(MessageKind::PullRequest)
74        ));
75        assert!(matches!(MessageKind::from_u8(2), Some(MessageKind::Issue)));
76        assert!(MessageKind::from_u8(255).is_none());
77    }
78
79    #[test]
80    fn test_message_kind_all_invalid_values() {
81        // Test all values from 3 to 255 are invalid
82        for i in 3..=255u8 {
83            assert!(
84                MessageKind::from_u8(i).is_none(),
85                "Expected None for value {}",
86                i
87            );
88        }
89    }
90
91    #[test]
92    fn test_message_kind_to_hex() {
93        assert_eq!(MessageKind::RepoUpdate.to_hex(), hex(&[0]));
94        assert_eq!(MessageKind::PullRequest.to_hex(), hex(&[1]));
95        assert_eq!(MessageKind::Issue.to_hex(), hex(&[2]));
96    }
97
98    #[test]
99    fn test_namespace_constant() {
100        assert_eq!(NAMESPACE, b"_GUTS");
101        assert_eq!(NAMESPACE.len(), 5);
102    }
103
104    #[test]
105    fn test_epoch_constants() {
106        assert_eq!(EPOCH, 0);
107        assert_eq!(EPOCH_LENGTH, u64::MAX);
108    }
109}