-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathutils.rs
172 lines (150 loc) · 4.52 KB
/
utils.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
use pyo3::pyfunction;
use sp_core::crypto::{AccountId32, Ss58Codec};
use std::str;
use crate::keypair::Keypair;
pub(crate) const SS58_FORMAT: u8 = 42;
/// Returns the SS58 format of the given address string.
pub fn get_ss58_format(ss58_address: &str) -> Result<u16, &'static str> {
match <AccountId32 as Ss58Codec>::from_ss58check_with_version(ss58_address) {
Ok((_, format)) => Ok(u16::from(format)),
Err(_) => Err("Invalid SS58 address."),
}
}
/// Checks if the given address is a valid ss58 address.
///
/// Args:
/// address(str): The address to check.
///
/// Returns:
/// True if the address is a valid ss58 address for Bittensor, False otherwise.
#[pyfunction]
pub fn is_valid_ss58_address(address: &str) -> bool {
if address.is_empty() {
// Possibly there could be a debug log, but not a print
// utils::print(format!("The given address is empty"));
return false;
}
sp_core::sr25519::Public::from_ss58check(address).is_ok()
}
/// Checks if the given public_key is a valid ed25519 key.
///
/// Args:
/// public_key: The public_key to check as string.
///
/// Returns:
/// True if the public_key is a valid ed25519 key, False otherwise.
pub fn is_string_valid_ed25519_pubkey(public_key: &str) -> bool {
if public_key.len() != 64 && public_key.len() != 66 {
return false;
}
let pub_key_var = Some(public_key.to_string());
let keypair_result = Keypair::new(None, pub_key_var, None, SS58_FORMAT, None, 1);
match keypair_result {
Ok(keypair) => keypair.ss58_address().is_some(),
Err(_) => false,
}
}
/// Checks if the given public_key is a valid ed25519 key.
///
/// Args:
/// public_key: The public_key to check as bytes.
///
/// Returns:
/// True if the public_key is a valid ed25519 key, False otherwise.
pub fn are_bytes_valid_ed25519_pubkey(public_key: &[u8]) -> bool {
if public_key.len() != 32 {
return false;
}
let pub_key_var = Some(hex::encode(public_key));
let keypair_result = Keypair::new(None, pub_key_var, None, SS58_FORMAT, None, 1);
match keypair_result {
Ok(keypair) => keypair.ss58_address().is_some(),
Err(_) => false,
}
}
/// Checks if the given address is a valid destination address.
///
/// Args:
/// address(Union[str, bytes]): The address to check.
///
/// Returns:
/// True if the address is a valid destination address, False otherwise.
#[pyfunction]
pub fn is_valid_bittensor_address_or_public_key(address: &str) -> bool {
if address.starts_with("0x") {
// Convert hex string to bytes
if let Ok(bytes) = hex::decode(&address[2..]) {
are_bytes_valid_ed25519_pubkey(&bytes)
} else {
is_valid_ss58_address(address)
}
} else {
is_valid_ss58_address(address)
}
}
#[cfg(not(feature = "python-bindings"))]
pub fn print(s: String) {
use std::io::{self, Write};
print!("{}", s);
io::stdout().flush().unwrap();
}
#[cfg(feature = "python-bindings")]
pub fn print(s: String) {
pyo3::Python::with_gil(|py| {
let locals = PyDict::new_bound(py);
locals.set_item("s", s).unwrap();
py.run_bound(
r#"
import sys
print(s, end='')
sys.stdout.flush()
"#,
None,
Some(&locals),
)
.unwrap();
});
}
/// Prompts the user and returns the response, if any.
///
/// Args:
/// prompt: String
///
/// Returns:
/// response: Option<String>
pub fn prompt(prompt: String) -> Option<String> {
use std::io::{self, Write};
print!("{}", prompt);
io::stdout().flush().ok()?;
let mut input = String::new();
match io::stdin().read_line(&mut input) {
Ok(_) => Some(input.trim().to_string()),
Err(_) => None,
}
}
/// Prompts the user with a password entry and returns the response, if any.
///
/// Args:
/// prompt (String): the prompt to ask the user with.
///
/// Returns:
/// response: Option<String>
pub fn prompt_password(prompt: String) -> Option<String> {
use rpassword::read_password;
use std::io::{self, Write};
print!("{}", prompt);
io::stdout().flush().ok()?;
match read_password() {
Ok(password) => Some(password.trim().to_string()),
Err(_) => None,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_ss58_format_success() {
let test_address = "5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty";
assert!(is_valid_ss58_address(test_address));
}
}