use crate::api::api;
use crate::error::BittensorError;
use crate::extrinsics::ExtrinsicResponse;
use crate::AccountId;
use subxt::OnlineClient;
use subxt::PolkadotConfig;
#[derive(Debug, Clone)]
pub struct ChildKey {
pub proportion: u64,
pub child: AccountId,
}
impl ChildKey {
pub fn new(child: AccountId, proportion: f64) -> Self {
let proportion = (proportion.clamp(0.0, 1.0) * u64::MAX as f64) as u64;
Self { proportion, child }
}
pub fn new_raw(child: AccountId, proportion: u64) -> Self {
Self { proportion, child }
}
}
#[derive(Debug, Clone)]
pub struct SetChildrenParams {
pub netuid: u16,
pub children: Vec<ChildKey>,
}
impl SetChildrenParams {
pub fn new(netuid: u16) -> Self {
Self {
netuid,
children: Vec::new(),
}
}
pub fn with_child(mut self, child: AccountId, proportion: f64) -> Self {
self.children.push(ChildKey::new(child, proportion));
self
}
pub fn with_children(mut self, children: Vec<ChildKey>) -> Self {
self.children.extend(children);
self
}
}
pub async fn set_children<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
hotkey: AccountId,
params: SetChildrenParams,
) -> Result<ExtrinsicResponse<()>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let children: Vec<(u64, AccountId)> = params
.children
.into_iter()
.map(|c| (c.proportion, c.child))
.collect();
let call = api::tx()
.subtensor_module()
.set_children(hotkey, params.netuid, children);
let tx_hash = client
.tx()
.sign_and_submit_default(&call, signer)
.await
.map_err(|e| BittensorError::TxSubmissionError {
message: format!("Failed to set children: {}", e),
})?;
Ok(ExtrinsicResponse::success()
.with_message("Children set successfully")
.with_extrinsic_hash(&format!("{:?}", tx_hash))
.with_data(()))
}
pub async fn set_childkey_take<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
hotkey: AccountId,
netuid: u16,
take: f64,
) -> Result<ExtrinsicResponse<()>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let take_u16 = (take.clamp(0.0, 1.0) * u16::MAX as f64) as u16;
let call = api::tx()
.subtensor_module()
.set_childkey_take(hotkey, netuid, take_u16);
let tx_hash = client
.tx()
.sign_and_submit_default(&call, signer)
.await
.map_err(|e| BittensorError::TxSubmissionError {
message: format!("Failed to set childkey take: {}", e),
})?;
Ok(ExtrinsicResponse::success()
.with_message("Childkey take set successfully")
.with_extrinsic_hash(&format!("{:?}", tx_hash))
.with_data(()))
}
pub async fn revoke_children<S>(
client: &OnlineClient<PolkadotConfig>,
signer: &S,
hotkey: AccountId,
netuid: u16,
) -> Result<ExtrinsicResponse<()>, BittensorError>
where
S: subxt::tx::Signer<PolkadotConfig>,
{
let children: Vec<(u64, AccountId)> = Vec::new();
let call = api::tx()
.subtensor_module()
.set_children(hotkey, netuid, children);
let tx_hash = client
.tx()
.sign_and_submit_default(&call, signer)
.await
.map_err(|e| BittensorError::TxSubmissionError {
message: format!("Failed to revoke children: {}", e),
})?;
Ok(ExtrinsicResponse::success()
.with_message("Children revoked successfully")
.with_extrinsic_hash(&format!("{:?}", tx_hash))
.with_data(()))
}
#[cfg(test)]
mod tests {
use super::*;
use subxt::utils::AccountId32;
#[test]
fn test_child_key_new() {
let child = AccountId32::from([1u8; 32]);
let key = ChildKey::new(child.clone(), 0.5);
assert_eq!(key.child, child);
let third = u64::MAX / 3;
let two_thirds = u64::MAX / 3 * 2;
assert!(key.proportion > third);
assert!(key.proportion < two_thirds);
}
#[test]
fn test_child_key_clamping() {
let child = AccountId32::from([1u8; 32]);
let key = ChildKey::new(child.clone(), -0.5);
assert_eq!(key.proportion, 0);
let key = ChildKey::new(child, 1.5);
assert_eq!(key.proportion, u64::MAX);
}
#[test]
fn test_child_key_raw() {
let child = AccountId32::from([1u8; 32]);
let key = ChildKey::new_raw(child.clone(), 12345);
assert_eq!(key.proportion, 12345);
}
#[test]
fn test_set_children_params() {
let child1 = AccountId32::from([1u8; 32]);
let child2 = AccountId32::from([2u8; 32]);
let params = SetChildrenParams::new(1)
.with_child(child1.clone(), 0.3)
.with_child(child2.clone(), 0.2);
assert_eq!(params.netuid, 1);
assert_eq!(params.children.len(), 2);
}
#[test]
fn test_set_children_params_with_children() {
let child1 = AccountId32::from([1u8; 32]);
let child2 = AccountId32::from([2u8; 32]);
let children = vec![ChildKey::new(child1, 0.5), ChildKey::new(child2, 0.5)];
let params = SetChildrenParams::new(1).with_children(children);
assert_eq!(params.children.len(), 2);
}
#[test]
fn test_child_key_clone() {
let child = AccountId32::from([1u8; 32]);
let key = ChildKey::new(child, 0.5);
let cloned = key.clone();
assert_eq!(key.proportion, cloned.proportion);
assert_eq!(key.child, cloned.child);
}
#[test]
fn test_child_key_debug() {
let child = AccountId32::from([1u8; 32]);
let key = ChildKey::new(child, 0.5);
let debug = format!("{:?}", key);
assert!(debug.contains("ChildKey"));
}
}