iota_validation/
input_validator.rs1use regex::Regex;
2
3use iota_constants;
4use iota_model::*;
5
6lazy_static! {
7 static ref TRYTE_REGEX: Regex = Regex::new("^[A-Z9]*$").expect("Failed to parse regex");
8 static ref NINE_TRYTE_REGEX: Regex = Regex::new("^[9]*$").expect("Failed to parse regex");
9}
10
11pub fn is_address(address: &str) -> bool {
13 address.len() == iota_constants::ADDRESS_LENGTH_WITHOUT_CHECKSUM
14 || address.len() == iota_constants::ADDRESS_LENGTH_WITH_CHECKSUM && is_trytes(address)
15}
16
17pub fn is_addresses_collection_valid(addresses: &[String]) -> bool {
19 for address in addresses {
20 if !is_address(&address) {
21 return false;
22 }
23 }
24 true
25}
26
27pub fn is_trytes(trytes: &str) -> bool {
29 TRYTE_REGEX.is_match(trytes)
30}
31
32pub fn is_nine_trytes(trytes: &str) -> bool {
34 NINE_TRYTE_REGEX.is_match(trytes)
35}
36
37pub fn is_trytes_with_length(trytes: &str, len: usize) -> bool {
39 trytes.len() == len && TRYTE_REGEX.is_match(trytes)
40}
41
42pub fn is_value(value: &str) -> bool {
44 match value.parse::<i64>() {
45 Ok(_val) => true,
46 Err(_e) => match value.parse::<u64>() {
47 Ok(_val) => true,
48 Err(_e) => false,
49 },
50 }
51}
52
53pub fn is_array_of_trytes<T: AsRef<str>>(trytes: &[T]) -> bool {
55 if trytes.is_empty() {
56 return false;
57 }
58 for tryte in trytes {
59 if !is_trytes(&tryte.as_ref()) {
60 return false;
61 }
62 }
63 true
64}
65
66pub fn is_array_of_hashes<T: AsRef<str>>(hashes: &[T]) -> bool {
68 if hashes.is_empty() {
69 return false;
70 }
71 for hash in hashes {
72 let hash = hash.as_ref();
73 match hash.len() {
74 90 => {
75 if !is_trytes(&hash[0..90]) {
76 return false;
77 }
78 }
79 81 => {
80 if !is_trytes(&hash[0..81]) {
81 return false;
82 }
83 }
84 _ => return false,
85 }
86 }
87 true
88}
89
90pub fn is_valid_transfer(transfer: &Transfer) -> bool {
92 is_address(&transfer.address) && is_trytes(&transfer.message) && is_trytes(&transfer.tag)
93}
94
95pub fn is_transfers_collection_valid(transfers: &[Transfer]) -> bool {
97 if transfers.is_empty() {
98 return false;
99 }
100 for transfer in transfers {
101 if !is_valid_transfer(&transfer) {
102 return false;
103 }
104 }
105 true
106}
107
108pub fn is_slice_of_transactions(bundle: &[Transaction]) -> bool {
110 if bundle.is_empty() {
111 return false;
112 }
113
114 let mut valid = true;
115 for tx in bundle {
116 if tx.hash == "" {
117 return false;
118 }
119 valid &= is_hash(&tx.hash);
120 if tx.signature_fragments == "" {
121 return false;
122 }
123 valid &= is_trytes(&tx.signature_fragments);
124 if tx.address == "" {
125 return false;
126 }
127 valid &= is_hash(&tx.address);
128 if tx.tag == "" {
129 return false;
130 }
131 valid &= is_trytes(&tx.tag);
132 if tx.obsolete_tag == "" {
133 return false;
134 }
135 valid &= is_trytes(&tx.obsolete_tag);
136 if tx.bundle == "" {
137 return false;
138 }
139 valid &= is_hash(&tx.bundle);
140 if tx.trunk_transaction == "" {
141 return false;
142 }
143 valid &= is_hash(&tx.trunk_transaction);
144 if tx.branch_transaction == "" {
145 return false;
146 }
147 valid &= is_hash(&tx.branch_transaction);
148 if tx.nonce == "" {
149 return false;
150 }
151 valid &= is_trytes(&tx.nonce);
152 if !valid {
153 return false;
154 }
155 }
156 valid
157}
158
159pub fn is_valid_seed(seed: &str) -> bool {
161 is_trytes(seed)
162}
163
164pub fn is_hash(hash: &str) -> bool {
166 if hash.len() == 81 {
167 return is_trytes(&hash[0..81]);
168 }
169 false
170}
171
172pub fn is_hashes(hashes: &[String]) -> bool {
174 for hash in hashes {
175 if !is_trytes(&hash[0..81]) {
176 return false;
177 }
178 }
179 true
180}
181
182pub fn is_array_of_attached_trytes(trytes: &[String]) -> bool {
184 if trytes.is_empty() {
185 return false;
186 }
187 for tryte_value in trytes {
188 if tryte_value.len() != 2673 {
189 return false;
190 }
191 if !is_trytes(&tryte_value[0..2673]) {
192 return false;
193 }
194 if is_nine_trytes(&tryte_value[2673 - (3 * 81)..]) {
195 return false;
196 }
197 }
198 true
199}
200
201#[cfg(test)]
202mod tests {
203 use super::*;
204
205 const TEST_ADDRESS_WITHOUT_CHECKSUM: &str = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA";
206 const TEST_ADDRESS_WITH_CHECKSUM: &str = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA";
207 const TEST_TRYTES: &str = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999";
208 const TEST_HASH: &str =
209 "OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999";
210 const TEST_MESSAGE: &str = "JOTA";
211 const TEST_TAG: &str = "JOTASPAM9999999999999999999";
212
213 #[test]
214 fn test_is_address() {
215 assert!(is_address(TEST_ADDRESS_WITHOUT_CHECKSUM))
216 }
217
218 #[test]
219 fn test_is_trytes() {
220 assert!(is_trytes(TEST_TRYTES))
221 }
222
223 #[test]
224 fn test_is_value() {
225 assert!(is_value("1234"));
226 }
227
228 #[test]
229 fn test_is_array_of_hashes() {
230 assert!(is_array_of_hashes(&vec![
231 TEST_HASH.to_string(),
232 TEST_HASH.to_string(),
233 ]));
234 }
235
236 #[test]
237 fn test_is_array_of_trytes() {
238 assert!(is_array_of_trytes(&vec![
239 TEST_TRYTES.to_string(),
240 TEST_TRYTES.to_string(),
241 ]));
242 }
243
244 #[test]
245 fn test_is_nine_trytes() {
246 assert!(is_nine_trytes("999999999"));
247 }
248
249 #[test]
250 fn test_is_valid_transfer() {
251 let mut t = Transfer::default();
252 t.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
253 t.value = 0;
254 t.message = TEST_MESSAGE.to_string();
255 t.tag = TEST_TAG.to_string();
256 assert!(is_valid_transfer(&t));
257 }
258
259 #[test]
260 fn test_is_transfers_collection_valid() {
261 let mut t = Transfer::default();
262 t.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
263 t.value = 0;
264 t.message = TEST_MESSAGE.to_string();
265 t.tag = TEST_TAG.to_string();
266
267 let mut t2 = Transfer::default();
268 t2.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
269 t2.value = 0;
270 t2.message = "".to_string();
271
272 let transfers = vec![t, t2];
273 assert!(is_transfers_collection_valid(&transfers));
274 }
275}