Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rustfmt.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
##
# rustup run nightly -- rustfmt node/src/main.rs

# max_width = 100
# max_width = 180
# hard_tabs = false
# tab_spaces = 4
# newline_style = "Auto"
Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

394 changes: 394 additions & 0 deletions docs/delegate-info.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions pallets/subtensor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ frame-support = { workspace = true }
frame-system = { workspace = true }
sp-io = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
serde-tuple-vec-map = { workspace = true }
serde_bytes = { workspace = true, features = ["alloc"] }
serde_with = { workspace = true, features = ["macros"] }
Expand Down
22 changes: 22 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,25 @@ pub mod pallet {
pub ip_type: u8,
}

/// Struct for Prometheus.
pub type ChainIdentityOf = ChainIdentity;
/// Data structure for Prometheus information.
#[derive(Encode, Decode, Default, TypeInfo, Clone, PartialEq, Eq, Debug)]
pub struct ChainIdentity {
/// The name of the chain identity
pub name: Vec<u8>,
/// The URL associated with the chain identity
pub url: Vec<u8>,
/// The image representation of the chain identity
pub image: Vec<u8>,
/// The Discord information for the chain identity
pub discord: Vec<u8>,
/// A description of the chain identity
pub description: Vec<u8>,
/// Additional information about the chain identity
pub additional: Vec<u8>,
}

/// ============================
/// ==== Staking + Accounts ====
/// ============================
Expand Down Expand Up @@ -1057,6 +1076,9 @@ pub mod pallet {
PrometheusInfoOf,
OptionQuery,
>;
#[pallet::storage] // --- MAP ( coldkey ) --> identity
pub type Identities<T: Config> =
StorageMap<_, Blake2_128Concat, T::AccountId, ChainIdentityOf, OptionQuery>;

/// =================================
/// ==== Axon / Promo Endpoints =====
Expand Down
36 changes: 36 additions & 0 deletions pallets/subtensor/src/macros/dispatches.rs
Original file line number Diff line number Diff line change
Expand Up @@ -901,5 +901,41 @@ mod dispatches {
Self::do_set_children(origin, hotkey, netuid, children)?;
Ok(().into())
}

/// ---- Set prometheus information for the neuron.
/// # Args:
/// * 'origin': (<T as frame_system::Config>Origin):
/// - The signature of the calling hotkey.
///
/// * 'netuid' (u16):
/// - The u16 network identifier.
///
/// * 'version' (u16):
/// - The bittensor version identifier.
///
/// * 'ip' (u128):
/// - The prometheus ip information as a u128 encoded integer.
///
/// * 'port' (u16):
/// - The prometheus port information as a u16 encoded integer.
///
/// * 'ip_type' (u8):
/// - The ip type v4 or v6.
///
#[pallet::call_index(68)]
#[pallet::weight((Weight::from_parts(45_000_000, 0)
.saturating_add(T::DbWeight::get().reads(4))
.saturating_add(T::DbWeight::get().writes(1)), DispatchClass::Normal, Pays::Yes))]
pub fn set_identity(
origin: OriginFor<T>,
name: Vec<u8>,
url: Vec<u8>,
image: Vec<u8>,
discord: Vec<u8>,
description: Vec<u8>,
additional: Vec<u8>,
) -> DispatchResult {
Self::do_set_identity(origin, name, url, image, discord, description, additional)
}
}
}
2 changes: 2 additions & 0 deletions pallets/subtensor/src/macros/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,5 +168,7 @@ mod errors {
TooManyChildren,
/// Default transaction rate limit exceeded.
TxRateLimitExceeded,
/// Invalid identity.
InvalidIdentity,
}
}
2 changes: 2 additions & 0 deletions pallets/subtensor/src/macros/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,7 @@ mod events {
HotkeyEmissionTempoSet(u64),
/// The network maximum stake has been set
NetworkMaxStakeSet(u16, u64),
/// The identity of a coldkey has been set
ChainIdentitySet(T::AccountId),
}
}
166 changes: 166 additions & 0 deletions pallets/subtensor/src/migrations/migrate_chain_identity.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
use crate::alloc::borrow::ToOwned;
use codec::Decode;
use scale_info::prelude::{string::String, vec::Vec};
use serde::Deserialize;
use sp_core::{crypto::Ss58Codec, ConstU32};
use sp_runtime::{AccountId32, BoundedVec};

use super::*;
use frame_support::{traits::Get, weights::Weight};
use log;

#[derive(Deserialize, Debug)]
struct RegistrationRecordJSON {
address: String,
name: String,
url: String,
description: String,
}

fn string_to_bounded_vec(input: &str) -> Result<BoundedVec<u8, ConstU32<1024>>, &'static str> {
let vec_u8: Vec<u8> = input.to_owned().into_bytes();

