Skip to content
Closed
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
4 changes: 4 additions & 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.

4 changes: 4 additions & 0 deletions pallets/registry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ scale-info = { workspace = true, features = ["derive"] }
frame-benchmarking = { workspace = true, optional = true }
frame-support = { workspace = true }
frame-system = { workspace = true }
log = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
sp-core = { workspace = true }
sp-runtime = { workspace = true }
sp-std = { workspace = true }
enumflags2 = { workspace = true }
Expand Down
22 changes: 22 additions & 0 deletions pallets/registry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
mod tests;

mod benchmarking;
pub mod migration;
pub mod types;
pub mod weights;
pub mod utils;

pub use pallet::*;
pub use types::*;
Expand Down Expand Up @@ -107,6 +109,26 @@ pub mod pallet {
OptionQuery,
>;

#[pallet::hooks]
impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
fn on_runtime_upgrade() -> frame_support::weights::Weight {
// --- Migrate storage
use crate::migration;
let mut weight = frame_support::weights::Weight::from_parts(0, 0);

weight = weight
// Initializes storage version (to 1)
.saturating_add(migration::migrate_set_hotkey_identities::<T>());

log::info!(
"Runtime upgrade migration in registry pallet, total weight = ({})",
weight
);

weight
}
}

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Register an identity for an account. This will overwrite any existing identity.
Expand Down
137 changes: 137 additions & 0 deletions pallets/registry/src/migration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@

use scale_info::prelude::{ string::{ String, ToString }, vec::Vec };
use serde::Deserialize;
use sp_core::{crypto::Ss58Codec, ConstU32};
use sp_runtime::{AccountId32, BoundedVec};
use sp_std::vec;
use codec::Decode;

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


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

fn string_to_bounded_vec(input: &String) -> Result<BoundedVec<u8, ConstU32<64>>, &'static str> {
let vec_u8: Vec<u8> = input.clone().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<64>>::try_from(vec_u8).map_err(|_| "Failed to convert to BoundedVec")
}

pub fn migrate_set_hotkey_identities<T: Config>() -> Weight {
let new_storage_version = 1;
let migration_name = "set hotkey identities";
let mut weight = T::DbWeight::get().reads_writes(1, 1);

let title = "description".to_string();

let onchain_version = Pallet::<T>::on_chain_storage_version();
log::info!("Current on-chain storage version: {:?}", onchain_version);
if onchain_version < new_storage_version {
log::info!("Starting migration: {}.", migration_name);

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

// Deserialize the JSON data into a HashMap
if let Ok(delegates) = serde_json::from_str::<Vec<RegistrationRecordJSON>>(data) {

log::info!("{} delegate records loaded", delegates.len());

// 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);

// Convert string address into AccountID
let maybe_account_id_32 = AccountId32::from_ss58check(&delegate.address);
let account_id = if maybe_account_id_32.is_ok() {
let account_id_32 = maybe_account_id_32.unwrap();
if let Ok(acc_id) = T::AccountId::decode(&mut account_id_32.as_ref()) {
Some(acc_id)
} else {
None
}
} else {
None
};

if name_result.is_ok() && desc_result.is_ok() && url_result.is_ok()
&& account_id.is_some()
{
let desc_title = Data::Raw(string_to_bounded_vec(&title).unwrap());
let desc_data = Data::Raw(desc_result.unwrap());
let desc_item = BoundedVec::try_from(vec![(desc_title, desc_data)]).unwrap();

let info: IdentityInfo<T::MaxAdditionalFields> = IdentityInfo {
display: Data::Raw(name_result.unwrap()),
additional: desc_item,
legal: Data::None,
web: Data::Raw(url_result.unwrap()),
riot: Data::None,
email: Data::None,
pgp_fingerprint: None,
image: Data::None,
twitter: Data::None,
};

// Insert delegate hotkeys info
let reg: Registration<BalanceOf<T>, T::MaxAdditionalFields> = Registration {
deposit: Zero::zero(),
info,
};

IdentityOf::<T>::insert(account_id.unwrap(), reg);
weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1));

} else {
log::info!("Migration {} couldn't be completed, bad JSON item for: {}", migration_name, delegate.address);
if !name_result.is_ok() {
log::info!("Name is bad");
}
if !desc_result.is_ok() {
log::info!("Description is bad");
}
if !url_result.is_ok() {
log::info!("URL is bad");
}
if !account_id.is_some() {
log::info!("Account ID is bad");
}
}

}


} else {
log::info!("Migration {} couldn't be completed, bad JSON file: {}", migration_name, data);
return weight;
}


StorageVersion::new(new_storage_version).put::<Pallet<T>>();
} else {
log::info!("Migration already done: {}", migration_name);
}

log::info!("Final weight: {:?}", weight);
weight
}
32 changes: 32 additions & 0 deletions pallets/registry/src/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use super::*;
use sp_std::vec::Vec;

