Skip to content
Closed
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ manual_inspect = "allow"
async-trait = "0.1"
cargo-husky = { version = "1", default-features = false }
clap = "4.5.4"
codec = { version = "3.2.2", default-features = false }
codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [
"derive",
] }
ed25519-dalek = { version = "2.1.0", default-features = false, features = ["alloc"] }
enumflags2 = "0.7.9"
futures = "0.3.30"
Expand Down
1 change: 1 addition & 0 deletions pallets/subtensor/rpc/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ serde = { workspace = true, features = ["derive"] }
# Substrate packages
sp-api = { workspace = true }
sp-blockchain = { workspace = true }
sp-core = { workspace = true }
sp-rpc = { workspace = true }
sp-runtime = { workspace = true }

Expand Down
132 changes: 82 additions & 50 deletions pallets/subtensor/rpc/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
//! RPC interface for the custom Subtensor rpc methods

use codec::{Decode, Encode};
use jsonrpsee::{
core::RpcResult,
proc_macros::rpc,
types::{error::ErrorObject, ErrorObjectOwned},
};
use sp_blockchain::HeaderBackend;
use sp_runtime::traits::Block as BlockT;
use sp_core::hexdisplay::AsBytesRef;
use sp_runtime::{traits::Block as BlockT, AccountId32};
use std::sync::Arc;

use sp_api::ProvideRuntimeApi;
Expand Down Expand Up @@ -45,10 +47,6 @@ pub trait SubtensorCustomApi<BlockHash> {
fn get_subnet_info(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubnetsInfo")]
fn get_subnets_info(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubnetInfo_v2")]
fn get_subnet_info_v2(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubnetsInf_v2")]
fn get_subnets_info_v2(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
#[method(name = "subnetInfo_getSubnetHyperparams")]
fn get_subnet_hyperparams(&self, netuid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;

Expand Down Expand Up @@ -107,9 +105,12 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_delegates(at).map_err(|e| {
Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into()
})
match api.get_delegates(at) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into())
}
Ok(result) => Ok(result.encode()),
}
}

fn get_delegate(
Expand All @@ -120,9 +121,20 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_delegate(at, delegate_account_vec).map_err(|e| {
Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into()
})
let delegate_account = match AccountId32::decode(&mut delegate_account_vec.as_bytes_ref()) {
Err(e) => {
return Err(
Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into(),
)
}
Ok(delegate_account) => delegate_account,
};
match api.get_delegate(at, delegate_account) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into())
}
Ok(result) => Ok(result.encode()),
}
}

fn get_delegated(
Expand All @@ -133,9 +145,21 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_delegated(at, delegatee_account_vec).map_err(|e| {
Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into()
})
let delegatee_account = match AccountId32::decode(&mut delegatee_account_vec.as_bytes_ref())
{
Err(e) => {
return Err(
Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into(),
)
}
Ok(delegatee_account) => delegatee_account,
};
match api.get_delegated(at, delegatee_account) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get delegates info: {:?}", e)).into())
}
Ok(result) => Ok(result.encode()),
}
}

fn get_neurons_lite(
Expand All @@ -146,9 +170,12 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_neurons_lite(at, netuid).map_err(|e| {
Error::RuntimeError(format!("Unable to get neurons lite info: {:?}", e)).into()
})
match api.get_neurons_lite(at, netuid) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get neurons lite info: {:?}", e)).into())
}
Ok(neurons) => Ok(neurons.encode()),
}
}

fn get_neuron_lite(
Expand All @@ -160,17 +187,24 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_neuron_lite(at, netuid, uid).map_err(|e| {
Error::RuntimeError(format!("Unable to get neurons lite info: {:?}", e)).into()
})
match api.get_neuron_lite(at, netuid, uid) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get neuron lite info: {:?}", e)).into())
}
Ok(neuron) => Ok(neuron.encode()),
}
}

fn get_neurons(&self, netuid: u16, 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_neurons(at, netuid)
.map_err(|e| Error::RuntimeError(format!("Unable to get neurons info: {:?}", e)).into())
match api.get_neurons(at, netuid) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get neurons info: {:?}", e)).into())
}
Ok(neurons) => Ok(neurons.encode()),
}
}

fn get_neuron(
Expand All @@ -182,8 +216,12 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_neuron(at, netuid, uid)
.map_err(|e| Error::RuntimeError(format!("Unable to get neuron info: {:?}", e)).into())
match api.get_neuron(at, netuid, uid) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get neuron info: {:?}", e)).into())
}
Ok(neuron) => Ok(neuron.encode()),
}
}

