Skip to content

fix: map to hotkey not uid #1774

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: devnet-ready
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pallets/admin-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,8 +121,8 @@ pub mod pallet {
Metagraph,
/// Enum for neuron precompile
Neuron,
/// Enum for UID lookup precompile
UidLookup,
/// Enum for hotkey lookup precompile
HotkeyLookup,
/// Enum for alpha precompile
Alpha,
}
Expand Down
13 changes: 10 additions & 3 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1675,9 +1675,16 @@ pub mod pallet {
/// ==== EVM related storage ====
/// =============================
#[pallet::storage]
/// --- DMAP (netuid, uid) --> (H160, last_block_where_ownership_was_proven)
pub type AssociatedEvmAddress<T: Config> =
StorageDoubleMap<_, Twox64Concat, NetUid, Twox64Concat, u16, (H160, u64), OptionQuery>;
/// --- DMAP (netuid, hotkey) --> (H160, last_block_where_ownership_was_proven)
pub type AssociatedEvmAddress<T: Config> = StorageDoubleMap<
_,
Twox64Concat,
NetUid,
Twox64Concat,
T::AccountId,
(H160, u64),
OptionQuery,
>;

/// ==================
/// ==== Genesis =====
Expand Down
4 changes: 3 additions & 1 deletion pallets/subtensor/src/macros/hooks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,9 @@ mod hooks {
// Reset max burn
.saturating_add(migrations::migrate_reset_max_burn::migrate_reset_max_burn::<T>())
// Migrate ColdkeySwapScheduled structure to new format
.saturating_add(migrations::migrate_coldkey_swap_scheduled::migrate_coldkey_swap_scheduled::<T>());
.saturating_add(migrations::migrate_coldkey_swap_scheduled::migrate_coldkey_swap_scheduled::<T>())
// Migrate AssociatedEvmAddress from UID to Hotkey
.saturating_add(migrations::migrate_evm_address_to_hotkey::migrate_evm_address_to_hotkey::<T>());
weight
}

Expand Down
105 changes: 105 additions & 0 deletions pallets/subtensor/src/migrations/migrate_evm_address_to_hotkey.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use super::*;
use frame_support::{
pallet_prelude::{OptionQuery, Twox64Concat},
storage_alias,
traits::Get,
weights::Weight,
};
use log::info;
use sp_core::H160;

const LOG_TARGET: &str = "migrate_evm_address_to_hotkey";

/// Module containing deprecated storage format for AssociatedEvmAddress
pub mod deprecated_evm_address_format {
use super::*;

#[storage_alias]
pub(super) type AssociatedEvmAddress<T: Config> =
StorageDoubleMap<Pallet<T>, Twox64Concat, u16, Twox64Concat, u16, (H160, u64), OptionQuery>;
}

/// Migrate AssociatedEvmAddress from (netuid, uid) -> (evm_address, block) to (netuid, hotkey) -> (evm_address, block)
pub fn migrate_evm_address_to_hotkey<T: Config>() -> Weight {
let mut weight = T::DbWeight::get().reads(1);
let migration_name = "Migrate AssociatedEvmAddress from UID to Hotkey";
let migration_name_bytes = migration_name.as_bytes().to_vec();

// Check if migration has already run
if HasMigrationRun::<T>::get(&migration_name_bytes) {
info!(
target: LOG_TARGET,
"Migration '{}' has already run. Skipping.",
migration_name
);
return Weight::zero();
}

info!(target: LOG_TARGET, ">>> Starting Migration: {}", migration_name);

let mut migrated_count: u64 = 0;
let mut orphaned_count: u64 = 0;
let mut storage_reads: u64 = 0;
let mut storage_writes: u64 = 0;

// Create a vector to store the old entries
let mut old_entries = Vec::new();

// Read all old entries
deprecated_evm_address_format::AssociatedEvmAddress::<T>::iter().for_each(
|(netuid, uid, (evm_address, block))| {
old_entries.push((netuid, uid, evm_address, block));
storage_reads = storage_reads.saturating_add(1);
},
);

weight = weight.saturating_add(T::DbWeight::get().reads(old_entries.len() as u64));

// Clear the old storage
let _ = deprecated_evm_address_format::AssociatedEvmAddress::<T>::clear(u32::MAX, None);
weight = weight.saturating_add(T::DbWeight::get().writes(1));

// Migrate each entry
for (netuid, uid, evm_address, block) in old_entries {
// Look up the hotkey for this uid on this subnet
if let Ok(hotkey) = Keys::<T>::try_get(netuid, uid) {
storage_reads = storage_reads.saturating_add(1);

// Store with the new format using hotkey
AssociatedEvmAddress::<T>::insert(netuid, &hotkey, (evm_address, block));
storage_writes = storage_writes.saturating_add(1);
migrated_count = migrated_count.saturating_add(1);

weight = weight.saturating_add(T::DbWeight::get().reads_writes(1, 1));

info!(
target: LOG_TARGET,
"Migrated EVM address {} from UID {} to hotkey {:?} on subnet {}",
evm_address, uid, hotkey, netuid
);
} else {
// No hotkey found for this UID - the neuron may have been deregistered
orphaned_count = orphaned_count.saturating_add(1);
weight = weight.saturating_add(T::DbWeight::get().reads(1));

info!(
target: LOG_TARGET,
"WARNING: Orphaned EVM address {} for UID {} on subnet {} - no hotkey found",
evm_address, uid, netuid
);
}
}

// Mark migration as complete
HasMigrationRun::<T>::insert(&migration_name_bytes, true);
storage_writes = storage_writes.saturating_add(1);
weight = weight.saturating_add(T::DbWeight::get().writes(1));

info!(
target: LOG_TARGET,
"Migration {} finished. Migrated: {}, Orphaned: {}, Storage reads: {}, Storage writes: {}",
migration_name, migrated_count, orphaned_count, storage_reads, storage_writes
);

weight
}
1 change: 1 addition & 0 deletions pallets/subtensor/src/migrations/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod migrate_commit_reveal_v2;
pub mod migrate_create_root_network;
pub mod migrate_delete_subnet_21;
pub mod migrate_delete_subnet_3;
pub mod migrate_evm_address_to_hotkey;
pub mod migrate_fix_is_network_member;
pub mod migrate_identities_v2;
pub mod migrate_init_total_issuance;
Expand Down
12 changes: 5 additions & 7 deletions pallets/subtensor/src/utils/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ impl<T: Config> Pallet<T> {
signature.0[64] = signature.0[64].saturating_sub(27);
}

let uid = Self::get_uid_for_net_and_hotkey(netuid, &hotkey)?;

let block_hash = keccak_256(block_number.encode().as_ref());
let message = [hotkey.encode().as_ref(), block_hash.as_ref()].concat();
let public = signature
Expand All @@ -74,7 +72,7 @@ impl<T: Config> Pallet<T> {

let current_block_number = Self::get_current_block_as_u64();

AssociatedEvmAddress::<T>::insert(netuid, uid, (evm_key, current_block_number));
AssociatedEvmAddress::<T>::insert(netuid, &hotkey, (evm_key, current_block_number));

Self::deposit_event(Event::EvmKeyAssociated {
netuid,
Expand All @@ -86,17 +84,17 @@ impl<T: Config> Pallet<T> {
Ok(())
}

pub fn uid_lookup(netuid: NetUid, evm_key: H160, limit: u16) -> Vec<(u16, u64)> {
pub fn hotkey_lookup(netuid: NetUid, evm_key: H160, limit: u16) -> Vec<(T::AccountId, u64)> {
let mut ret_val = AssociatedEvmAddress::<T>::iter_prefix(netuid)
.take(limit as usize)
.filter_map(|(uid, (stored_evm_key, block_associated))| {
.filter_map(|(hotkey, (stored_evm_key, block_associated))| {
if stored_evm_key != evm_key {
return None;
}

Some((uid, block_associated))
Some((hotkey, block_associated))
})
.collect::<Vec<(u16, u64)>>();
.collect::<Vec<(T::AccountId, u64)>>();
ret_val.sort_by(|(_, block1), (_, block2)| block1.cmp(block2));
ret_val
}
Expand Down
31 changes: 20 additions & 11 deletions precompiles/src/uid_lookup.rs → precompiles/src/hotkey_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@ use core::marker::PhantomData;

use frame_support::dispatch::{GetDispatchInfo, PostDispatchInfo};
use pallet_evm::PrecompileHandle;
use parity_scale_codec::Encode;
use precompile_utils::{EvmResult, prelude::Address};
use sp_runtime::traits::{Dispatchable, StaticLookup};
use sp_std::vec::Vec;

use crate::PrecompileExt;

pub(crate) struct UidLookupPrecompile<R>(PhantomData<R>);
pub(crate) struct HotkeyLookupPrecompile<R>(PhantomData<R>);

impl<R> PrecompileExt<R::AccountId> for UidLookupPrecompile<R>
impl<R> PrecompileExt<R::AccountId> for HotkeyLookupPrecompile<R>
where
R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config,
R::AccountId: From<[u8; 32]>,
Expand All @@ -25,7 +26,7 @@ where
}

#[precompile_utils::precompile]
impl<R> UidLookupPrecompile<R>
impl<R> HotkeyLookupPrecompile<R>
where
R: frame_system::Config + pallet_subtensor::Config + pallet_evm::Config,
R::AccountId: From<[u8; 32]>,
Expand All @@ -36,18 +37,26 @@ where
+ Dispatchable<PostInfo = PostDispatchInfo>,
<<R as frame_system::Config>::Lookup as StaticLookup>::Source: From<R::AccountId>,
{
#[precompile::public("uidLookup(uint16,address,uint16)")]
#[precompile::public("hotkeyLookup(uint16,address,uint16)")]
#[precompile::view]
fn uid_lookup(
fn hotkey_lookup(
_handle: &mut impl PrecompileHandle,
netuid: u16,
evm_address: Address,
limit: u16,
) -> EvmResult<Vec<(u16, u64)>> {
Ok(pallet_subtensor::Pallet::<R>::uid_lookup(
netuid.into(),
evm_address.0,
limit,
))
) -> EvmResult<Vec<(Address, u64)>> {
let results =
pallet_subtensor::Pallet::<R>::hotkey_lookup(netuid.into(), evm_address.0, limit);

// Convert AccountId to Address for EVM compatibility
Ok(results
.into_iter()
.map(|(account_id, block)| {
let mut bytes = [0u8; 20];
let account_bytes = account_id.encode();
bytes.copy_from_slice(&account_bytes[..20.min(account_bytes.len())]);
(Address::from(bytes), block)
})
.collect())
}
}
10 changes: 5 additions & 5 deletions precompiles/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,25 +28,25 @@ use crate::alpha::*;
use crate::balance_transfer::*;
use crate::ed25519::*;
use crate::extensions::*;
use crate::hotkey_lookup::*;
use crate::metagraph::*;
use crate::neuron::*;
use crate::sr25519::*;
use crate::staking::*;
use crate::storage_query::*;
use crate::subnet::*;
use crate::uid_lookup::*;

mod alpha;
mod balance_transfer;
mod ed25519;
mod extensions;
mod hotkey_lookup;
mod metagraph;
mod neuron;
mod sr25519;
mod staking;
mod storage_query;
mod subnet;
mod uid_lookup;
pub struct Precompiles<R>(PhantomData<R>);

impl<R> Default for Precompiles<R>
Expand Down Expand Up @@ -117,7 +117,7 @@ where
hash(NeuronPrecompile::<R>::INDEX),
hash(StakingPrecompileV2::<R>::INDEX),
hash(StorageQueryPrecompile::<R>::INDEX),
hash(UidLookupPrecompile::<R>::INDEX),
hash(HotkeyLookupPrecompile::<R>::INDEX),
hash(AlphaPrecompile::<R>::INDEX),
]
}
Expand Down Expand Up @@ -185,8 +185,8 @@ where
a if a == hash(NeuronPrecompile::<R>::INDEX) => {
NeuronPrecompile::<R>::try_execute::<R>(handle, PrecompileEnum::Neuron)
}
a if a == hash(UidLookupPrecompile::<R>::INDEX) => {
UidLookupPrecompile::<R>::try_execute::<R>(handle, PrecompileEnum::UidLookup)
a if a == hash(HotkeyLookupPrecompile::<R>::INDEX) => {
HotkeyLookupPrecompile::<R>::try_execute::<R>(handle, PrecompileEnum::HotkeyLookup)
}
a if a == hash(StorageQueryPrecompile::<R>::INDEX) => {
Some(StorageQueryPrecompile::<R>::execute(handle))
Expand Down
Loading