Skip to content

Commit 1a88e73

Browse files
author
Samuel Dare
committed
Merge remote-tracking branch 'origin/devnet-ready' into feat/childkey_take
2 parents 06013f8 + a03ce30 commit 1a88e73

File tree

24 files changed

+1563
-148
lines changed

24 files changed

+1563
-148
lines changed

.rustfmt.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
##
77
# rustup run nightly -- rustfmt node/src/main.rs
88

9-
# max_width = 100
9+
# max_width = 180
1010
# hard_tabs = false
1111
# tab_spaces = 4
1212
# newline_style = "Auto"

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/delegate-info.json

Lines changed: 394 additions & 0 deletions
Large diffs are not rendered by default.

pallets/subtensor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ frame-support = { workspace = true }
2828
frame-system = { workspace = true }
2929
sp-io = { workspace = true }
3030
serde = { workspace = true, features = ["derive"] }
31+
serde_json = { workspace = true }
3132
serde-tuple-vec-map = { workspace = true }
3233
serde_bytes = { workspace = true, features = ["alloc"] }
3334
serde_with = { workspace = true, features = ["macros"] }
@@ -83,6 +84,7 @@ std = [
8384
"serde_with/std",
8485
"substrate-fixed/std",
8586
"num-traits/std",
87+
"serde_json/std"
8688
]
8789
runtime-benchmarks = [
8890
"frame-benchmarking/runtime-benchmarks",

pallets/subtensor/src/lib.rs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ pub mod staking;
4444
pub mod subnets;
4545
pub mod swap;
4646
pub mod utils;
47-
use crate::utils::TransactionType;
47+
use crate::utils::rate_limiting::TransactionType;
4848
use macros::{config, dispatches, errors, events, genesis, hooks};
4949

5050
// apparently this is stabilized since rust 1.36
@@ -133,6 +133,25 @@ pub mod pallet {
133133
pub ip_type: u8,
134134
}
135135

136+
/// Struct for Prometheus.
137+
pub type ChainIdentityOf = ChainIdentity;
138+
/// Data structure for Prometheus information.
139+
#[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
140+
pub struct ChainIdentity {
141+
/// The name of the chain identity
142+
pub name: Vec<u8>,
143+
/// The URL associated with the chain identity
144+
pub url: Vec<u8>,
145+
/// The image representation of the chain identity
146+
pub image: Vec<u8>,
147+
/// The Discord information for the chain identity
148+
pub discord: Vec<u8>,
149+
/// A description of the chain identity
150+
pub description: Vec<u8>,
151+
/// Additional information about the chain identity
152+
pub additional: Vec<u8>,
153+
}
154+
136155
/// ============================
137156
/// ==== Staking + Accounts ====
138157
/// ============================
@@ -580,6 +599,15 @@ pub mod pallet {
580599
/// ============================
581600
/// ==== Staking Variables ====
582601
/// ============================
602+
/// The Subtensor [`TotalIssuance`] represents the total issuance of tokens on the Bittensor network.
603+
///
604+
/// It is comprised of three parts:
605+
/// - The total amount of issued tokens, tracked in the TotalIssuance of the Balances pallet
606+
/// - The total amount of tokens staked in the system, tracked in [`TotalStake`]
607+
/// - The total amount of tokens locked up for subnet reg, tracked in [`TotalSubnetLocked`] attained by iterating over subnet lock.
608+
///
609+
/// Eventually, Bittensor should migrate to using Holds afterwhich time we will not require this
610+
/// separate accounting.
583611
#[pallet::storage] // --- ITEM ( total_issuance )
584612
pub type TotalIssuance<T> = StorageValue<_, u64, ValueQuery, DefaultTotalIssuance<T>>;
585613
#[pallet::storage] // --- ITEM ( total_stake )
@@ -1086,6 +1114,9 @@ pub mod pallet {
10861114
PrometheusInfoOf,
10871115
OptionQuery,
10881116
>;
1117+
#[pallet::storage] // --- MAP ( coldkey ) --> identity
1118+
pub type Identities<T: Config> =
1119+
StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOf, OptionQuery>;
10891120

10901121
/// =================================
10911122
/// ==== Axon / Promo Endpoints =====

pallets/subtensor/src/macros/dispatches.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,5 +977,41 @@ mod dispatches {
977977
Self::do_set_children(origin, hotkey, netuid, children)?;
978978
Ok(().into())
979979
}
980+
981+
/// ---- Set prometheus information for the neuron.
982+
/// # Args:
983+
/// * 'origin': (<T as frame_system::Config>Origin):
984+
/// - The signature of the calling hotkey.
985+
///
986+
/// * 'netuid' (u16):
987+
/// - The u16 network identifier.
988+
///
989+
/// * 'version' (u16):
990+
/// - The bittensor version identifier.
991+
///
992+
/// * 'ip' (u128):
993+
/// - The prometheus ip information as a u128 encoded integer.
994+
///
995+
/// * 'port' (u16):
996+
/// - The prometheus port information as a u16 encoded integer.
997+
///
998+
/// * 'ip_type' (u8):
999+
/// - The ip type v4 or v6.
1000+
///
1001+
#[pallet::call_index(68)]
1002+
#[pallet::weight((Weight::from_parts(45_000_000, 0)
1003+
.saturating_add(T::DbWeight::get().reads(4))
1004+
.saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::Yes))]
1005+
pub fn set_identity(
1006+
origin: OriginFor<T>,
1007+
name: Vec<u8>,
1008+
url: Vec<u8>,
1009+
image: Vec<u8>,
1010+
discord: Vec<u8>,
1011+
description: Vec<u8>,
1012+
additional: Vec<u8>,
1013+
) -> DispatchResult {
1014+
Self::do_set_identity(origin, name, url, image, discord, description, additional)
1015+
}
9801016
}
9811017
}