// Check if the length is within bounds
if vec_u8.len() > 64 {
return Err("Input string is too long");
}

// Convert to BoundedVec
BoundedVec::<u8, ConstU32<1024>>::try_from(vec_u8)
.map_err(|_| "Failed to convert to BoundedVec")
}

pub fn migrate_set_hotkey_identities<T: Config>() -> Weight {
let migration_name = b"fix_total_coldkey_stake_v7".to_vec();

// Initialize the weight with one read operation.
let mut weight = T::DbWeight::get().reads(1);

// Check if the migration has already run
if HasMigrationRun::<T>::get(&migration_name) {
log::info!(
"Migration '{:?}' has already run. Skipping.",
migration_name
);
return weight;
}
log::info!(
"Running migration '{}'",
String::from_utf8_lossy(&migration_name)
);

// Include the JSON file with delegate info
let data = include_str!("../../../../docs/delegate-info.json");

// Iterate over all the delegate records
if let Ok(delegates) = serde_json::from_str::<Vec<RegistrationRecordJSON>>(data) {
// Iterate through the delegates
for delegate in delegates.iter() {
// Convert fields to bounded vecs
let name_result = string_to_bounded_vec(&delegate.name);
let desc_result = string_to_bounded_vec(&delegate.description);
let url_result = string_to_bounded_vec(&delegate.url);
let hotkey: AccountId32 = match AccountId32::from_ss58check(&delegate.address) {
Ok(account) => account,
Err(_) => {
log::warn!(
"Invalid SS58 address: {:?}. Skipping this delegate.",
delegate.address
);
continue;
}
};
let decoded_hotkey: T::AccountId = match T::AccountId::decode(&mut hotkey.as_ref()) {
Ok(decoded) => decoded,
Err(e) => {
log::warn!("Failed to decode hotkey: {:?}. Skipping this delegate.", e);
continue;
}
};
log::info!("Hotkey unwrapped: {:?}", decoded_hotkey);

// If we should continue with real values.
let mut name: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
let mut description: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
let mut url: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
if let Ok(n) = name_result {
name = n;
}
if let Ok(d) = desc_result {
description = d;
}
if let Ok(u) = url_result {
url = u;
}

// Unwrap the real values.
let image: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
let discord: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();
let additional: BoundedVec<u8, ConstU32<1024>> = BoundedVec::default();

// Create the chain identity.
let identity = ChainIdentityOf {
name: name.into(),
url: url.into(),
image: image.into(),
discord: discord.into(),
description: description.into(),
additional: additional.into(),
};

// Log the identity details
log::info!("Setting identity for hotkey: {:?}", hotkey);
log::info!("Name: {:?}", String::from_utf8_lossy(&identity.name));
log::info!("URL: {:?}", String::from_utf8_lossy(&identity.url));
log::info!("Image: {:?}", String::from_utf8_lossy(&identity.image));
log::info!("Discord: {:?}", String::from_utf8_lossy(&identity.discord));
log::info!(
"Description: {:?}",
String::from_utf8_lossy(&identity.description)
);
log::info!(
"Additional: {:?}",
String::from_utf8_lossy(&identity.additional)
);

// Check validation.
let total_length = identity
.name
.len()
.saturating_add(identity.url.len())
.saturating_add(identity.image.len())
.saturating_add(identity.discord.len())
.saturating_add(identity.description.len())
.saturating_add(identity.additional.len());
let is_valid: bool = total_length <= 256 + 256 + 1024 + 256 + 1024 + 1024
&& identity.name.len() <= 256
&& identity.url.len() <= 256
&& identity.image.len() <= 1024
&& identity.discord.len() <= 256
&& identity.description.len() <= 1024
&& identity.additional.len() <= 1024;
if !is_valid {
continue;
}

// Get the owning coldkey.
let coldkey = Owner::<T>::get(decoded_hotkey.clone());
weight = weight.saturating_add(T::DbWeight::get().reads(1));

// Sink into the map.
Identities::<T>::insert(coldkey.clone(), identity.clone());
weight = weight.saturating_add(T::DbWeight::get().writes(1));
}
}
// Mark the migration as completed
HasMigrationRun::<T>::insert(&migration_name, true);
weight = weight.saturating_add(T::DbWeight::get().writes(1));

log::info!(
"Migration '{:?}' completed. Storage version set to 7.",
String::from_utf8_lossy(&migration_name)
);

// Return the migration weight.
weight
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use super::*;
pub mod migrate_chain_identity;
pub mod migrate_create_root_network;
pub mod migrate_delete_subnet_21;
pub mod migrate_delete_subnet_3;
Expand Down
Loading