Skip to content

Commit d6bc13d

Browse files
committed
Filter for incorrect sudo calls
1 parent 780bd7a commit d6bc13d

File tree

6 files changed

+132
-1
lines changed

6 files changed

+132
-1
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/subtensor/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ sha2.workspace = true
5555
rand_chacha.workspace = true
5656
pallet-crowdloan.workspace = true
5757
pallet-subtensor-proxy.workspace = true
58+
pallet-sudo.workspace = true
5859

5960
[dev-dependencies]
6061
pallet-balances = { workspace = true, features = ["std"] }
@@ -117,6 +118,7 @@ std = [
117118
"pallet-subtensor-swap/std",
118119
"subtensor-swap-interface/std",
119120
"pallet-subtensor-utility/std",
121+
"pallet-sudo/std",
120122
"safe-math/std",
121123
"share-pool/std",
122124
"ark-serialize/std",

pallets/subtensor/src/tests/mock.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ frame_support::construct_runtime!(
4747
Swap: pallet_subtensor_swap::{Pallet, Call, Storage, Event<T>} = 12,
4848
Crowdloan: pallet_crowdloan::{Pallet, Call, Storage, Event<T>} = 13,
4949
Proxy: pallet_subtensor_proxy = 14,
50+
Sudo: pallet_sudo::{Pallet, Call, Storage, Event<T>} = 15,
5051
}
5152
);
5253

@@ -471,6 +472,12 @@ impl InstanceFilter<RuntimeCall> for subtensor_runtime_common::ProxyType {
471472
}
472473
}
473474

475+
impl pallet_sudo::Config for Test {
476+
type RuntimeEvent = RuntimeEvent;
477+
type RuntimeCall = RuntimeCall;
478+
type WeightInfo = pallet_sudo::weights::SubstrateWeight<Test>;
479+
}
480+
474481
mod test_crypto {
475482
use super::KEY_TYPE;
476483
use sp_core::{

pallets/subtensor/src/tests/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,4 @@ mod swap_hotkey;
3131
mod swap_hotkey_with_subnet;
3232
mod uids;
3333
mod weights;
34+
mod tx_extension;
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
use frame_support::assert_ok;
2+
use frame_support::dispatch::GetDispatchInfo;
3+
use crate::tests::mock::{new_test_ext, RuntimeCall, RuntimeOrigin, SubtensorCall};
4+
use subtensor_runtime_common::{NetUid, TaoCurrency};
5+
use sp_core::U256;
6+
use sp_runtime::traits::{TransactionExtension, TxBaseImplication, ValidateResult};
7+
use crate::transaction_extension::SubtensorTransactionExtension;
8+
9+
use super::mock::*;
10+
use crate::*;
11+
12+
fn some_call() -> RuntimeCall {
13+
let hotkey = U256::from(0);
14+
let amount_staked = TaoCurrency::from(5000);
15+
let netuid = NetUid::from(1);
16+
RuntimeCall::SubtensorModule(SubtensorCall::add_stake {
17+
hotkey,
18+
netuid,
19+
amount_staked,
20+
})
21+
}
22+
fn sudo_extrinsic(inner: RuntimeCall) -> RuntimeCall {
23+
RuntimeCall::Sudo(pallet_sudo::Call::sudo {
24+
call: Box::new(inner),
25+
})
26+
}
27+
28+
fn validate_ext(
29+
origin: RuntimeOrigin,
30+
call: &RuntimeCall,
31+
) -> ValidateResult<Option<<Test as frame_system::Config>::AccountId>, RuntimeCall> {
32+
let ext = SubtensorTransactionExtension::<Test>::new();
33+
34+
ext.validate(
35+
origin,
36+
call,
37+
&call.get_dispatch_info(),
38+
0,
39+
(),
40+
&TxBaseImplication(()),
41+
TransactionSource::External,
42+
)
43+
}
44+
#[test]
45+
fn sudo_signed_by_correct_key_is_valid() {
46+
new_test_ext(1).execute_with(|| {
47+
let sudo_key: <Test as frame_system::Config>::AccountId = U256::from(42);
48+
pallet_sudo::Key::<Test>::put(sudo_key);
49+
let sudo_call = sudo_extrinsic(some_call());
50+
51+
// Signed origin with correct sudo key
52+
let origin = RuntimeOrigin::signed(sudo_key);
53+
let res = validate_ext(origin, &sudo_call);
54+
assert_ok!(res);
55+
});
56+
}
57+
58+
#[test]
59+
fn sudo_signed_by_wrong_account_is_rejected() {
60+
new_test_ext(1).execute_with(|| {
61+
let sudo_key: <Test as frame_system::Config>::AccountId = U256::from(42);
62+
// Set sudo key in storage
63+
pallet_sudo::Key::<Test>::put(sudo_key);
64+
let sudo_call = sudo_extrinsic(some_call());
65+
// Wrong signer
66+
let origin = RuntimeOrigin::signed(U256::from(99));
67+
let res = validate_ext(origin, &sudo_call);
68+
assert!(
69+
matches!(
70+
res,
71+
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner))
72+
)
73+
);
74+
});
75+
}
76+
77+
#[test]
78+
fn sudo_when_no_sudo_key_configured_is_rejected() {
79+
new_test_ext(1).execute_with(|| {
80+
// Remove sudo key
81+
pallet_sudo::Key::<Test>::kill();
82+
let sudo_call = sudo_extrinsic(some_call());
83+
let origin = RuntimeOrigin::signed(U256::from(42));
84+
let res = validate_ext(origin, &sudo_call);
85+
assert!(
86+
matches!(
87+
res,
88+
Err(TransactionValidityError::Invalid(InvalidTransaction::BadSigner))
89+
)
90+
);
91+
});
92+
}
93+
94+
#[test]
95+
fn non_sudo_extrinsic_does_not_trigger_filter() {
96+
new_test_ext(1).execute_with(|| {
97+
let origin = RuntimeOrigin::signed(U256::from(42));
98+
let call = some_call();
99+
let res = validate_ext(origin, &call);
100+
assert!(res.is_ok());
101+
});
102+
}

