waves_rust/model/
alias.rs1use crate::error::{Error, Result};
2use crate::util::ByteWriter;
3use regex::Regex;
4
5const PREFIX: &str = "alias:";
6const MIN_LENGTH: u8 = 4;
7const MAX_LENGTH: u8 = 30;
8const ALPHABET: &str = "-.0-9@_a-z";
9const TYPE: u8 = 2;
10
11#[derive(Clone, Eq, PartialEq, Debug, Hash)]
12pub struct Alias {
13 bytes: Vec<u8>,
14 name: String,
15 full_name: String,
16}
17
18impl Alias {
19 pub fn new(chain_id: u8, name: &str) -> Result<Self> {
20 if Self::is_valid(chain_id, name) {
21 let bytes = ByteWriter::new()
22 .push_byte(TYPE)
23 .push_byte(chain_id)
24 .push_bytes(&mut name.to_owned().into_bytes())
25 .bytes();
26 let name = Self::replace_prefix(chain_id, name);
27 let full_name = format!("{}{}:{}", PREFIX, chain_id as char, &name);
28 return Ok(Self {
29 bytes,
30 name,
31 full_name,
32 });
33 }
34 Err(Error::InvalidAliasName {
35 min_length: MIN_LENGTH,
36 max_length: MAX_LENGTH,
37 alphabet: ALPHABET.to_owned(),
38 prefix: PREFIX.to_owned(),
39 chain_id: chain_id as char,
40 })
41 }
42
43 pub fn chain_id(full_name: String) -> u8 {
44 full_name
45 .replace(PREFIX, "")
46 .chars()
47 .next()
48 .expect("failed to get chain id from alias") as u8
49 }
50
51 pub fn bytes(&self) -> Vec<u8> {
52 self.bytes.clone()
53 }
54
55 pub fn name(&self) -> String {
56 self.name.clone()
57 }
58
59 pub fn full_name(&self) -> String {
60 self.full_name.clone()
61 }
62
63 pub fn is_valid(chain_id: u8, name: &str) -> bool {
64 let name = Self::replace_prefix(chain_id, name);
65 Regex::new(&format!(
66 r"^[{}]{{{},{}}}$",
67 ALPHABET, MIN_LENGTH, MAX_LENGTH
68 ))
69 .expect("invalid regex")
70 .is_match(&name)
71 }
72
73 fn replace_prefix(chain_id: u8, name: &str) -> String {
74 Regex::new(&format!(r"^{}{}:", PREFIX, chain_id as char))
75 .expect("invalid regex")
76 .replace(name, "")
77 .to_string()
78 }
79}
80
81#[cfg(test)]
82mod tests {
83 use crate::model::{Alias, ChainId};
84
85 #[test]
86 fn test_is_valid() {
87 let valid_alias = "alias:T:alias1662650000377".to_owned();
88 assert_eq!(true, Alias::is_valid(ChainId::TESTNET.byte(), &valid_alias));
89 }
90
91 #[test]
92 fn test_is_invalid() {
93 let invalid_alias1 = "alias1662650000377!".to_owned();
94 let invalid_alias2 = "alias 1662650000377".to_owned();
95 let invalid_alias3 = "ali".to_owned();
96 let invalid_alias4 = "alias1662650000377alias166265000037".to_owned();
97 assert_eq!(
98 false,
99 Alias::is_valid(ChainId::TESTNET.byte(), &invalid_alias1)
100 );
101 assert_eq!(
102 false,
103 Alias::is_valid(ChainId::TESTNET.byte(), &invalid_alias2)
104 );
105 assert_eq!(
106 false,
107 Alias::is_valid(ChainId::TESTNET.byte(), &invalid_alias3)
108 );
109 assert_eq!(
110 false,
111 Alias::is_valid(ChainId::TESTNET.byte(), &invalid_alias4)
112 )
113 }
114
115 #[test]
116 fn test_create_alias() {
117 let result = Alias::new(ChainId::TESTNET.byte(), "alias1662650000377");
118 match result {
119 Ok(alias) => {
120 assert_eq!(alias.name(), "alias1662650000377");
121 assert_eq!(alias.full_name(), "alias:T:alias1662650000377");
122 let mut bytes = vec![2, 84];
123 bytes.append(&mut alias.name().into_bytes());
124 assert_eq!(alias.bytes(), bytes);
125 }
126 Err(err) => {
127 println!("{:?}", err);
128 panic!("failed to create alias")
129 }
130 }
131 }
132
133 #[test]
134 fn test_chain_id_from_full_name_alias() {
135 let i = Alias::chain_id("alias:T:alias1662650000377".to_owned());
136 assert_eq!(84, i);
137 }
138}