impl<T: Config> Pallet<T> {
pub fn set_identity_of(account: &T::AccountId, reg: Registration<BalanceOf<T>, T::MaxAdditionalFields>) {
IdentityOf::<T>::insert(account, reg);
}

pub fn get_identity_of(account: &T::AccountId) -> Option<IdentityInfo<T::MaxAdditionalFields>> {
if let Some(value) = IdentityOf::<T>::get(account) {
return Some(value.info);
}

None
}

pub fn get_all_identities() -> Vec<IdentityInfo<T::MaxAdditionalFields>> {
let mut identities = Vec::<IdentityInfo<T::MaxAdditionalFields>>::new();
for id in IdentityOf::<T>::iter_keys() {
let delegate_id = Self::get_identity_of(&id);

match delegate_id {
Some(identity) => {
identities.push(identity);
}
None => continue,
}
}

identities
}
}
1 change: 1 addition & 0 deletions pallets/subtensor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pallet-transaction-payment = { workspace = true }
pallet-utility = { workspace = true }
ndarray = { workspace = true }
hex = { workspace = true }
pallet-registry= { default-features = false, path = "../registry" }

# Used for sudo decentralization
pallet-collective = { version = "4.0.0-dev", default-features = false, path = "../collective" }
Expand Down
23 changes: 23 additions & 0 deletions pallets/subtensor/rpc/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ pub trait SubtensorCustomApi<BlockHash> {
delegatee_account_vec: Vec<u8>,
at: Option<BlockHash>,
) -> RpcResult<Vec<u8>>;
#[method(name = "delegateInfo_getDelegateIdentity")]
fn get_delegate_identity(&self, delegatee_account_vec: Vec<u8>, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;

#[method(name = "delegateInfo_getDelegateIdentities")]
fn get_delegate_identities(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;

#[method(name = "neuronInfo_getNeuronsLite")]
fn get_neurons_lite(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
Expand Down Expand Up @@ -135,6 +140,24 @@ where
})
}

fn get_delegate_identity(&self, delegate_account_vec: Vec<u8>, at: Option<<Block as BlockT>::Hash>) -> RpcResult<Vec<u8>> {
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_delegate_identity(at, delegate_account_vec).map_err(|e| {
Error::RuntimeError(format!("Unable to get delegate identity: {:?}", e)).into()
})
}

fn get_delegate_identities(&self, at: Option<<Block as BlockT>::Hash>) -> RpcResult<Vec<u8>> {
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_delegate_identities(at).map_err(|e| {
Error::RuntimeError(format!("Unable to get delegate identities: {:?}", e)).into()
})
}

fn get_neurons_lite(
&self,
netuid: u16,
Expand Down
2 changes: 2 additions & 0 deletions pallets/subtensor/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ sp_api::decl_runtime_apis! {
fn get_delegates() -> Vec<u8>;
fn get_delegate( delegate_account_vec: Vec<u8> ) -> Vec<u8>;
fn get_delegated( delegatee_account_vec: Vec<u8> ) -> Vec<u8>;
fn get_delegate_identity (delegatee_account_vec: Vec<u8>) -> Vec<u8>;
fn get_delegate_identities() -> Vec<u8>;
}

pub trait NeuronInfoRuntimeApi {
Expand Down
14 changes: 13 additions & 1 deletion pallets/subtensor/src/delegate_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use substrate_fixed::types::U64F64;
extern crate alloc;
use codec::Compact;
use sp_core::hexdisplay::AsBytesRef;
use pallet_registry::{IdentityInfo, Pallet as RegistryPallet};

#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
pub struct DelegateInfo<T: Config> {
Expand All @@ -19,7 +20,7 @@ pub struct DelegateInfo<T: Config> {
total_daily_return: Compact<u64>, // Delegators current daily return
}

impl<T: Config> Pallet<T> {
impl<T: Config + pallet_registry::Config> Pallet<T> {
fn get_delegate_by_existing_account(delegate: AccountIdOf<T>) -> DelegateInfo<T> {
let mut nominators = Vec::<(T::AccountId, Compact<u64>)>::new();

Expand Down Expand Up @@ -130,4 +131,15 @@ impl<T: Config> Pallet<T> {

delegates
}

pub fn get_delegate_identity(delegate_account_vec: Vec<u8>) -> Option<IdentityInfo<T::MaxAdditionalFields>> {
let Ok(delegate) = T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()) else {
return None; // No delegates for invalid account
};
RegistryPallet::<T>::get_identity_of(&delegate)
}

pub fn get_delegate_identities() -> Vec<IdentityInfo<T::MaxAdditionalFields>> {
RegistryPallet::<T>::get_all_identities()
}
}
12 changes: 11 additions & 1 deletion runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ pub const MILLISECS_PER_BLOCK: u64 = 12000;

/// Fast blocks for development
#[cfg(feature = "fast-blocks")]
pub const MILLISECS_PER_BLOCK: u64 = 250;
pub const MILLISECS_PER_BLOCK: u64 = 12000;

// NOTE: Currently it is not possible to change the slot duration after the chain has started.
// Attempting to do so will brick block production.
Expand Down Expand Up @@ -1501,6 +1501,16 @@ impl_runtime_apis! {
let result = SubtensorModule::get_delegated(delegatee_account_vec);
result.encode()
}

fn get_delegate_identity(delegatee_account_vec: Vec<u8>) -> Vec<u8> {
let result = SubtensorModule::get_delegate_identity(delegatee_account_vec);
result.encode()
}

fn get_delegate_identities() -> Vec<u8> {
let result = SubtensorModule::get_delegate_identities();
result.encode()
}
}

impl subtensor_custom_rpc_runtime_api::NeuronInfoRuntimeApi<Block> for Runtime {
Expand Down