use regex::Regex;
use iota_constants;
use iota_model::*;
lazy_static! {
static ref TRYTE_REGEX: Regex = Regex::new("^[A-Z9]*$").expect("Failed to parse regex");
static ref NINE_TRYTE_REGEX: Regex = Regex::new("^[9]*$").expect("Failed to parse regex");
}
/// Validates that the provided string is an address
pub fn is_address(address: &str) -> bool {
address.len() == iota_constants::ADDRESS_LENGTH_WITHOUT_CHECKSUM
|| address.len() == iota_constants::ADDRESS_LENGTH_WITH_CHECKSUM && is_trytes(address)
}
/// Validates that a slice of strings are all addresses
pub fn is_addresses_collection_valid(addresses: &[String]) -> bool {
for address in addresses {
if !is_address(&address) {
return false;
}
}
true
}
/// Validates that a string contains only tryte characters
pub fn is_trytes(trytes: &str) -> bool {
TRYTE_REGEX.is_match(trytes)
}
/// Validates that a string contains only the number 9
pub fn is_nine_trytes(trytes: &str) -> bool {
NINE_TRYTE_REGEX.is_match(trytes)
}
/// Validates that a string contains only tryte characters
pub fn is_trytes_with_length(trytes: &str, len: usize) -> bool {
trytes.len() == len && TRYTE_REGEX.is_match(trytes)
}
/// Validates that a string is an integer
pub fn is_value(value: &str) -> bool {
match value.parse::<i64>() {
Ok(_val) => true,
Err(_e) => match value.parse::<u64>() {
Ok(_val) => true,
Err(_e) => false,
},
}
}
/// Validates that a slice of strings are all valid trytes
pub fn is_array_of_trytes<T: AsRef<str>>(trytes: &[T]) -> bool {
if trytes.is_empty() {
return false;
}
for tryte in trytes {
if !is_trytes(&tryte.as_ref()) {
return false;
}
}
true
}
/// Validates that a slice of strings are all valid hashes
pub fn is_array_of_hashes<T: AsRef<str>>(hashes: &[T]) -> bool {
if hashes.is_empty() {
return false;
}
for hash in hashes {
let hash = hash.as_ref();
match hash.len() {
90 => {
if !is_trytes(&hash[0..90]) {
return false;
}
}
81 => {
if !is_trytes(&hash[0..81]) {
return false;
}
}
_ => return false,
}
}
true
}
/// Validates a transfer
pub fn is_valid_transfer(transfer: &Transfer) -> bool {
is_address(&transfer.address) && is_trytes(&transfer.message) && is_trytes(&transfer.tag)
}
/// Validates a slice of transfers
pub fn is_transfers_collection_valid(transfers: &[Transfer]) -> bool {
if transfers.is_empty() {
return false;
}
for transfer in transfers {
if !is_valid_transfer(&transfer) {
return false;
}
}
true
}
/// Validates a slice of transactions
pub fn is_slice_of_transactions(bundle: &[Transaction]) -> bool {
if bundle.is_empty() {
return false;
}
let mut valid = true;
for tx in bundle {
if tx.hash == "" {
return false;
}
valid &= is_hash(&tx.hash);
if tx.signature_fragments == "" {
return false;
}
valid &= is_trytes(&tx.signature_fragments);
if tx.address == "" {
return false;
}
valid &= is_hash(&tx.address);
if tx.tag == "" {
return false;
}
valid &= is_trytes(&tx.tag);
if tx.obsolete_tag == "" {
return false;
}
valid &= is_trytes(&tx.obsolete_tag);
if tx.bundle == "" {
return false;
}
valid &= is_hash(&tx.bundle);
if tx.trunk_transaction == "" {
return false;
}
valid &= is_hash(&tx.trunk_transaction);
if tx.branch_transaction == "" {
return false;
}
valid &= is_hash(&tx.branch_transaction);
if tx.nonce == "" {
return false;
}
valid &= is_trytes(&tx.nonce);
if !valid {
return false;
}
}
valid
}
/// Validates that a string is a seed
pub fn is_valid_seed(seed: &str) -> bool {
is_trytes(seed)
}
/// Validates that a string is a hash
pub fn is_hash(hash: &str) -> bool {
if hash.len() == 81 {
return is_trytes(&hash[0..81]);
}
false
}
/// Validates that a slice of strings are all hash
pub fn is_hashes(hashes: &[String]) -> bool {
for hash in hashes {
if !is_trytes(&hash[0..81]) {
return false;
}
}
true
}
/// Validates that a slice of strings contains only attached trytes
pub fn is_array_of_attached_trytes(trytes: &[String]) -> bool {
if trytes.is_empty() {
return false;
}
for tryte_value in trytes {
if tryte_value.len() != 2673 {
return false;
}
if !is_trytes(&tryte_value[0..2673]) {
return false;
}
if is_nine_trytes(&tryte_value[2673 - (3 * 81)..]) {
return false;
}
}
true
}
#[cfg(test)]
mod tests {
use super::*;
const TEST_ADDRESS_WITHOUT_CHECKSUM: &str = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA";
const TEST_ADDRESS_WITH_CHECKSUM: &str = "PNGMCSNRCTRHCHPXYTPKEJYPCOWKOMRXZFHH9N9VDIKMNVAZCMIYRHVJIAZARZTUETJVFDMBEBIQE9QTHBFWDAOEFA";
const TEST_TRYTES: &str = "BYSWEAUTWXHXZ9YBZISEK9LUHWGMHXCGEVNZHRLUWQFCUSDXZHOFHWHL9MQPVJXXZLIXPXPXF9KYEREFSKCPKYIIKPZVLHUTDFQKKVVBBN9ATTLPCNPJDWDEVIYYLGPZGCWXOBDXMLJC9VO9QXTTBLAXTTBFUAROYEGQIVB9MJWJKXJMCUPTWAUGFZBTZCSJVRBGMYXTVBDDS9MYUJCPZ9YDWWQNIPUAIJXXSNLKUBSCOIJPCLEFPOXFJREXQCUVUMKSDOVQGGHRNILCO9GNCLWFM9APMNMWYASHXQAYBEXF9QRIHIBHYEJOYHRQJAOKAQ9AJJFQ9WEIWIJOTZATIBOXQLBMIJU9PCGBLVDDVFP9CFFSXTDUXMEGOOFXWRTLFGV9XXMYWEMGQEEEDBTIJ9OJOXFAPFQXCDAXOUDMLVYRMRLUDBETOLRJQAEDDLNVIRQJUBZBO9CCFDHIX9MSQCWYAXJVWHCUPTRSXJDESISQPRKZAFKFRULCGVRSBLVFOPEYLEE99JD9SEBALQINPDAZHFAB9RNBH9AZWIJOTLBZVIEJIAYGMC9AZGNFWGRSWAXTYSXVROVNKCOQQIWGPNQZKHUNODGYADPYLZZZUQRTJRTODOUKAOITNOMWNGHJBBA99QUMBHRENGBHTH9KHUAOXBVIVDVYYZMSEYSJWIOGGXZVRGN999EEGQMCOYVJQRIRROMPCQBLDYIGQO9AMORPYFSSUGACOJXGAQSPDY9YWRRPESNXXBDQ9OZOXVIOMLGTSWAMKMTDRSPGJKGBXQIVNRJRFRYEZ9VJDLHIKPSKMYC9YEGHFDS9SGVDHRIXBEMLFIINOHVPXIFAZCJKBHVMQZEVWCOSNWQRDYWVAIBLSCBGESJUIBWZECPUCAYAWMTQKRMCHONIPKJYYTEGZCJYCT9ABRWTJLRQXKMWY9GWZMHYZNWPXULNZAPVQLPMYQZCYNEPOCGOHBJUZLZDPIXVHLDMQYJUUBEDXXPXFLNRGIPWBRNQQZJSGSJTTYHIGGFAWJVXWL9THTPWOOHTNQWCNYOYZXALHAZXVMIZE9WMQUDCHDJMIBWKTYH9AC9AFOT9DPCADCV9ZWUTE9QNOMSZPTZDJLJZCJGHXUNBJFUBJWQUEZDMHXGBPTNSPZBR9TGSKVOHMOQSWPGFLSWNESFKSAZY9HHERAXALZCABFYPOVLAHMIHVDBGKUMDXC9WHHTIRYHZVWNXSVQUWCR9M9RAGMFEZZKZ9XEOQGOSLFQCHHOKLDSA9QCMDGCGMRYJZLBVIFOLBIJPROKMHOYTBTJIWUZWJMCTKCJKKTR9LCVYPVJI9AHGI9JOWMIWZAGMLDFJA9WU9QAMEFGABIBEZNNAL9OXSBFLOEHKDGHWFQSHMPLYFCNXAAZYJLMQDEYRGL9QKCEUEJ9LLVUOINVSZZQHCIKPAGMT9CAYIIMTTBCPKWTYHOJIIY9GYNPAJNUJ9BKYYXSV9JSPEXYMCFAIKTGNRSQGUNIYZCRT9FOWENSZQPD9ALUPYYAVICHVYELYFPUYDTWUSWNIYFXPX9MICCCOOZIWRNJIDALWGWRATGLJXNAYTNIZWQ9YTVDBOFZRKO9CFWRPAQQRXTPACOWCPRLYRYSJARRKSQPR9TCFXDVIXLP9XVL99ERRDSOHBFJDJQQGGGCZNDQ9NYCTQJWVZIAELCRBJJFDMCNZU9FIZRPGNURTXOCDSQGXTQHKHUECGWFUUYS9J9NYQ9U9P9UUP9YMZHWWWCIASCFLCMSKTELZWUGCDE9YOKVOVKTAYPHDF9ZCCQAYPJIJNGSHUIHHCOSSOOBUDOKE9CJZGYSSGNCQJVBEFTZFJ9SQUHOASKRRGBSHWKBCBWBTJHOGQ9WOMQFHWJVEG9NYX9KWBTCAIXNXHEBDIOFO9ALYMFGRICLCKKLG9FOBOX9PDWNQRGHBKHGKKRLWTBEQMCWQRLHAVYYZDIIPKVQTHYTWQMTOACXZOQCDTJTBAAUWXSGJF9PNQIJ9AJRUMUVCPWYVYVARKR9RKGOUHHNKNVGGPDDLGKPQNOYHNKAVVKCXWXOQPZNSLATUJT9AUWRMPPSWHSTTYDFAQDXOCYTZHOYYGAIM9CELMZ9AZPWB9MJXGHOKDNNSZVUDAGXTJJSSZCPZVPZBYNNTUQABSXQWZCHDQSLGK9UOHCFKBIBNETK999999999999999999999999999999999999999999999999999999999999999999999999999999999NOXDXXKUDWLOFJLIPQIBRBMGDYCPGDNLQOLQS99EQYKBIU9VHCJVIPFUYCQDNY9APGEVYLCENJIOBLWNB999999999XKBRHUD99C99999999NKZKEKWLDKMJCI9N9XQOLWEPAYWSH9999999999999999999999999KDDTGZLIPBNZKMLTOLOXQVNGLASESDQVPTXALEKRMIOHQLUHD9ELQDBQETS9QFGTYOYWLNTSKKMVJAUXSIROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999IROUICDOXKSYZTDPEDKOQENTJOWJONDEWROCEJIEWFWLUAACVSJFTMCHHXJBJRKAAPUDXXVXFWP9X9999";
const TEST_HASH: &str =
"OAATQS9VQLSXCLDJVJJVYUGONXAXOFMJOZNSYWRZSWECMXAQQURHQBJNLD9IOFEPGZEPEMPXCIVRX9999";
const TEST_MESSAGE: &str = "JOTA";
const TEST_TAG: &str = "JOTASPAM9999999999999999999";
#[test]
fn test_is_address() {
assert!(is_address(TEST_ADDRESS_WITHOUT_CHECKSUM))
}
#[test]
fn test_is_trytes() {
assert!(is_trytes(TEST_TRYTES))
}
#[test]
fn test_is_value() {
assert!(is_value("1234"));
}
#[test]
fn test_is_array_of_hashes() {
assert!(is_array_of_hashes(&vec![
TEST_HASH.to_string(),
TEST_HASH.to_string(),
]));
}
#[test]
fn test_is_array_of_trytes() {
assert!(is_array_of_trytes(&vec![
TEST_TRYTES.to_string(),
TEST_TRYTES.to_string(),
]));
}
#[test]
fn test_is_nine_trytes() {
assert!(is_nine_trytes("999999999"));
}
#[test]
fn test_is_valid_transfer() {
let mut t = Transfer::default();
t.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
t.value = 0;
t.message = TEST_MESSAGE.to_string();
t.tag = TEST_TAG.to_string();
assert!(is_valid_transfer(&t));
}
#[test]
fn test_is_transfers_collection_valid() {
let mut t = Transfer::default();
t.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
t.value = 0;
t.message = TEST_MESSAGE.to_string();
t.tag = TEST_TAG.to_string();
let mut t2 = Transfer::default();
t2.address = TEST_ADDRESS_WITH_CHECKSUM.to_string();
t2.value = 0;
t2.message = "".to_string();
let transfers = vec![t, t2];
assert!(is_transfers_collection_valid(&transfers));
}
}