Skip to content

Commit 0010253

Browse files
committed
fix: clean up AllowancesStorage on subnet deregistration
Add PrecompileCleanupInterface trait to allow the pallet to invoke cross-crate storage cleanup when a subnet is removed. The precompiles crate iterates and removes all AllowancesStorage entries matching the dissolved netuid, preventing stale EVM approvals from carrying over when the netuid is recycled.
1 parent 7ac0548 commit 0010253

7 files changed

Lines changed: 71 additions & 3 deletions

File tree

pallets/subtensor/src/coinbase/root.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ impl<T: Config> Pallet<T> {
218218
Self::destroy_alpha_in_out_stakes(netuid)?;
219219
T::SwapInterface::clear_protocol_liquidity(netuid)?;
220220
T::CommitmentsInterface::purge_netuid(netuid);
221+
T::PrecompileCleanupInterface::purge_netuid(netuid);
221222

222223
// --- Remove the network
223224
Self::remove_network(netuid);

pallets/subtensor/src/lib.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2747,3 +2747,8 @@ impl<T> ProxyInterface<T> for () {
27472747
pub trait CommitmentsInterface {
27482748
fn purge_netuid(netuid: NetUid);
27492749
}
2750+
2751+
/// EVM precompile crates implement this to clean up storage when a subnet is removed.
2752+
pub trait PrecompileCleanupInterface {
2753+
fn purge_netuid(netuid: NetUid);
2754+
}

pallets/subtensor/src/macros/config.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use frame_support::pallet_macros::pallet_section;
66
#[pallet_section]
77
mod config {
88

9-
use crate::{CommitmentsInterface, GetAlphaForTao, GetTaoForAlpha};
9+
use crate::{CommitmentsInterface, GetAlphaForTao, GetTaoForAlpha, PrecompileCleanupInterface};
1010
use pallet_commitments::GetCommitments;
1111
use subtensor_runtime_common::AuthorshipInfo;
1212
use subtensor_swap_interface::{SwapEngine, SwapHandler};
@@ -60,6 +60,9 @@ mod config {
6060
/// Interface to clean commitments on network dissolution.
6161
type CommitmentsInterface: CommitmentsInterface;
6262

63+
/// Interface to clean EVM precompile storage on network dissolution.
64+
type PrecompileCleanupInterface: PrecompileCleanupInterface;
65+
6366
/// Rate limit for associating an EVM key.
6467
type EvmKeyAssociateRateLimit: Get<u64>;
6568

pallets/subtensor/src/tests/mock.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,7 @@ impl crate::Config for Test {
319319
type GetCommitments = ();
320320
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
321321
type CommitmentsInterface = CommitmentsI;
322+
type PrecompileCleanupInterface = PrecompileCleanupI;
322323
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
323324
type AuthorshipProvider = MockAuthorshipProvider;
324325
type WeightInfo = ();
@@ -361,6 +362,11 @@ impl CommitmentsInterface for CommitmentsI {
361362
fn purge_netuid(_netuid: NetUid) {}
362363
}
363364

365+
pub struct PrecompileCleanupI;
366+
impl PrecompileCleanupInterface for PrecompileCleanupI {
367+
fn purge_netuid(_netuid: NetUid) {}
368+
}
369+
364370
parameter_types! {
365371
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
366372
BlockWeights::get().max_block;

precompiles/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ mod metagraph;
5555
mod neuron;
5656
mod proxy;
5757
mod sr25519;
58-
mod staking;
58+
pub mod staking;
5959
mod storage_query;
6060
mod subnet;
6161
mod uid_lookup;

precompiles/src/staking.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,22 @@ pub type AllowancesStorage = StorageDoubleMap<
7474
ValueQuery,
7575
>;
7676

77+
/// Remove all AllowancesStorage entries whose key contains the given netuid.
78+
pub fn purge_netuid_allowances(netuid: u16) {
79+
let to_remove: Vec<(H160, (H160, u16))> = AllowancesStorage::iter()
80+
.filter_map(|(approver, (spender, n), _)| {
81+
if n == netuid {
82+
Some((approver, (spender, n)))
83+
} else {
84+
None
85+
}
86+
})
87+
.collect();
88+
for (approver, key) in to_remove {
89+
AllowancesStorage::remove(approver, key);
90+
}
91+
}
92+
7793
// Old StakingPrecompile had ETH-precision in values, which was not alligned with Substrate API. So
7894
// it's kinda deprecated, but exists for backward compatibility. Eventually, we should remove it
7995
// to stop supporting both precompiles.
@@ -895,3 +911,32 @@ fn try_u64_from_u256(value: U256) -> Result<u64, PrecompileFailure> {
895911
exit_status: ExitError::Other("the value is outside of u64 bounds".into()),
896912
})
897913
}
914+
915+
#[cfg(test)]
916+
mod tests {
917+
use super::*;
918+
919+
#[test]
920+
fn purge_netuid_allowances_removes_only_target_netuid() {
921+
sp_io::TestExternalities::default().execute_with(|| {
922+
let approver = H160::from_low_u64_be(1);
923+
let spender = H160::from_low_u64_be(2);
924+
let netuid_a: u16 = 5;
925+
let netuid_b: u16 = 7;
926+
927+
AllowancesStorage::insert(approver, (spender, netuid_a), U256::from(100));
928+
AllowancesStorage::insert(approver, (spender, netuid_b), U256::from(200));
929+
930+
purge_netuid_allowances(netuid_a);
931+
932+
assert_eq!(
933+
AllowancesStorage::get(approver, (spender, netuid_a)),
934+
U256::zero(),
935+
);
936+
assert_eq!(
937+
AllowancesStorage::get(approver, (spender, netuid_b)),
938+
U256::from(200),
939+
);
940+
});
941+
}
942+
}

runtime/src/lib.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ use pallet_subtensor::rpc_info::{
4141
stake_info::StakeInfo,
4242
subnet_info::{SubnetHyperparams, SubnetHyperparamsV2, SubnetInfo, SubnetInfov2},
4343
};
44-
use pallet_subtensor::{CommitmentsInterface, ProxyInterface};
44+
use pallet_subtensor::{CommitmentsInterface, PrecompileCleanupInterface, ProxyInterface};
4545
use pallet_subtensor_proxy as pallet_proxy;
4646
use pallet_subtensor_swap_runtime_api::{SimSwapResult, SubnetPrice};
4747
use pallet_subtensor_utility as pallet_utility;
@@ -878,6 +878,13 @@ impl CommitmentsInterface for CommitmentsI {
878878
}
879879
}
880880

881+
pub struct PrecompileCleanupI;
882+
impl PrecompileCleanupInterface for PrecompileCleanupI {
883+
fn purge_netuid(netuid: NetUid) {
884+
subtensor_precompiles::staking::purge_netuid_allowances(<u16 as From<NetUid>>::from(netuid));
885+
}
886+
}
887+
881888
parameter_types! {
882889
pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
883890
BlockWeights::get().max_block;
@@ -1199,6 +1206,7 @@ impl pallet_subtensor::Config for Runtime {
11991206
type GetCommitments = GetCommitmentsStruct;
12001207
type MaxImmuneUidsPercentage = MaxImmuneUidsPercentage;
12011208
type CommitmentsInterface = CommitmentsI;
1209+
type PrecompileCleanupInterface = PrecompileCleanupI;
12021210
type EvmKeyAssociateRateLimit = EvmKeyAssociateRateLimit;
12031211
type AuthorshipProvider = BlockAuthorFromAura<Aura>;
12041212
type WeightInfo = pallet_subtensor::weights::SubstrateWeight<Runtime>;

0 commit comments

Comments
 (0)