fn get_subnet_info(
Expand All @@ -194,8 +232,12 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_subnet_info(at, netuid)
.map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into())
match api.get_subnet_info(at, netuid) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into())
}
Ok(result) => Ok(result.encode()),
}
}

fn get_subnet_hyperparams(
Expand All @@ -206,36 +248,26 @@ where
let api = self.client.runtime_api();
let at = at.unwrap_or_else(|| self.client.info().best_hash);

api.get_subnet_hyperparams(at, netuid)
.map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into())
match api.get_subnet_hyperparams(at, netuid) {
Err(e) => Err(Error::RuntimeError(format!(
"Unable to get subnet hyperparam info: {:?}",
e
))
.into()),
Ok(result) => Ok(result.encode()),
}
}

fn get_subnets_info(&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_subnets_info(at)
.map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into())
}

fn get_subnet_info_v2(
&self,
netuid: u16,
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_subnet_info_v2(at, netuid)
.map_err(|e| Error::RuntimeError(format!("Unable to get subnet info: {:?}", e)).into())
}

fn get_subnets_info_v2(&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_subnets_info_v2(at)
.map_err(|e| Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into())
match api.get_subnets_info(at) {
Err(e) => {
Err(Error::RuntimeError(format!("Unable to get subnets info: {:?}", e)).into())
}
Ok(result) => Ok(result.encode()),
}
}

