|
| 1 | +use frame_support::{assert_ok, traits::InstanceFilter, BoundedVec}; |
| 2 | +use node_subtensor_runtime::{ |
| 3 | + AccountId, BalancesCall, BuildStorage, Proxy, ProxyType, Runtime, RuntimeCall, RuntimeEvent, |
| 4 | + RuntimeGenesisConfig, RuntimeOrigin, SubtensorModule, System, SystemCall, |
| 5 | +}; |
| 6 | + |
| 7 | +use frame_support::dispatch::Encode; |
| 8 | + |
| 9 | +const ACCOUNT: [u8; 32] = [1_u8; 32]; |
| 10 | +const DELEGATE: [u8; 32] = [2_u8; 32]; |
| 11 | +const OTHER_ACCOUNT: [u8; 32] = [3_u8; 32]; |
| 12 | + |
| 13 | +type SystemError = frame_system::Error<Runtime>; |
| 14 | + |
| 15 | +pub fn new_test_ext() -> sp_io::TestExternalities { |
| 16 | + sp_tracing::try_init_simple(); |
| 17 | + let amount = 1_000_000_000_000; |
| 18 | + let mut ext: sp_io::TestExternalities = RuntimeGenesisConfig { |
| 19 | + balances: pallet_balances::GenesisConfig { |
| 20 | + balances: vec![ |
| 21 | + (AccountId::from(ACCOUNT), amount), |
| 22 | + (AccountId::from(DELEGATE), amount), |
| 23 | + (AccountId::from(OTHER_ACCOUNT), amount), |
| 24 | + ], |
| 25 | + }, |
| 26 | + |
| 27 | + triumvirate: pallet_collective::GenesisConfig { |
| 28 | + members: vec![AccountId::from(ACCOUNT)], |
| 29 | + phantom: Default::default(), |
| 30 | + }, |
| 31 | + senate_members: pallet_membership::GenesisConfig { |
| 32 | + members: BoundedVec::try_from(vec![AccountId::from(ACCOUNT)]).unwrap(), |
| 33 | + phantom: Default::default(), |
| 34 | + }, |
| 35 | + ..Default::default() |
| 36 | + } |
| 37 | + .build_storage() |
| 38 | + .unwrap() |
| 39 | + .into(); |
| 40 | + ext.execute_with(|| System::set_block_number(1)); |
| 41 | + ext |
| 42 | +} |
| 43 | + |
| 44 | +// transfer call |
| 45 | +fn call_transfer() -> RuntimeCall { |
| 46 | + let value = 100; |
| 47 | + RuntimeCall::Balances(BalancesCall::transfer_allow_death { |
| 48 | + dest: AccountId::from(OTHER_ACCOUNT).into(), |
| 49 | + value, |
| 50 | + }) |
| 51 | +} |
| 52 | + |
| 53 | +// remark call |
| 54 | +fn call_remark() -> RuntimeCall { |
| 55 | + let remark = vec![1, 2, 3]; |
| 56 | + RuntimeCall::System(SystemCall::remark { remark }) |
| 57 | +} |
| 58 | + |
| 59 | +// owner call |
| 60 | +fn call_owner_util() -> RuntimeCall { |
| 61 | + let netuid = 1; |
| 62 | + let serving_rate_limit = 2; |
| 63 | + RuntimeCall::AdminUtils(pallet_admin_utils::Call::sudo_set_serving_rate_limit { |
| 64 | + netuid, |
| 65 | + serving_rate_limit, |
| 66 | + }) |
| 67 | +} |
| 68 | + |
| 69 | +// critical call for Subtensor |
| 70 | +fn call_propose() -> RuntimeCall { |
| 71 | + let proposal = call_remark(); |
| 72 | + let proposal_len: u32 = proposal.using_encoded(|p| p.len() as u32); |
| 73 | + |
| 74 | + RuntimeCall::Triumvirate(pallet_collective::Call::propose { |
| 75 | + proposal: Box::new(call_remark()), |
| 76 | + length_bound: proposal_len, |
| 77 | + duration: 100_000_000_u32.into(), |
| 78 | + }) |
| 79 | +} |
| 80 | + |
| 81 | +// critical call for Subtensor |
| 82 | +fn call_root_register() -> RuntimeCall { |
| 83 | + RuntimeCall::SubtensorModule(pallet_subtensor::Call::root_register { |
| 84 | + hotkey: AccountId::from(ACCOUNT), |
| 85 | + }) |
| 86 | +} |
| 87 | + |
| 88 | +// triumvirate call |
| 89 | +fn call_triumvirate() -> RuntimeCall { |
| 90 | + RuntimeCall::TriumvirateMembers(pallet_membership::Call::change_key { |
| 91 | + new: AccountId::from(ACCOUNT).into(), |
| 92 | + }) |
| 93 | +} |
| 94 | + |
| 95 | +// senate call |
| 96 | +fn call_senate() -> RuntimeCall { |
| 97 | + RuntimeCall::SenateMembers(pallet_membership::Call::change_key { |
| 98 | + new: AccountId::from(ACCOUNT).into(), |
| 99 | + }) |
| 100 | +} |
| 101 | + |
| 102 | +// staking call |
| 103 | +fn call_add_stake() -> RuntimeCall { |
| 104 | + let amount_staked = 100; |
| 105 | + RuntimeCall::SubtensorModule(pallet_subtensor::Call::add_stake { |
| 106 | + hotkey: AccountId::from(DELEGATE).into(), |
| 107 | + amount_staked, |
| 108 | + }) |
| 109 | +} |
| 110 | + |
| 111 | +// register call, account as hotkey, delegate as coldkey |
| 112 | +fn call_register() -> RuntimeCall { |
| 113 | + let block_number: u64 = 1; |
| 114 | + let netuid: u16 = 2; |
| 115 | + let (nonce, work): (u64, Vec<u8>) = SubtensorModule::create_work_for_block_number( |
| 116 | + netuid, |
| 117 | + block_number, |
| 118 | + 0, |
| 119 | + &AccountId::from(ACCOUNT), |
| 120 | + ); |
| 121 | + |
| 122 | + RuntimeCall::SubtensorModule(pallet_subtensor::Call::register { |
| 123 | + netuid, |
| 124 | + block_number, |
| 125 | + nonce, |
| 126 | + work: work.clone(), |
| 127 | + hotkey: AccountId::from(ACCOUNT), |
| 128 | + coldkey: AccountId::from(DELEGATE), |
| 129 | + }) |
| 130 | +} |
| 131 | + |
| 132 | +fn verify_call_with_proxy_type(proxy_type: &ProxyType, call: &RuntimeCall) { |
| 133 | + assert_ok!(Proxy::proxy( |
| 134 | + RuntimeOrigin::signed(AccountId::from(DELEGATE)), |
| 135 | + AccountId::from(ACCOUNT).into(), |
| 136 | + None, |
| 137 | + Box::new(call.clone()), |
| 138 | + )); |
| 139 | + |
| 140 | + let filtered_event: RuntimeEvent = pallet_proxy::Event::ProxyExecuted { |
| 141 | + result: Err(SystemError::CallFiltered.into()), |
| 142 | + } |
| 143 | + .into(); |
| 144 | + |
| 145 | + // check if the filter works by checking the last event |
| 146 | + // filtered if the last event is SystemError::CallFiltered |
| 147 | + // not filtered if the last event is proxy executed done or any error from proxy call |
| 148 | + if proxy_type.filter(call) { |
| 149 | + let last_event = System::events().last().unwrap().event.clone(); |
| 150 | + assert_ne!(last_event, filtered_event); |
| 151 | + } else { |
| 152 | + System::assert_last_event(filtered_event); |
| 153 | + } |
| 154 | +} |
| 155 | + |
| 156 | +#[test] |
| 157 | +fn test_proxy_pallet() { |
| 158 | + let proxy_types = [ |
| 159 | + ProxyType::Any, |
| 160 | + ProxyType::Owner, |
| 161 | + ProxyType::NonCritical, |
| 162 | + ProxyType::NonTransfer, |
| 163 | + ProxyType::Senate, |
| 164 | + ProxyType::NonFungibile, |
| 165 | + ProxyType::Triumvirate, |
| 166 | + ProxyType::Governance, |
| 167 | + ProxyType::Staking, |
| 168 | + ProxyType::Registration, |
| 169 | + ]; |
| 170 | + |
| 171 | + let calls = [ |
| 172 | + call_transfer, |
| 173 | + call_remark, |
| 174 | + call_owner_util, |
| 175 | + call_propose, |
| 176 | + call_root_register, |
| 177 | + call_triumvirate, |
| 178 | + call_senate, |
| 179 | + call_add_stake, |
| 180 | + call_register, |
| 181 | + ]; |
| 182 | + |
| 183 | + for call in calls.iter() { |
| 184 | + for proxy_type in proxy_types.iter() { |
| 185 | + new_test_ext().execute_with(|| { |
| 186 | + assert_ok!(Proxy::add_proxy( |
| 187 | + RuntimeOrigin::signed(AccountId::from(ACCOUNT)), |
| 188 | + AccountId::from(DELEGATE).into(), |
| 189 | + *proxy_type, |
| 190 | + 0 |
| 191 | + )); |
| 192 | + |
| 193 | + verify_call_with_proxy_type(proxy_type, &call()); |
| 194 | + }); |
| 195 | + } |
| 196 | + } |
| 197 | +} |
0 commit comments