Skip to content

Commit 664e08b

Browse files
Add root validators as parent to subnet owner hotkey.
1 parent f4b4a21 commit 664e08b

File tree

2 files changed

+200
-0
lines changed

2 files changed

+200
-0
lines changed

pallets/subtensor/src/staking/set_children.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,70 @@ impl<T: Config> Pallet<T> {
769769
// State cleaners (for use in migration)
770770
// TODO: Deprecate when the state is clean for a while
771771

772+
/// Establishes parent-child relationships between all root validators and
773+
/// a subnet owner's hotkey on the specified subnet.
774+
///
775+
/// For each validator on the root network (netuid 0), this function calls
776+
/// `do_schedule_children` to schedule the subnet owner hotkey as a child
777+
/// of that root validator on the given subnet, with full proportion (u64::MAX).
778+
///
779+
/// # Arguments
780+
/// * `netuid` - The subnet on which to establish relationships.
781+
///
782+
/// # Returns
783+
/// * `DispatchResult` - Ok if at least the setup completes; individual
784+
/// scheduling failures per validator are logged but do not abort the loop.
785+
pub fn do_set_root_validators_for_subnet(netuid: NetUid) -> DispatchResult {
786+
// Cannot set children on root network itself.
787+
ensure!(
788+
!netuid.is_root(),
789+
Error::<T>::RegistrationNotPermittedOnRootSubnet
790+
);
791+
792+
// Subnet must exist.
793+
ensure!(Self::if_subnet_exist(netuid), Error::<T>::SubnetNotExists);
794+
795+
// Get the subnet owner hotkey.
796+
let subnet_owner_hotkey = SubnetOwnerHotkey::<T>::try_get(netuid)
797+
.map_err(|_| Error::<T>::SubnetNotExists)?;
798+
799+
// Iterate over all root validators and schedule each one as a parent
800+
// of the subnet owner hotkey.
801+
for (_uid, root_validator_hotkey) in Keys::<T>::iter_prefix(NetUid::ROOT) {
802+
// Skip if the root validator is the subnet owner hotkey itself
803+
// (cannot be both parent and child).
804+
if root_validator_hotkey == subnet_owner_hotkey {
805+
continue;
806+
}
807+
808+
// Look up the coldkey that owns this root validator hotkey.
809+
let coldkey = Self::get_owning_coldkey_for_hotkey(&root_validator_hotkey);
810+
811+
// Build a signed origin from the coldkey.
812+
let origin: T::RuntimeOrigin =
813+
frame_system::RawOrigin::Signed(coldkey).into();
814+
815+
// Schedule the subnet owner hotkey as a child with full proportion.
816+
let children = vec![(u64::MAX, subnet_owner_hotkey.clone())];
817+
818+
if let Err(e) = Self::do_schedule_children(
819+
origin,
820+
root_validator_hotkey.clone(),
821+
netuid,
822+
children,
823+
) {
824+
log::warn!(
825+
"Failed to schedule children for root validator {:?} on netuid {:?}: {:?}",
826+
root_validator_hotkey,
827+
netuid,
828+
e
829+
);
830+
}
831+
}
832+
833+
Ok(())
834+
}
835+
772836
pub fn clean_zero_childkey_vectors(weight: &mut Weight) {
773837
// Collect keys to delete first to avoid mutating while iterating.
774838
let mut to_remove: Vec<(T::AccountId, NetUid)> = Vec::new();

pallets/subtensor/src/tests/children.rs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4220,3 +4220,139 @@ fn test_set_child_keys_empty_vector_clears_storage() {
42204220
assert!(ParentKeys::<Test>::get(child, netuid).is_empty());
42214221
});
42224222
}
4223+
4224+
// Test that do_set_root_children_for_subnet enables a subnet owner to set weights
4225+
// by inheriting stake from root validators.
4226+
// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::children::test_root_children_enable_subnet_owner_set_weights --exact --show-output --nocapture
4227+
#[test]
4228+
fn test_root_children_enable_subnet_owner_set_weights() {
4229+
new_test_ext(1).execute_with(|| {
4230+
// --- Setup accounts ---
4231+
let subnet_owner_coldkey = U256::from(1001);
4232+
let subnet_owner_hotkey = U256::from(1002);
4233+
4234+
let root_val_coldkey_1 = U256::from(100);
4235+
let root_val_hotkey_1 = U256::from(101);
4236+
let root_val_coldkey_2 = U256::from(200);
4237+
let root_val_hotkey_2 = U256::from(201);
4238+
4239+
// --- Create root network and subnet ---
4240+
add_network(NetUid::ROOT, 1, 0);
4241+
let netuid =
4242+
add_dynamic_network_disable_commit_reveal(&subnet_owner_hotkey, &subnet_owner_coldkey);
4243+
4244+
// --- Register root validators on a subnet first (required before root_register) ---
4245+
register_ok_neuron(netuid, root_val_hotkey_1, root_val_coldkey_1, 0);
4246+
register_ok_neuron(netuid, root_val_hotkey_2, root_val_coldkey_2, 0);
4247+
4248+
// --- Register root validators on root network ---
4249+
assert_ok!(SubtensorModule::root_register(
4250+
RuntimeOrigin::signed(root_val_coldkey_1),
4251+
root_val_hotkey_1,
4252+
));
4253+
assert_ok!(SubtensorModule::root_register(
4254+
RuntimeOrigin::signed(root_val_coldkey_2),
4255+
root_val_hotkey_2,
4256+
));
4257+
4258+
// Subnet owner hotkey is auto-registered on the subnet via add_dynamic_network.
4259+
4260+
// --- Add significant stake for root validators on root and the subnet ---
4261+
let root_stake = AlphaBalance::from(1_000_000_000);
4262+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
4263+
&root_val_hotkey_1,
4264+
&root_val_coldkey_1,
4265+
NetUid::ROOT,
4266+
root_stake,
4267+
);
4268+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
4269+
&root_val_hotkey_1,
4270+
&root_val_coldkey_1,
4271+
netuid,
4272+
root_stake,
4273+
);
4274+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
4275+
&root_val_hotkey_2,
4276+
&root_val_coldkey_2,
4277+
NetUid::ROOT,
4278+
root_stake,
4279+
);
4280+
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
4281+
&root_val_hotkey_2,
4282+
&root_val_coldkey_2,
4283+
netuid,
4284+
root_stake,
4285+
);
4286+
4287+
// --- Set a high stake threshold so the subnet owner alone cannot set weights ---
4288+
let high_threshold = 500_000_000u64;
4289+
SubtensorModule::set_stake_threshold(high_threshold);
4290+
4291+
// Disable rate limits for clean testing
4292+
SubtensorModule::set_weights_set_rate_limit(netuid, 0);
4293+
4294+
let version_key = SubtensorModule::get_weights_version_key(netuid);
4295+
let uids: Vec<u16> = vec![0];
4296+
let values: Vec<u16> = vec![u16::MAX];
4297+
4298+
// Show that subnet owner CANNOT set weights (insufficient stake) ---
4299+
assert!(
4300+
!SubtensorModule::check_weights_min_stake(&subnet_owner_hotkey, netuid),
4301+
"Subnet owner should NOT have enough stake to set weights initially"
4302+
);
4303+
assert_noop!(
4304+
SubtensorModule::set_weights(
4305+
RuntimeOrigin::signed(subnet_owner_hotkey),
4306+
netuid,
4307+
uids.clone(),
4308+
values.clone(),
4309+
version_key
4310+
),
4311+
Error::<Test>::NotEnoughStakeToSetWeights
4312+
);
4313+
4314+
// Minimize the pending children cooldown via root extrinsic ---
4315+
assert_ok!(SubtensorModule::set_pending_childkey_cooldown(
4316+
RuntimeOrigin::root(),
4317+
0, // zero block cooldown
4318+
));
4319+
4320+
assert_ok!(SubtensorModule::do_set_root_validators_for_subnet(netuid));
4321+
4322+
// Activate pending children (cooldown is 0, advance 1 block) ---
4323+
step_block(1);
4324+
SubtensorModule::do_set_pending_children(netuid);
4325+
4326+
// Verify that child-parent relationships were created:
4327+
// Each root validator should have the subnet owner hotkey as a child on netuid
4328+
let children_1 = SubtensorModule::get_children(&root_val_hotkey_1, netuid);
4329+
assert_eq!(
4330+
children_1,
4331+
vec![(u64::MAX, subnet_owner_hotkey)],
4332+
"Root validator 1 should have subnet owner as child"
4333+
);
4334+
let children_2 = SubtensorModule::get_children(&root_val_hotkey_2, netuid);
4335+
assert_eq!(
4336+
children_2,
4337+
vec![(u64::MAX, subnet_owner_hotkey)],
4338+
"Root validator 2 should have subnet owner as child"
4339+
);
4340+
4341+
// Verify that the subnet owner has both root validators as parents
4342+
let parents = SubtensorModule::get_parents(&subnet_owner_hotkey, netuid);
4343+
assert_eq!(parents.len(), 2, "Subnet owner should have 2 parents");
4344+
4345+
// Show that subnet owner CAN now set weights ---
4346+
assert!(
4347+
SubtensorModule::check_weights_min_stake(&subnet_owner_hotkey, netuid),
4348+
"Subnet owner should now have enough inherited stake to set weights"
4349+
);
4350+
assert_ok!(SubtensorModule::set_weights(
4351+
RuntimeOrigin::signed(subnet_owner_hotkey),
4352+
netuid,
4353+
uids,
4354+
values,
4355+
version_key
4356+
));
4357+
});
4358+
}

0 commit comments

Comments
 (0)