Skip to content

Commit e4c9ef2

Browse files
author
Samuel Dare
committed
feat: allow subnet owners to swap without funds , todo: fix test_comprehensive_coldkey_swap_scenarios
1 parent b1feb3c commit e4c9ef2

File tree

2 files changed

+197
-7
lines changed

2 files changed

+197
-7
lines changed

pallets/subtensor/src/swap.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -246,11 +246,17 @@ impl<T: Config> Pallet<T> {
246246
) -> DispatchResult {
247247
ensure!(old_coldkey != new_coldkey, Error::<T>::SameColdkey);
248248

249-
// Check minimum amount of TAO (1 TAO)
250-
ensure!(
251-
Self::meets_min_allowed_coldkey_balance(&old_coldkey),
252-
Error::<T>::InsufficientBalanceToPerformColdkeySwap
253-
);
249+
// Check if the old_coldkey is a subnet owner for any network
250+
let is_subnet_owner = (0..=TotalNetworks::<T>::get())
251+
.any(|netuid| SubnetOwner::<T>::get(netuid) == *old_coldkey);
252+
253+
// Only check the minimum balance if the old_coldkey is not a subnet owner
254+
if !is_subnet_owner {
255+
ensure!(
256+
Self::meets_min_allowed_coldkey_balance(&old_coldkey),
257+
Error::<T>::InsufficientBalanceToPerformColdkeySwap
258+
);
259+
}
254260

255261
// Get current destination coldkeys
256262
let mut destination_coldkeys: Vec<T::AccountId> =

pallets/subtensor/tests/staking.rs

Lines changed: 186 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3992,7 +3992,8 @@ fn test_coldkey_meets_enough() {
39923992
add_network(netuid, 13, 0);
39933993
register_ok_neuron(netuid, hotkey, coldkey, 0);
39943994
let current_block = SubtensorModule::get_current_block_as_u64();
3995-
let (work1, nonce1) = generate_valid_pow(&coldkey, current_block, U256::from(10_000_000u64));
3995+
let (work1, nonce1) =
3996+
generate_valid_pow(&coldkey, current_block, U256::from(10_000_000u64));
39963997
assert_err!(
39973998
SubtensorModule::do_schedule_coldkey_swap(
39983999
&coldkey.clone(),
@@ -4014,7 +4015,190 @@ fn test_coldkey_meets_enough() {
40144015
current_block,
40154016
nonce1
40164017
));
4017-
4018+
});
4019+
}
4020+
4021+
#[test]
4022+
fn test_comprehensive_coldkey_swap_scenarios() {
4023+
new_test_ext(1).execute_with(|| {
4024+
// Set arbitration period to 5 blocks
4025+
ArbitrationPeriod::<Test>::put(5);
4026+
4027+
let subnet_owner1 = U256::from(1);
4028+
let subnet_owner2 = U256::from(2);
4029+
let regular_user = U256::from(3);
4030+
let new_coldkey1 = U256::from(4);
4031+
let new_coldkey2 = U256::from(5);
4032+
let new_coldkey3 = U256::from(6);
4033+
let netuid1 = 1;
4034+
let netuid2 = 2;
4035+
4036+
// Add networks and register subnet owners
4037+
add_network(netuid1, 13, 0);
4038+
add_network(netuid2, 13, 0);
4039+
SubnetOwner::<Test>::insert(netuid1, subnet_owner1);
4040+
SubnetOwner::<Test>::insert(netuid2, subnet_owner2);
4041+
4042+
// Add balance to regular user
4043+
SubtensorModule::add_balance_to_coldkey_account(
4044+
&regular_user,
4045+
MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP * 2,
4046+
);
40184047

4048+
let current_block = SubtensorModule::get_current_block_as_u64();
4049+
4050+
// Schedule swaps for subnet owners and regular user
4051+
let (work1, nonce1) =
4052+
generate_valid_pow(&subnet_owner1, current_block, U256::from(10_000_000u64));
4053+
let (work2, nonce2) =
4054+
generate_valid_pow(&subnet_owner2, current_block, U256::from(20_000_000u64));
4055+
let (work3, nonce3) =
4056+
generate_valid_pow(&regular_user, current_block, U256::from(30_000_000u64));
4057+
4058+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4059+
&subnet_owner1,
4060+
&new_coldkey1,
4061+
work1.to_fixed_bytes().to_vec(),
4062+
current_block,
4063+
nonce1
4064+
));
4065+
4066+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4067+
&subnet_owner2,
4068+
&new_coldkey2,
4069+
work2.to_fixed_bytes().to_vec(),
4070+
current_block,
4071+
nonce2
4072+
));
4073+
4074+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4075+
&regular_user,
4076+
&new_coldkey3,
4077+
work3.to_fixed_bytes().to_vec(),
4078+
current_block,
4079+
nonce3
4080+
));
4081+
4082+
// Check if swaps were scheduled correctly
4083+
assert_eq!(
4084+
ColdkeySwapDestinations::<Test>::get(subnet_owner1),
4085+
vec![new_coldkey1]
4086+
);
4087+
assert_eq!(
4088+
ColdkeySwapDestinations::<Test>::get(subnet_owner2),
4089+
vec![new_coldkey2]
4090+
);
4091+
assert_eq!(
4092+
ColdkeySwapDestinations::<Test>::get(regular_user),
4093+
vec![new_coldkey3]
4094+
);
4095+
4096+
// Run through the arbitration period plus one block
4097+
for i in 0..6 {
4098+
next_block();
4099+
SubtensorModule::on_idle(System::block_number(), Weight::MAX);
4100+
4101+
log::info!(
4102+
"Block {}: Coldkey in arbitration: {}, Swap destinations: {:?}",
4103+
i + 1,
4104+
SubtensorModule::coldkey_in_arbitration(&subnet_owner1),
4105+
ColdkeySwapDestinations::<Test>::get(subnet_owner1)
4106+
);
4107+
4108+
// Test edge case: try to schedule another swap during arbitration
4109+
if i == 2 {
4110+
let (work4, nonce4) = generate_valid_pow(
4111+
&subnet_owner1,
4112+
current_block + i as u64,
4113+
U256::from(40_000_000u64),
4114+
);
4115+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4116+
&subnet_owner1,
4117+
&new_coldkey2,
4118+
work4.to_fixed_bytes().to_vec(),
4119+
current_block + i as u64,
4120+
nonce4
4121+
));
4122+
// This should add new_coldkey2 to subnet_owner1's destinations
4123+
assert_eq!(
4124+
ColdkeySwapDestinations::<Test>::get(subnet_owner1),
4125+
vec![new_coldkey1, new_coldkey2]
4126+
);
4127+
}
4128+
}
4129+
4130+
// Check if swaps have been executed
4131+
log::info!(
4132+
"After arbitration period - Swap destinations for subnet_owner1: {:?}",
4133+
ColdkeySwapDestinations::<Test>::get(subnet_owner1)
4134+
);
4135+
assert_eq!(
4136+
ColdkeySwapDestinations::<Test>::get(subnet_owner1),
4137+
vec![new_coldkey1, new_coldkey2],
4138+
"ColdkeySwapDestinations for subnet_owner1 should still contain two destinations after arbitration period"
4139+
);
4140+
assert!(ColdkeySwapDestinations::<Test>::get(subnet_owner2).is_empty());
4141+
assert!(ColdkeySwapDestinations::<Test>::get(regular_user).is_empty());
4142+
4143+
// Verify that subnet ownerships have NOT been transferred for subnet_owner1
4144+
assert_eq!(SubnetOwner::<Test>::get(netuid1), subnet_owner1);
4145+
// But subnet_owner2's ownership should have been transferred
4146+
assert_eq!(SubnetOwner::<Test>::get(netuid2), new_coldkey2);
4147+
4148+
// Verify regular user's balance has been transferred
4149+
assert_eq!(
4150+
SubtensorModule::get_coldkey_balance(&new_coldkey3),
4151+
MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP * 2
4152+
);
4153+
assert_eq!(SubtensorModule::get_coldkey_balance(&regular_user), 0);
4154+
4155+
// Test multiple calls for the same subnet owner
4156+
let (work5, nonce5) =
4157+
generate_valid_pow(&new_coldkey1, current_block + 7, U256::from(50_000_000u64));
4158+
let (work6, nonce6) =
4159+
generate_valid_pow(&new_coldkey1, current_block + 7, U256::from(60_000_000u64));
4160+
4161+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4162+
&new_coldkey1,
4163+
&subnet_owner1,
4164+
work5.to_fixed_bytes().to_vec(),
4165+
current_block + 7,
4166+
nonce5
4167+
));
4168+
4169+
assert_ok!(SubtensorModule::do_schedule_coldkey_swap(
4170+
&new_coldkey1,
4171+
&subnet_owner2,
4172+
work6.to_fixed_bytes().to_vec(),
4173+
current_block + 7,
4174+
nonce6
4175+
));
4176+
4177+
assert_eq!(
4178+
ColdkeySwapDestinations::<Test>::get(new_coldkey1),
4179+
vec![subnet_owner1, subnet_owner2]
4180+
);
4181+
4182+
// Run through another arbitration period plus one block
4183+
for i in 0..6 {
4184+
next_block();
4185+
SubtensorModule::on_idle(System::block_number(), Weight::MAX);
4186+
4187+
log::info!(
4188+
"Block {}: Coldkey in arbitration: {}, Swap destinations: {:?}",
4189+
i + 7,
4190+
SubtensorModule::coldkey_in_arbitration(&new_coldkey1),
4191+
ColdkeySwapDestinations::<Test>::get(new_coldkey1)
4192+
);
4193+
}
4194+
4195+
// Check final state
4196+
log::info!(
4197+
"Final state - Swap destinations for new_coldkey1: {:?}",
4198+
ColdkeySwapDestinations::<Test>::get(new_coldkey1)
4199+
);
4200+
assert!(ColdkeySwapDestinations::<Test>::get(new_coldkey1).is_empty());
4201+
assert_eq!(SubnetOwner::<Test>::get(netuid1), subnet_owner1);
4202+
assert_eq!(SubnetOwner::<Test>::get(netuid2), subnet_owner2);
40194203
});
40204204
}

0 commit comments

Comments
 (0)