pallets/subtensor/src/macros/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,5 +172,7 @@ mod errors {
172172
InvalidChildkeyTake,
173173
/// Childkey take rate limit exceeded.
174174
TxChildkeyTakeRateLimitExceeded,
175+
/// Invalid identity.
176+
InvalidIdentity,
175177
}
176178
}

pallets/subtensor/src/macros/events.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,5 +185,7 @@ mod events {
185185
HotkeyEmissionTempoSet(u64),
186186
/// The network maximum stake has been set
187187
NetworkMaxStakeSet(u16, u64),
188+
/// The identity of a coldkey has been set
189+
ChainIdentitySet(T::AccountId),
188190
}
189191
}

pallets/subtensor/src/macros/hooks.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,8 +68,16 @@ mod hooks {
6868
.saturating_add(migrations::migrate_populate_staking_hotkeys::migrate_populate_staking_hotkeys::<T>())
6969
// Fix total coldkey stake.
7070
// Storage version v8 -> v9
71-
.saturating_add(migrations::migrate_fix_total_coldkey_stake::migrate_fix_total_coldkey_stake::<T>());
71+
.saturating_add(migrations::migrate_fix_total_coldkey_stake::migrate_fix_total_coldkey_stake::<T>())
72+
// Migrate Delegate Ids on chain
73+
.saturating_add(migrations::migrate_chain_identity::migrate_set_hotkey_identities::<T>());
7274
weight
7375
}
76+
77+
#[cfg(feature = "try-runtime")]
78+
fn try_state(_n: BlockNumberFor<T>) -> Result<(), sp_runtime::TryRuntimeError> {
79+
Self::check_accounting_invariants()?;
80+
Ok(())
81+
}
7482
}
7583
}
Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
use crate::alloc::borrow::ToOwned;
2+
use codec::Decode;
3+
use scale_info::prelude::{string::String, vec::Vec};
4+
use serde::Deserialize;
5+
use sp_core::{crypto::Ss58Codec, ConstU32};
6+
use sp_runtime::{AccountId32, BoundedVec};
7+
8+
use super::*;
9+
use frame_support::{traits::Get, weights::Weight};
10+
use log;
11+
12+
#[derive(Deserialize, Debug)]
13+
struct RegistrationRecordJSON {
14+
address: String,
15+
name: String,
16+
url: String,
17+
description: String,
18+
}
19+
20+
fn string_to_bounded_vec(input: &str) -> Result<BoundedVec<u8, ConstU32<1024>>, &'static str> {
21+
let vec_u8: Vec<u8> = input.to_owned().into_bytes();
22+
23+
// Check if the length is within bounds
24+
if vec_u8.len() > 64 {
25+
return Err("Input string is too long");
26+
}
27+
28+
// Convert to BoundedVec
29+
BoundedVec::<u8, ConstU32<1024>>::try_from(vec_u8)
30+
.map_err(|_| "Failed to convert to BoundedVec")
31+
}
32+
33+
pub fn migrate_set_hotkey_identities<T: Config>() -> Weight {
34+
let migration_name = b"migrate_identities".to_vec();
35+
36+
// Initialize the weight with one read operation.
37+
let mut weight = T::DbWeight::get().reads(1);
38+
39+
// Check if the migration has already run
40+
if HasMigrationRun::<T>::get(&migration_name) {
41+
log::info!(
42+
"Migration '{:?}' has already run. Skipping.",
43+
migration_name
44+
);
45+
return weight;
46+
}
47+
log::info!(
48+
"Running migration '{}'",
49+
String::from_utf8_lossy(&migration_name)
50+
);
51+
52+
// Include the JSON file with delegate info
53+
let data = include_str!("../../../../docs/delegate-info.json");
54+
55+
// Iterate over all the delegate records
56+
if let Ok(delegates) = serde_json::from_str::<Vec<RegistrationRecordJSON>>(data) {
57+
// Iterate through the delegates
58+
for delegate in delegates.iter() {
59+
// Convert fields to bounded vecs
60+
let name_result = string_to_bounded_vec(&delegate.name);
61+
let desc_result = string_to_bounded_vec(&delegate.description);
62+
let url_result = string_to_bounded_vec(&delegate.url);
63+
let hotkey: AccountId32 = match AccountId32::from_ss58check(&delegate.address) {
64+
Ok(account) => account,
65+
Err(_) => {
66+
log::warn!(
67+
"Invalid SS58 address: {:?}. Skipping this delegate.",
68+
delegate.address
69+
);
70+
continue;
71+
}
72+
};
73+
let decoded_hotkey: T::AccountId = match T::AccountId::decode(&mut hotkey.as_ref()) {
74+
Ok(decoded) => decoded,
75+
Err(e) => {
76+
log::warn!("Failed to decode hotkey: {:?}. Skipping this delegate.", e);
77+
continue;
78+
}
79+
};
80+
log::info!("Hotkey unwrapped: {:?}", decoded_hotkey);
81+
82+
// If we should continue with real values.
83+
let mut name: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
84+
let mut description: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
85+
let mut url: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
86+
if let Ok(n) = name_result {
87+
name = n;
88+
}
89+
if let Ok(d) = desc_result {
90+
description = d;
91+
}
92+
if let Ok(u) = url_result {
93+
url = u;
94+
}
95+
96+
// Unwrap the real values.
97+
let image: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
98+
let discord: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
99+
let additional: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
100+
101+
// Create the chain identity.
102+
let identity = ChainIdentityOf {
103+
name: name.into(),
104+
url: url.into(),
105+
image: image.into(),
106+
discord: discord.into(),
107+
description: description.into(),
108+
additional: additional.into(),
109+
};
110+
111+
// Log the identity details
112+
log::info!("Setting identity for hotkey: {:?}", hotkey);
113+
log::info!("Name: {:?}", String::from_utf8_lossy(&identity.name));
114+
log::info!("URL: {:?}", String::from_utf8_lossy(&identity.url));
115+
log::info!("Image: {:?}", String::from_utf8_lossy(&identity.image));
116+
log::info!("Discord: {:?}", String::from_utf8_lossy(&identity.discord));
117+
log::info!(
118+
"Description: {:?}",
119+
String::from_utf8_lossy(&identity.description)
120+
);
121+
log::info!(
122+
"Additional: {:?}",
123+
String::from_utf8_lossy(&identity.additional)
124+
);
125+
126+
// Check validation.
127+
let total_length = identity
128+
.name
129+
.len()
130+
.saturating_add(identity.url.len())
131+
.saturating_add(identity.image.len())
132+
.saturating_add(identity.discord.len())
133+
.saturating_add(identity.description.len())
134+
.saturating_add(identity.additional.len());
135+
let is_valid: bool = total_length <= 256 + 256 + 1024 + 256 + 1024 + 1024
136+
&& identity.name.len() <= 256
137+
&& identity.url.len() <= 256
138+
&& identity.image.len() <= 1024
139+
&& identity.discord.len() <= 256
140+
&& identity.description.len() <= 1024
141+
&& identity.additional.len() <= 1024;
142+
if !is_valid {
143+
log::info!("Bytes not correct");
144+
continue;
145+
}
146+
147+
// Get the owning coldkey.
148+
let coldkey = Owner::<T>::get(decoded_hotkey.clone());
149+
log::info!("ColdKey: {:?}", decoded_hotkey);
150+
151+
weight = weight.saturating_add(T::DbWeight::get().reads(1));
152+
153+
// Sink into the map.
154+
Identities::<T>::insert(coldkey.clone(), identity.clone());
155+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
156+
}
157+
} else {
158+
log::info!("Failed to decode JSON");
159+
}
160+
// Mark the migration as completed
161+
HasMigrationRun::<T>::insert(&migration_name, true);
162+
weight = weight.saturating_add(T::DbWeight::get().writes(1));
163+
164+
log::info!(
165+
"Migration '{:?}' completed. Storage version set to 7.",
166+
String::from_utf8_lossy(&migration_name)
167+
);
168+
169+
// Return the migration weight.
170+
weight
171+
}

0 commit comments

Comments
 (0)