1use crate::api::api;
6use crate::error::BittensorError;
7use subxt::OnlineClient;
8use subxt::PolkadotConfig;
9
10#[derive(Debug, Clone)]
12pub struct SubnetInfo {
13 pub netuid: u16,
15 pub tempo: u16,
17 pub n: u16,
19 pub max_n: u16,
21 pub immunity_period: u16,
23 pub registration_allowed: bool,
25}
26
27#[derive(Debug, Clone)]
29pub struct SubnetHyperparameters {
30 pub tempo: u16,
32 pub max_n: u16,
34 pub min_allowed_weights: u16,
36 pub max_allowed_weights: u16,
38 pub weights_version_key: u64,
40 pub weights_rate_limit: u64,
42 pub registration_allowed: bool,
44 pub adjustment_interval: u16,
46 pub target_regs_per_interval: u16,
48 pub immunity_period: u16,
50}
51
52pub async fn get_subnet_info(
54 client: &OnlineClient<PolkadotConfig>,
55 netuid: u16,
56) -> Result<SubnetInfo, BittensorError> {
57 let storage = client
58 .storage()
59 .at_latest()
60 .await
61 .map_err(|e| BittensorError::RpcError {
62 message: format!("Failed to get storage: {}", e),
63 })?;
64
65 let tempo = storage
66 .fetch(&api::storage().subtensor_module().tempo(netuid))
67 .await
68 .map_err(|e| BittensorError::StorageQueryError {
69 key: "tempo".to_string(),
70 message: e.to_string(),
71 })?
72 .ok_or(BittensorError::SubnetNotFound { netuid })?;
73
74 let n = storage
75 .fetch(&api::storage().subtensor_module().subnetwork_n(netuid))
76 .await
77 .map_err(|e| BittensorError::StorageQueryError {
78 key: "n".to_string(),
79 message: e.to_string(),
80 })?
81 .unwrap_or(0);
82
83 let max_n = storage
84 .fetch(&api::storage().subtensor_module().max_allowed_uids(netuid))
85 .await
86 .map_err(|e| BittensorError::StorageQueryError {
87 key: "max_n".to_string(),
88 message: e.to_string(),
89 })?
90 .unwrap_or(0);
91
92 let immunity_period = storage
93 .fetch(&api::storage().subtensor_module().immunity_period(netuid))
94 .await
95 .map_err(|e| BittensorError::StorageQueryError {
96 key: "immunity_period".to_string(),
97 message: e.to_string(),
98 })?
99 .unwrap_or(0);
100
101 let registration_allowed = storage
102 .fetch(
103 &api::storage()
104 .subtensor_module()
105 .network_registration_allowed(netuid),
106 )
107 .await
108 .map_err(|e| BittensorError::StorageQueryError {
109 key: "registration_allowed".to_string(),
110 message: e.to_string(),
111 })?
112 .unwrap_or(false);
113
114 Ok(SubnetInfo {
115 netuid,
116 tempo,
117 n,
118 max_n,
119 immunity_period,
120 registration_allowed,
121 })
122}
123
124pub async fn get_subnet_hyperparameters(
126 client: &OnlineClient<PolkadotConfig>,
127 netuid: u16,
128) -> Result<SubnetHyperparameters, BittensorError> {
129 let storage = client
130 .storage()
131 .at_latest()
132 .await
133 .map_err(|e| BittensorError::RpcError {
134 message: format!("Failed to get storage: {}", e),
135 })?;
136
137 let tempo = storage
138 .fetch(&api::storage().subtensor_module().tempo(netuid))
139 .await
140 .map_err(|e| BittensorError::StorageQueryError {
141 key: "tempo".to_string(),
142 message: e.to_string(),
143 })?
144 .ok_or(BittensorError::SubnetNotFound { netuid })?;
145
146 let max_n = storage
147 .fetch(&api::storage().subtensor_module().max_allowed_uids(netuid))
148 .await
149 .map_err(|e| BittensorError::StorageQueryError {
150 key: "max_n".to_string(),
151 message: e.to_string(),
152 })?
153 .unwrap_or(0);
154
155 let min_allowed_weights = storage
156 .fetch(
157 &api::storage()
158 .subtensor_module()
159 .min_allowed_weights(netuid),
160 )
161 .await
162 .map_err(|e| BittensorError::StorageQueryError {
163 key: "min_allowed_weights".to_string(),
164 message: e.to_string(),
165 })?
166 .unwrap_or(0);
167
168 let max_allowed_weights = storage
169 .fetch(&api::storage().subtensor_module().max_weights_limit(netuid))
170 .await
171 .map_err(|e| BittensorError::StorageQueryError {
172 key: "max_allowed_weights".to_string(),
173 message: e.to_string(),
174 })?
175 .unwrap_or(0);
176
177 let weights_version_key = storage
178 .fetch(
179 &api::storage()
180 .subtensor_module()
181 .weights_version_key(netuid),
182 )
183 .await
184 .map_err(|e| BittensorError::StorageQueryError {
185 key: "weights_version_key".to_string(),
186 message: e.to_string(),
187 })?
188 .unwrap_or(0);
189
190 let weights_rate_limit = storage
191 .fetch(
192 &api::storage()
193 .subtensor_module()
194 .weights_set_rate_limit(netuid),
195 )
196 .await
197 .map_err(|e| BittensorError::StorageQueryError {
198 key: "weights_rate_limit".to_string(),
199 message: e.to_string(),
200 })?
201 .unwrap_or(0);
202
203 let registration_allowed = storage
204 .fetch(
205 &api::storage()
206 .subtensor_module()
207 .network_registration_allowed(netuid),
208 )
209 .await
210 .map_err(|e| BittensorError::StorageQueryError {
211 key: "registration_allowed".to_string(),
212 message: e.to_string(),
213 })?
214 .unwrap_or(false);
215
216 let adjustment_interval = storage
217 .fetch(
218 &api::storage()
219 .subtensor_module()
220 .adjustment_interval(netuid),
221 )
222 .await
223 .map_err(|e| BittensorError::StorageQueryError {
224 key: "adjustment_interval".to_string(),
225 message: e.to_string(),
226 })?
227 .unwrap_or(0);
228
229 let target_regs_per_interval = storage
230 .fetch(
231 &api::storage()
232 .subtensor_module()
233 .target_registrations_per_interval(netuid),
234 )
235 .await
236 .map_err(|e| BittensorError::StorageQueryError {
237 key: "target_regs_per_interval".to_string(),
238 message: e.to_string(),
239 })?
240 .unwrap_or(0);
241
242 let immunity_period = storage
243 .fetch(&api::storage().subtensor_module().immunity_period(netuid))
244 .await
245 .map_err(|e| BittensorError::StorageQueryError {
246 key: "immunity_period".to_string(),
247 message: e.to_string(),
248 })?
249 .unwrap_or(0);
250
251 Ok(SubnetHyperparameters {
252 tempo,
253 max_n,
254 min_allowed_weights,
255 max_allowed_weights,
256 weights_version_key,
257 weights_rate_limit,
258 registration_allowed,
259 adjustment_interval,
260 target_regs_per_interval,
261 immunity_period,
262 })
263}
264
265pub async fn get_total_subnets(
267 client: &OnlineClient<PolkadotConfig>,
268) -> Result<u16, BittensorError> {
269 let storage = client
270 .storage()
271 .at_latest()
272 .await
273 .map_err(|e| BittensorError::RpcError {
274 message: format!("Failed to get storage: {}", e),
275 })?;
276
277 let count = storage
278 .fetch(&api::storage().subtensor_module().total_networks())
279 .await
280 .map_err(|e| BittensorError::StorageQueryError {
281 key: "total_networks".to_string(),
282 message: e.to_string(),
283 })?
284 .unwrap_or(0);
285
286 Ok(count)
287}
288
289pub async fn subnet_exists(
291 client: &OnlineClient<PolkadotConfig>,
292 netuid: u16,
293) -> Result<bool, BittensorError> {
294 let storage = client
295 .storage()
296 .at_latest()
297 .await
298 .map_err(|e| BittensorError::RpcError {
299 message: format!("Failed to get storage: {}", e),
300 })?;
301
302 let exists = storage
303 .fetch(&api::storage().subtensor_module().networks_added(netuid))
304 .await
305 .map_err(|e| BittensorError::StorageQueryError {
306 key: "networks_added".to_string(),
307 message: e.to_string(),
308 })?
309 .unwrap_or(false);
310
311 Ok(exists)
312}
313
314#[cfg(test)]
315mod tests {
316 use super::*;
317
318 #[test]
319 fn test_subnet_info_struct() {
320 let info = SubnetInfo {
321 netuid: 1,
322 tempo: 360,
323 n: 256,
324 max_n: 4096,
325 immunity_period: 100,
326 registration_allowed: true,
327 };
328
329 assert_eq!(info.netuid, 1);
330 assert_eq!(info.tempo, 360);
331 }
332
333 #[test]
334 fn test_hyperparameters_struct() {
335 let params = SubnetHyperparameters {
336 tempo: 360,
337 max_n: 4096,
338 min_allowed_weights: 0,
339 max_allowed_weights: 65535,
340 weights_version_key: 0,
341 weights_rate_limit: 100,
342 registration_allowed: true,
343 adjustment_interval: 112,
344 target_regs_per_interval: 2,
345 immunity_period: 100,
346 };
347
348 assert_eq!(params.tempo, 360);
349 assert!(params.registration_allowed);
350 }
351}