mithril_aggregator/http_server/validators/
prover_transactions_hash_validator.rs

1use mithril_common::entities::ClientError;
2
3pub struct ProverTransactionsHashValidator {
4    max_hashes: usize,
5}
6
7impl ProverTransactionsHashValidator {
8    const LABEL: &'static str = "invalid_transaction_hashes";
9
10    pub fn new(max_hashes: usize) -> Self {
11        Self { max_hashes }
12    }
13
14    pub fn validate(&self, hashes: &[String]) -> Result<(), ClientError> {
15        if hashes.len() > self.max_hashes {
16            return Err(ClientError::new(
17                Self::LABEL,
18                format!(
19                    "Transaction hashes list contains more than maximum allowed number of hashes: '{}'",
20                    self.max_hashes
21                ),
22            ));
23        }
24
25        for hash in hashes {
26            if hash.is_empty() {
27                return Err(ClientError::new(
28                    Self::LABEL,
29                    "Transaction hash cannot be empty",
30                ));
31            }
32
33            if hash.chars().count() != 64 {
34                return Err(ClientError::new(
35                    Self::LABEL,
36                    "Transaction hash must have 64 characters",
37                ));
38            }
39
40            if !hash.chars().all(|c| c.is_ascii_hexdigit()) {
41                return Err(ClientError::new(
42                    Self::LABEL,
43                    "Transaction hash must contain only hexadecimal characters",
44                ));
45            }
46        }
47
48        Ok(())
49    }
50}
51
52#[cfg(test)]
53impl Default for ProverTransactionsHashValidator {
54    fn default() -> Self {
55        Self::new(usize::MAX)
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62
63    #[test]
64    fn prover_transactions_hash_validator_return_error_when_empty_hash() {
65        let error = ProverTransactionsHashValidator::default()
66            .validate(&["".to_string()])
67            .expect_err("Should return an error");
68
69        assert_eq!(
70            error,
71            ClientError::new(
72                "invalid_transaction_hashes",
73                "Transaction hash cannot be empty"
74            )
75        );
76    }
77
78    #[test]
79    fn prover_transactions_hash_validator_return_error_when_hash_size_different_than_64() {
80        let error = ProverTransactionsHashValidator::default()
81            .validate(&["abc".to_string()])
82            .expect_err("Should return an error");
83
84        assert_eq!(
85            error,
86            ClientError::new(
87                "invalid_transaction_hashes",
88                "Transaction hash must have 64 characters"
89            )
90        );
91    }
92
93    #[test]
94    fn prover_transactions_hash_validator_return_error_when_hash_contains_non_hexadecimal_characters(
95    ) {
96        for invalid_char in ["g", "x", ";", " ", "à"].iter() {
97            let hash = format!("{}{}", "a".repeat(63), invalid_char);
98            let error = ProverTransactionsHashValidator::default()
99                .validate(&[hash.clone()])
100                .expect_err("Should return an error");
101            assert_eq!(
102                error,
103                ClientError::new(
104                    "invalid_transaction_hashes",
105                    "Transaction hash must contain only hexadecimal characters"
106                ),
107                "Invalid hash: {}",
108                hash
109            );
110        }
111    }
112
113    #[test]
114    fn prover_transactions_hash_validator_when_hash_contains_only_hexadecimal_characters() {
115        ProverTransactionsHashValidator::default()
116            .validate(&[format!("bcd9{}", "a".repeat(60))])
117            .expect("Should succeed");
118    }
119
120    #[test]
121    fn prover_transactions_hash_validator_return_error_when_more_hashes_than_max_allowed() {
122        let transactions_hashes = vec!["a".repeat(64), "b".repeat(64), "c".repeat(64)];
123        let validator = ProverTransactionsHashValidator::new(2);
124
125        let error = validator
126            .validate(&transactions_hashes)
127            .expect_err("Should return an error");
128
129        assert_eq!(
130            error,
131            ClientError::new(
132                "invalid_transaction_hashes",
133                format!(
134                    "Transaction hashes list contains more than maximum allowed number of hashes: '{}'",
135                    validator.max_hashes
136                )
137            )
138        );
139    }
140}