|
1 | 1 | #![allow(clippy::indexing_slicing, clippy::unwrap_used)] |
2 | 2 |
|
3 | 3 | use crate::mock::*; |
4 | | -use frame_support::{assert_err, assert_ok}; |
5 | | -use frame_system::Config; |
6 | | -use frame_system::{EventRecord, Phase}; |
7 | | -use pallet_subtensor::migration; |
8 | | -use pallet_subtensor::Error; |
| 4 | +use frame_support::{assert_err, assert_ok, dispatch::DispatchInfo}; |
| 5 | +use frame_system::{Config, EventRecord, Phase}; |
| 6 | +use pallet_subtensor::{ |
| 7 | + migration, BaseDifficulty, ColdkeySwapDestinations, Error, MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, |
| 8 | +}; |
9 | 9 | use sp_core::{Get, H256, U256}; |
| 10 | +use sp_runtime::{ |
| 11 | + traits::{DispatchInfoOf, SignedExtension}, |
| 12 | + transaction_validity::{InvalidTransaction, TransactionValidityError}, |
| 13 | +}; |
10 | 14 |
|
11 | 15 | mod mock; |
12 | 16 |
|
@@ -974,3 +978,103 @@ fn test_dissolve_network_does_not_exist_err() { |
974 | 978 | ); |
975 | 979 | }); |
976 | 980 | } |
| 981 | + |
| 982 | +#[test] |
| 983 | +fn test_dissolve_network_validate() { |
| 984 | + fn generate_valid_pow(coldkey: &U256, block_number: u64, difficulty: U256) -> (H256, u64) { |
| 985 | + let mut nonce: u64 = 0; |
| 986 | + loop { |
| 987 | + let work = SubtensorModule::create_seal_hash(block_number, nonce, coldkey); |
| 988 | + if SubtensorModule::hash_meets_difficulty(&work, difficulty) { |
| 989 | + return (work, nonce); |
| 990 | + } |
| 991 | + nonce += 1; |
| 992 | + } |
| 993 | + } |
| 994 | + // Testing the signed extension validate function |
| 995 | + // correctly filters the `dissolve_network` transaction. |
| 996 | + |
| 997 | + new_test_ext(0).execute_with(|| { |
| 998 | + let netuid: u16 = 1; |
| 999 | + let delegate_coldkey = U256::from(1); |
| 1000 | + let delegate_hotkey = U256::from(2); |
| 1001 | + let new_coldkey = U256::from(3); |
| 1002 | + let current_block = 0u64; |
| 1003 | + |
| 1004 | + add_network(netuid, 0, 0); |
| 1005 | + register_ok_neuron(netuid, delegate_hotkey, delegate_coldkey, 0); |
| 1006 | + |
| 1007 | + // Make delegate a delegate |
| 1008 | + assert_ok!(SubtensorModule::become_delegate( |
| 1009 | + RuntimeOrigin::signed(delegate_coldkey), |
| 1010 | + delegate_hotkey |
| 1011 | + )); |
| 1012 | + |
| 1013 | + // Add more than 500 TAO of stake to the delegate's hotkey |
| 1014 | + let stake_amount = 501_000_000_000; // 501 TAO in RAO |
| 1015 | + let delegator = U256::from(4); |
| 1016 | + SubtensorModule::add_balance_to_coldkey_account(&delegator, stake_amount); |
| 1017 | + assert_ok!(SubtensorModule::add_stake( |
| 1018 | + RuntimeOrigin::signed(delegator), |
| 1019 | + delegate_hotkey, |
| 1020 | + stake_amount |
| 1021 | + )); |
| 1022 | + |
| 1023 | + // Ensure the delegate's coldkey has less than minimum balance |
| 1024 | + assert!( |
| 1025 | + SubtensorModule::get_coldkey_balance(&delegate_coldkey) |
| 1026 | + < MIN_BALANCE_TO_PERFORM_COLDKEY_SWAP, |
| 1027 | + "Delegate coldkey balance should be less than minimum required" |
| 1028 | + ); |
| 1029 | + |
| 1030 | + // Ensure the delegate's hotkey has more than 500 TAO delegated |
| 1031 | + assert!( |
| 1032 | + SubtensorModule::get_total_delegated_stake(&delegate_coldkey) >= 500_000_000_000, |
| 1033 | + "Delegate hotkey should have at least 500 TAO delegated" |
| 1034 | + ); |
| 1035 | + |
| 1036 | + // Generate valid PoW |
| 1037 | + let (work, nonce) = generate_valid_pow( |
| 1038 | + &delegate_coldkey, |
| 1039 | + current_block, |
| 1040 | + U256::from(4) * U256::from(BaseDifficulty::<Test>::get()), |
| 1041 | + ); |
| 1042 | + |
| 1043 | + // Schedule coldkey swap |
| 1044 | + assert_ok!(SubtensorModule::do_schedule_coldkey_swap( |
| 1045 | + &delegate_coldkey, |
| 1046 | + &new_coldkey, |
| 1047 | + work.to_fixed_bytes().to_vec(), |
| 1048 | + current_block, |
| 1049 | + nonce, |
| 1050 | + )); |
| 1051 | + |
| 1052 | + // Verify that the swap was scheduled |
| 1053 | + assert_eq!( |
| 1054 | + ColdkeySwapDestinations::<Test>::get(delegate_coldkey), |
| 1055 | + vec![new_coldkey] |
| 1056 | + ); |
| 1057 | + |
| 1058 | + // Check if the coldkey is in arbitration |
| 1059 | + assert!( |
| 1060 | + SubtensorModule::coldkey_in_arbitration(&delegate_coldkey), |
| 1061 | + "Delegate coldkey should be in arbitration after swap" |
| 1062 | + ); |
| 1063 | + |
| 1064 | + let who = delegate_coldkey; // The coldkey signs this transaction |
| 1065 | + let call = RuntimeCall::SubtensorModule(SubtensorCall::dissolve_network { netuid }); |
| 1066 | + |
| 1067 | + let info: DispatchInfo = |
| 1068 | + DispatchInfoOf::<<Test as frame_system::Config>::RuntimeCall>::default(); |
| 1069 | + |
| 1070 | + let extension = pallet_subtensor::SubtensorSignedExtension::<Test>::new(); |
| 1071 | + |
| 1072 | + // Submit to the signed extension validate function |
| 1073 | + let result_in_arbitration = extension.validate(&who, &call.clone(), &info, 10); |
| 1074 | + // Should fail with InvalidTransaction::Custom(6) because coldkey is in arbitration |
| 1075 | + assert_err!( |
| 1076 | + result_in_arbitration, |
| 1077 | + TransactionValidityError::Invalid(InvalidTransaction::Custom(6)) |
| 1078 | + ); |
| 1079 | + }); |
| 1080 | +} |
0 commit comments