code/pallets/subtensor/rpc/src/lib.rs

lib.rs

586 lines · 20,590 bytes · 19a6485969RawGitHub
//! RPC interface for the custom Subtensor rpc methods

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

use sp_api::ProvideRuntimeApi;

pub use subtensor_custom_rpc_runtime_api::{
    DelegateInfoRuntimeApi, NeuronInfoRuntimeApi, StakeInfoRuntimeApi, SubnetInfoRuntimeApi,
    SubnetRegistrationRuntimeApi,
};

#[rpc(client, server)]
pub trait SubtensorCustomApi<BlockHash> {
    #[method(name = "delegateInfo_getDelegates")]
    fn get_delegates(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "delegateInfo_getDelegate")]
    fn get_delegate(
        &self,
        delegate_account_vec: Vec<u8>,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "delegateInfo_getDelegated")]
    fn get_delegated(
        &self,
        delegatee_account_vec: Vec<u8>,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;

    #[method(name = "neuronInfo_getNeuronsLite")]
    fn get_neurons_lite(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "neuronInfo_getNeuronLite")]
    fn get_neuron_lite(
        &self,
        netuid: NetUid,
        uid: u16,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "neuronInfo_getNeurons")]
    fn get_neurons(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "neuronInfo_getNeuron")]
    fn get_neuron(&self, netuid: NetUid, uid: u16, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetInfo")]
    fn get_subnet_info(&self, netuid: NetUid, 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: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetsInfo_v2")]
    fn get_subnets_info_v2(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetHyperparams")]
    fn get_subnet_hyperparams(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetHyperparamsV2")]
    fn get_subnet_hyperparams_v2(
        &self,
        netuid: NetUid,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getAllDynamicInfo")]
    fn get_all_dynamic_info(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getDynamicInfo")]
    fn get_dynamic_info(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getAllMetagraphs")]
    fn get_all_metagraphs(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getMetagraph")]
    fn get_metagraph(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getAllMechagraphs")]
    fn get_all_mechagraphs(&self, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getMechagraph")]
    fn get_mechagraph(
        &self,
        netuid: NetUid,
        mecid: MechId,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetState")]
    fn get_subnet_state(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;

    #[method(name = "subnetInfo_getBlockEmission")]
    fn get_block_emission(&self, at: Option<BlockHash>) -> RpcResult<TaoBalance>;
    #[method(name = "subnetInfo_getLockCost")]
    fn get_network_lock_cost(&self, at: Option<BlockHash>) -> RpcResult<TaoBalance>;
    #[method(name = "subnetInfo_getSelectiveMetagraph")]
    fn get_selective_metagraph(
        &self,
        netuid: NetUid,
        metagraph_index: Vec<u16>,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getColdkeyAutoStakeHotkey")]
    fn get_coldkey_auto_stake_hotkey(
        &self,
        coldkey: AccountId32,
        netuid: NetUid,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSelectiveMechagraph")]
    fn get_selective_mechagraph(
        &self,
        netuid: NetUid,
        mecid: MechId,
        metagraph_index: Vec<u16>,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
    #[method(name = "subnetInfo_getSubnetToPrune")]
    fn get_subnet_to_prune(&self, at: Option<BlockHash>) -> RpcResult<Option<NetUid>>;
    #[method(name = "subnetInfo_getSubnetAccountId")]
    fn get_subnet_account_id(&self, netuid: NetUid, at: Option<BlockHash>) -> RpcResult<Vec<u8>>;
    #[method(name = "stakeInfo_getColdkeyLock")]
    fn get_coldkey_lock(
        &self,
        coldkey: AccountId32,
        netuid: NetUid,
        at: Option<BlockHash>,
    ) -> RpcResult<Vec<u8>>;
}

pub struct SubtensorCustom<C, P> {
    /// Shared reference to the client.
    client: Arc<C>,
    _marker: std::marker::PhantomData<P>,
}

impl<C, P> SubtensorCustom<C, P> {
    /// Creates a new instance of the TransactionPayment Rpc helper.
    pub fn new(client: Arc<C>) -> Self {
        Self {
            client,
            _marker: Default::default(),
        }
    }
}

/// Error type of this RPC api.
pub enum Error {
    /// The call to runtime failed.
    RuntimeError(String),
}

impl From<Error> for ErrorObjectOwned {
    fn from(e: Error) -> Self {
        match e {
            Error::RuntimeError(e) => ErrorObject::owned(1, e, None::<()>),
        }
    }
}

impl From<Error> for i32 {
    fn from(e: Error) -> i32 {
        match e {
            Error::RuntimeError(_) => 1,
        }
    }
}

impl<C, Block> SubtensorCustomApiServer<<Block as BlockT>::Hash> for SubtensorCustom<C, Block>
where
    Block: BlockT,
    C: ProvideRuntimeApi<Block> + HeaderBackend<Block> + Send + Sync + 'static,
    C::Api: DelegateInfoRuntimeApi<Block>,
    C::Api: NeuronInfoRuntimeApi<Block>,
    C::Api: SubnetInfoRuntimeApi<Block>,
    C::Api: StakeInfoRuntimeApi<Block>,
    C::Api: SubnetRegistrationRuntimeApi<Block>,
{
    fn get_delegates(&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);

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

    fn get_delegate(
        &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);

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

    fn get_delegated(
        &self,
        delegatee_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);

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

    fn get_neurons_lite(
        &self,
        netuid: NetUid,
        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);

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

    fn get_neuron_lite(
        &self,
        netuid: NetUid,
        uid: 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);

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

    fn get_neurons(
        &self,
        netuid: NetUid,
        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);

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

    fn get_neuron(
        &self,
        netuid: NetUid,
        uid: 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);

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

    fn get_subnet_info(
        &self,
        netuid: NetUid,
        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);

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

    #[allow(deprecated)]
    fn get_subnet_hyperparams(
        &self,
        netuid: NetUid,
        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);

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

    #[allow(deprecated)]
    fn get_subnet_hyperparams_v2(
        &self,
        netuid: NetUid,
        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);

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

    fn get_all_dynamic_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);

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

    fn get_all_metagraphs(&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);

        match api.get_all_metagraphs(at) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!("Unable to get metagraps: {e:?}")).into()),
        }
    }

    fn get_all_mechagraphs(&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);

        match api.get_all_mechagraphs(at) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!("Unable to get metagraps: {e:?}")).into()),
        }
    }

    fn get_dynamic_info(
        &self,
        netuid: NetUid,
        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);

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

    fn get_metagraph(
        &self,
        netuid: NetUid,
        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);
        match api.get_metagraph(at, netuid) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!(
                "Unable to get dynamic subnets info: {e:?}"
            ))
            .into()),
        }
    }

    fn get_mechagraph(
        &self,
        netuid: NetUid,
        mecid: MechId,
        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);
        match api.get_mechagraph(at, netuid, mecid) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!(
                "Unable to get dynamic subnets info: {e:?}"
            ))
            .into()),
        }
    }

    fn get_subnet_state(
        &self,
        netuid: NetUid,
        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);

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

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

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

    fn get_subnet_info_v2(
        &self,
        netuid: NetUid,
        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);

        match api.get_subnet_info_v2(at, netuid) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(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);

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

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

        api.get_block_emission(at)
            .map_err(|e| Error::RuntimeError(format!("Unable to get block emission: {e:?}")).into())
    }

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

        api.get_network_registration_cost(at).map_err(|e| {
            Error::RuntimeError(format!("Unable to get subnet lock cost: {e:?}")).into()
        })
    }

    fn get_selective_metagraph(
        &self,
        netuid: NetUid,
        metagraph_index: Vec<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);

        match api.get_selective_metagraph(at, netuid, metagraph_index) {
            Ok(result) => Ok(result.encode()),
            Err(e) => {
                Err(Error::RuntimeError(format!("Unable to get selective metagraph: {e:?}")).into())
            }
        }
    }

    fn get_coldkey_auto_stake_hotkey(
        &self,
        coldkey: AccountId32,
        netuid: NetUid,
        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);

        match api.get_coldkey_auto_stake_hotkey(at, coldkey, netuid) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!(
                "Unable to get coldkey auto stake hotkey: {e:?}"
            ))
            .into()),
        }
    }

    fn get_selective_mechagraph(
        &self,
        netuid: NetUid,
        mecid: MechId,
        metagraph_index: Vec<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);

        match api.get_selective_mechagraph(at, netuid, mecid, metagraph_index) {
            Ok(result) => Ok(result.encode()),
            Err(e) => {
                Err(Error::RuntimeError(format!("Unable to get selective metagraph: {e:?}")).into())
            }
        }
    }

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

        match api.get_subnet_to_prune(at) {
            Ok(result) => Ok(result),
            Err(e) => {
                Err(Error::RuntimeError(format!("Unable to get subnet to prune: {e:?}")).into())
            }
        }
    }

    fn get_subnet_account_id(
        &self,
        netuid: NetUid,
        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);

        match api.get_subnet_account_id(at, netuid) {
            Ok(result) => Ok(result.encode()),
            Err(_) => Err(Error::RuntimeError("Subnet does not exist".to_string()).into()),
        }
    }

    fn get_coldkey_lock(
        &self,
        coldkey: AccountId32,
        netuid: NetUid,
        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);

        match api.get_coldkey_lock(at, coldkey, netuid) {
            Ok(result) => Ok(result.encode()),
            Err(e) => Err(Error::RuntimeError(format!("Unable to get coldkey lock: {e:?}")).into()),
        }
    }
}