fn get_network_lock_cost(&self, at: Option<<Block as BlockT>::Hash>) -> RpcResult<u64> {
Expand Down
1 change: 1 addition & 0 deletions pallets/subtensor/runtime-api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ workspace = true

[dependencies]
sp-api = { workspace = true }
codec = { workspace = true }
frame-support = { workspace = true }
serde = { workspace = true, features = ["derive"] }

Expand Down
34 changes: 20 additions & 14 deletions pallets/subtensor/runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,40 @@
#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
use alloc::vec::Vec;
use codec::Compact;
use frame_support::sp_runtime::AccountId32;
use pallet_subtensor::rpc_info::{
delegate_info::DelegateInfo,
neuron_info::{NeuronInfo, NeuronInfoLite},
stake_info::StakeInfo,
subnet_info::{SubnetHyperparams, SubnetInfo},
};

// Here we declare the runtime API. It is implemented it the `impl` block in
// src/neuron_info.rs, src/subnet_info.rs, and src/delegate_info.rs
sp_api::decl_runtime_apis! {
pub trait DelegateInfoRuntimeApi {
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_delegates() -> Vec<DelegateInfo<AccountId32>>;
fn get_delegate( delegate_account: AccountId32 ) -> Option<DelegateInfo<AccountId32>>;
fn get_delegated( delegatee_account: AccountId32 ) -> Vec<(DelegateInfo<AccountId32>, Compact<u64>)>;
}

pub trait NeuronInfoRuntimeApi {
fn get_neurons(netuid: u16) -> Vec<u8>;
fn get_neuron(netuid: u16, uid: u16) -> Vec<u8>;
fn get_neurons_lite(netuid: u16) -> Vec<u8>;
fn get_neuron_lite(netuid: u16, uid: u16) -> Vec<u8>;
fn get_neurons(netuid: u16) -> Vec<NeuronInfo<AccountId32>>;
fn get_neuron(netuid: u16, uid: u16) -> Option<NeuronInfo<AccountId32>>;
fn get_neurons_lite(netuid: u16) -> Vec<NeuronInfoLite<AccountId32>>;
fn get_neuron_lite(netuid: u16, uid: u16) -> Option<NeuronInfoLite<AccountId32>>;
}

pub trait SubnetInfoRuntimeApi {
fn get_subnet_info(netuid: u16) -> Vec<u8>;
fn get_subnets_info() -> Vec<u8>;
fn get_subnet_info_v2(netuid: u16) -> Vec<u8>;
fn get_subnets_info_v2() -> Vec<u8>;
fn get_subnet_hyperparams(netuid: u16) -> Vec<u8>;
fn get_subnet_info(netuid: u16) -> Option<SubnetInfo<AccountId32>>;
fn get_subnets_info() -> Vec<Option<SubnetInfo<AccountId32>>>;
fn get_subnet_hyperparams(netuid: u16) -> Option<SubnetHyperparams>;
}

pub trait StakeInfoRuntimeApi {
fn get_stake_info_for_coldkey( coldkey_account_vec: Vec<u8> ) -> Vec<u8>;
fn get_stake_info_for_coldkeys( coldkey_account_vecs: Vec<Vec<u8>> ) -> Vec<u8>;
fn get_stake_info_for_coldkey( coldkey_account: AccountId32 ) -> Vec<StakeInfo<AccountId32>>;
fn get_stake_info_for_coldkeys( coldkey_accounts: Vec<AccountId32> ) -> Vec<(AccountId32, Vec<StakeInfo<AccountId32>>)>;
}

pub trait SubnetRegistrationRuntimeApi {
Expand Down
33 changes: 18 additions & 15 deletions pallets/subtensor/src/rpc_info/delegate_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@ use super::*;
use frame_support::pallet_prelude::{Decode, Encode};
use frame_support::storage::IterableStorageMap;
use frame_support::IterableStorageDoubleMap;
use sp_runtime::AccountId32;
use substrate_fixed::types::U64F64;
extern crate alloc;
use codec::Compact;
use sp_core::hexdisplay::AsBytesRef;

#[freeze_struct("5752e4c650a83e0d")]
#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug)]
pub struct DelegateInfo<T: Config> {
delegate_ss58: T::AccountId,
#[freeze_struct("66105c2cfec0608d")]
#[derive(Decode, Encode, PartialEq, Eq, Clone, Debug, TypeInfo)]
pub struct DelegateInfo<AccountId: TypeInfo + Encode + Decode> {
delegate_ss58: AccountId,
take: Compact<u16>,
nominators: Vec<(T::AccountId, Compact<u64>)>, // map of nominator_ss58 to stake amount
owner_ss58: T::AccountId,
nominators: Vec<(AccountId, Compact<u64>)>, // map of nominator_ss58 to stake amount
owner_ss58: AccountId,
registrations: Vec<Compact<u16>>, // Vec of netuid this delegate is registered on
validator_permits: Vec<Compact<u16>>, // Vec of netuid this delegate has validator permit on
return_per_1000: Compact<u64>, // Delegators current daily return per 1000 TAO staked minus take fee
total_daily_return: Compact<u64>, // Delegators current daily return
}

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

for (nominator, stake) in
Expand Down Expand Up @@ -82,10 +83,8 @@ impl<T: Config> Pallet<T> {
}
}

pub fn get_delegate(delegate_account_vec: Vec<u8>) -> Option<DelegateInfo<T>> {
if delegate_account_vec.len() != 32 {
return None;
}
pub fn get_delegate(delegate_account: AccountId32) -> Option<DelegateInfo<T::AccountId>> {
let delegate_account_vec = delegate_account.encode();

let delegate: AccountIdOf<T> =
T::AccountId::decode(&mut delegate_account_vec.as_bytes_ref()).ok()?;
Expand All @@ -100,8 +99,8 @@ impl<T: Config> Pallet<T> {

/// get all delegates info from storage
///
pub fn get_delegates() -> Vec<DelegateInfo<T>> {
let mut delegates = Vec::<DelegateInfo<T>>::new();
pub fn get_delegates() -> Vec<DelegateInfo<T::AccountId>> {
let mut delegates = Vec::<DelegateInfo<T::AccountId>>::new();
for delegate in <Delegates<T> as IterableStorageMap<T::AccountId, u16>>::iter_keys() {
let delegate_info = Self::get_delegate_by_existing_account(delegate.clone());
delegates.push(delegate_info);
Expand All @@ -112,12 +111,16 @@ impl<T: Config> Pallet<T> {

/// get all delegate info and staked token amount for a given delegatee account
///
pub fn get_delegated(delegatee_account_vec: Vec<u8>) -> Vec<(DelegateInfo<T>, Compact<u64>)> {
pub fn get_delegated(
delegatee_account: AccountId32,
) -> Vec<(DelegateInfo<T::AccountId>, Compact<u64>)> {
let delegatee_account_vec = delegatee_account.encode();

let Ok(delegatee) = T::AccountId::decode(&mut delegatee_account_vec.as_bytes_ref()) else {
return Vec::new(); // No delegates for invalid account
};

let mut delegates: Vec<(DelegateInfo<T>, Compact<u64>)> = Vec::new();
let mut delegates: Vec<(DelegateInfo<T::AccountId>, Compact<u64>)> = Vec::new();
for delegate in <Delegates<T> as IterableStorageMap<T::AccountId, u16>>::iter_keys() {
let staked_to_this_delegatee =
Self::get_stake_for_coldkey_and_hotkey(&delegatee.clone(), &delegate.clone());
Expand Down
Loading