pallets/subtensor/src/transaction_extension.rs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use sp_runtime::traits::{
1313
};
1414
use sp_runtime::transaction_validity::{
1515
TransactionSource, TransactionValidity, TransactionValidityError, ValidTransaction,
16+
InvalidTransaction
1617
};
18+
use pallet_sudo::Call as SudoCall;
1719
use sp_std::marker::PhantomData;
1820
use sp_std::vec::Vec;
1921
use subtensor_macros::freeze_struct;
@@ -85,7 +87,7 @@ where
8587
}
8688
}
8789

88-
impl<T: Config + Send + Sync + TypeInfo + pallet_balances::Config>
90+
impl<T: Config + Send + Sync + TypeInfo + pallet_balances::Config + pallet_sudo::Config>
8991
TransactionExtension<<T as frame_system::Config>::RuntimeCall>
9092
for SubtensorTransactionExtension<T>
9193
where
@@ -94,6 +96,7 @@ where
9496
<T as frame_system::Config>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + Clone,
9597
<T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>>,
9698
<T as frame_system::Config>::RuntimeCall: IsSubType<BalancesCall<T>>,
99+
<T as frame_system::Config>::RuntimeCall: IsSubType<SudoCall<T>>,
97100
{
98101
const IDENTIFIER: &'static str = "SubtensorTransactionExtension";
99102

@@ -121,6 +124,21 @@ where
121124
return Ok((Default::default(), None, origin));
122125
};
123126

127+
// Check validity of the signer for sudo call
128+
if let Some(_sudo_call) = IsSubType::<pallet_sudo::Call<T>>::is_sub_type(call) {
129+
let sudo_key = pallet_sudo::pallet::Key::<T>::get();
130+
131+
// No sudo key configured → reject
132+
let Some(expected_who) = sudo_key else {
133+
return Err(InvalidTransaction::BadSigner.into());
134+
};
135+
136+
// Signer does not match the sudo key → reject
137+
if *who != expected_who {
138+
return Err(InvalidTransaction::BadSigner.into());
139+
}
140+
}
141+
124142
// Verify ColdkeySwapScheduled map for coldkey
125143
match call.is_sub_type() {
126144
// Whitelist

0 commit comments

Comments
 (0)