verifier/
class_hash.rs

1use regex::Regex;
2use std::fmt;
3use thiserror::Error;
4
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
6pub struct ClassHash(String);
7
8#[derive(Error, Debug, Clone, PartialEq)]
9pub enum ClassHashError {
10    #[error("{0} is not valid class hash")]
11    Match(String),
12    #[error("Class hash regex error")]
13    Regex(#[from] regex::Error),
14}
15
16impl ClassHash {
17    const NORMALIZED_LENGTH: usize = 66;
18    const PATTERN: &str = r"^0x[a-fA-F0-9]+$";
19
20    /// # Errors
21    ///
22    /// Will fail if the `raw` dosn't match class hash regex, i.e. it
23    /// has to start with "0x" followed by 64 hexadecimal digits.
24    pub fn new(raw: &str) -> Result<Self, ClassHashError> {
25        let re = Regex::new(Self::PATTERN)?;
26
27        if raw.len() <= Self::NORMALIZED_LENGTH && re.is_match(raw) {
28            Ok(Self(raw.into()))
29        } else {
30            Err(ClassHashError::Match(raw.to_string()))
31        }
32    }
33}
34
35impl fmt::Display for ClassHash {
36    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37        write!(f, "{}", self.0)
38    }
39}
40
41impl AsRef<str> for ClassHash {
42    fn as_ref(&self) -> &str {
43        self.0.as_str()
44    }
45}
46
47impl AsRef<String> for ClassHash {
48    fn as_ref(&self) -> &String {
49        &self.0
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_valid_class_hash_normalized() {
59        let valid_hash = "0x044dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18";
60        assert!(ClassHash::new(valid_hash).is_ok());
61    }
62
63    #[test]
64    fn test_valid_class_hash_without_leading_zeros() {
65        let valid_hash = "0x44dc2b3239382230d8b1e943df23b96f52eebcac93efe6e8bde92f9a2f1da18";
66        assert!(ClassHash::new(valid_hash).is_ok());
67    }
68
69    #[test]
70    fn test_invalid_class_hash_pattern() {
71        let invalid_hash = "0xGHIJKLMNOPQRSTUVWXYZ";
72        assert!(ClassHash::new(invalid_hash).is_err());
73    }
74
75    #[test]
76    fn test_invalid_class_hash_no_prefix() {
77        let invalid_hash = "1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef";
78        assert!(ClassHash::new(invalid_hash).is_err());
79    }
80}