Skip to content

Commit

Permalink
Make devnet-ready mergable with main
Browse files Browse the repository at this point in the history
  • Loading branch information
gztensor committed Oct 29, 2024
1 parent cae4366 commit d81cbaa
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 46 deletions.
64 changes: 37 additions & 27 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,69 +265,65 @@ impl<T: Config> Pallet<T> {
// --- 1.0 Drain the hotkey emission.
PendingdHotkeyEmission::<T>::insert(hotkey, 0);

// --- 2 Retrieve the last time this hotkey's emissions were drained.
let last_emission_drain: u64 = LastHotkeyEmissionDrain::<T>::get(hotkey);

// --- 3 Update the block value to the current block number.
// --- 2 Update the block value to the current block number.
LastHotkeyEmissionDrain::<T>::insert(hotkey, block_number);

// --- 4 Retrieve the total stake for the hotkey from all nominations.
// --- 3 Retrieve the total stake for the hotkey from all nominations.
let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey);

// --- 5 Calculate the emission take for the hotkey.
// --- 4 Calculate the emission take for the hotkey.
let take_proportion: I64F64 = I64F64::from_num(Delegates::<T>::get(hotkey))
.saturating_div(I64F64::from_num(u16::MAX));
let hotkey_take: u64 =
(take_proportion.saturating_mul(I64F64::from_num(emission))).to_num::<u64>();

// --- 6 Compute the remaining emission after deducting the hotkey's take.
// --- 5 Compute the remaining emission after deducting the hotkey's take.
let emission_minus_take: u64 = emission.saturating_sub(hotkey_take);

// --- 7 Calculate the remaining emission after the hotkey's take.
// --- 6 Calculate the remaining emission after the hotkey's take.
let mut remainder: u64 = emission_minus_take;

// --- 8 Iterate over each nominator and get all viable stake.
// --- 7 Iterate over each nominator and get all viable stake.
let mut total_viable_nominator_stake: u64 = total_hotkey_stake;
for (nominator, nominator_stake) in Stake::<T>::iter_prefix(hotkey) {
if LastAddStakeIncrease::<T>::get(hotkey, nominator) > last_emission_drain {
total_viable_nominator_stake =
total_viable_nominator_stake.saturating_sub(nominator_stake);
}
for (nominator, _) in Stake::<T>::iter_prefix(hotkey) {
let nonviable_nomintaor_stake = Self::get_nonviable_stake(hotkey, &nominator);

total_viable_nominator_stake =
total_viable_nominator_stake.saturating_sub(nonviable_nomintaor_stake);
}

// --- 9 Iterate over each nominator.
// --- 8 Iterate over each nominator.
if total_viable_nominator_stake != 0 {
for (nominator, nominator_stake) in Stake::<T>::iter_prefix(hotkey) {
// --- 10 Check if the stake was manually increased by the user since the last emission drain for this hotkey.
// --- 9 Check if the stake was manually increased by the user since the last emission drain for this hotkey.
// If it was, skip this nominator as they will not receive their proportion of the emission.
if LastAddStakeIncrease::<T>::get(hotkey, nominator.clone()) > last_emission_drain {
continue;
}
let viable_nominator_stake =
nominator_stake.saturating_sub(Self::get_nonviable_stake(hotkey, &nominator));

// --- 11 Calculate this nominator's share of the emission.
let nominator_emission: I64F64 = I64F64::from_num(emission_minus_take)
.saturating_mul(I64F64::from_num(nominator_stake))
// --- 10 Calculate this nominator's share of the emission.
let nominator_emission: I64F64 = I64F64::from_num(viable_nominator_stake)
.checked_div(I64F64::from_num(total_viable_nominator_stake))
.unwrap_or(I64F64::from_num(0));
.unwrap_or(I64F64::from_num(0))
.saturating_mul(I64F64::from_num(emission_minus_take));

// --- 12 Increase the stake for the nominator.
// --- 11 Increase the stake for the nominator.
Self::increase_stake_on_coldkey_hotkey_account(
&nominator,
hotkey,
nominator_emission.to_num::<u64>(),
);

// --- 13* Record event and Subtract the nominator's emission from the remainder.
// --- 12* Record event and Subtract the nominator's emission from the remainder.
total_new_tao = total_new_tao.saturating_add(nominator_emission.to_num::<u64>());
remainder = remainder.saturating_sub(nominator_emission.to_num::<u64>());
}
}

// --- 14 Finally, add the stake to the hotkey itself, including its take and the remaining emission.
// --- 13 Finally, add the stake to the hotkey itself, including its take and the remaining emission.
let hotkey_new_tao: u64 = hotkey_take.saturating_add(remainder);
Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao);

// --- 15 Record new tao creation event and return the amount created.
// --- 14 Record new tao creation event and return the amount created.
total_new_tao = total_new_tao.saturating_add(hotkey_new_tao);
total_new_tao
}
Expand Down Expand Up @@ -382,4 +378,18 @@ impl<T: Config> Pallet<T> {
let remainder = block_plus_netuid.rem_euclid(tempo_plus_one);
(tempo as u64).saturating_sub(remainder)
}

/// Calculates the nonviable stake for a nominator.
/// The nonviable stake is the stake that was added by the nominator since the last emission drain.
/// This stake will not receive emission until the next emission drain.
/// Note: if the stake delta is below zero, we return zero. We don't allow more stake than the nominator has.
pub fn get_nonviable_stake(hotkey: &T::AccountId, nominator: &T::AccountId) -> u64 {
let stake_delta = StakeDeltaSinceLastEmissionDrain::<T>::get(hotkey, nominator);
if stake_delta.is_negative() {
0
} else {
// Should never fail the into, but we handle it anyway.
stake_delta.try_into().unwrap_or(u64::MAX)
}
}
}
13 changes: 9 additions & 4 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,11 @@ pub mod pallet {
0
}
#[pallet::type_value]
/// Default stake delta.
pub fn DefaultStakeDelta<T: Config>() -> i128 {
0
}
#[pallet::type_value]
/// Default stakes per interval.
pub fn DefaultStakesPerInterval<T: Config>() -> (u64, u64) {
(0, 0)
Expand Down Expand Up @@ -791,16 +796,16 @@ pub mod pallet {
DefaultAccumulatedEmission<T>,
>;
#[pallet::storage]
/// Map ( hot, cold ) --> block_number | Last add stake increase.
pub type LastAddStakeIncrease<T: Config> = StorageDoubleMap<
/// Map ( hot, cold ) --> stake: i128 | Stake added/removed since last emission drain.
pub type StakeDeltaSinceLastEmissionDrain<T: Config> = StorageDoubleMap<
_,
Blake2_128Concat,
T::AccountId,
Identity,
T::AccountId,
u64,
i128,
ValueQuery,
DefaultAccountTake<T>,
DefaultStakeDelta<T>,
>;
#[pallet::storage]
/// DMAP ( parent, netuid ) --> Vec<(proportion,child)>
Expand Down
6 changes: 4 additions & 2 deletions pallets/subtensor/src/staking/add_stake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,10 @@ impl<T: Config> Pallet<T> {
Error::<T>::StakeRateLimitExceeded
);

// Set the last time the stake increased for nominator drain protection.
LastAddStakeIncrease::<T>::insert(&hotkey, &coldkey, Self::get_current_block_as_u64());
// Track this addition in the stake delta.
StakeDeltaSinceLastEmissionDrain::<T>::mutate(&hotkey, &coldkey, |stake_delta| {
*stake_delta = stake_delta.saturating_add_unsigned(stake_to_be_added as u128);
});

// If coldkey is not owner of the hotkey, it's a nomination stake.
if !Self::coldkey_owns_hotkey(&coldkey, &hotkey) {
Expand Down
48 changes: 35 additions & 13 deletions pallets/subtensor/src/swap/swap_hotkey.rs
Original file line number Diff line number Diff line change
Expand Up @@ -206,33 +206,42 @@ impl<T: Config> Pallet<T> {
Delegates::<T>::insert(new_hotkey, old_delegate_take);
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
}
// 9. Swap all subnet specific info.

// 9. swap PendingdHotkeyEmission
if PendingdHotkeyEmission::<T>::contains_key(old_hotkey) {
let old_pending_hotkey_emission = PendingdHotkeyEmission::<T>::get(old_hotkey);
PendingdHotkeyEmission::<T>::remove(old_hotkey);
PendingdHotkeyEmission::<T>::insert(new_hotkey, old_pending_hotkey_emission);
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
}

// 10. Swap all subnet specific info.
let all_netuids: Vec<u16> = Self::get_all_subnet_netuids();
for netuid in all_netuids {
// 9.1 Remove the previous hotkey and insert the new hotkey from membership.
// 10.1 Remove the previous hotkey and insert the new hotkey from membership.
// IsNetworkMember( hotkey, netuid ) -> bool -- is the hotkey a subnet member.
let is_network_member: bool = IsNetworkMember::<T>::get(old_hotkey, netuid);
IsNetworkMember::<T>::remove(old_hotkey, netuid);
IsNetworkMember::<T>::insert(new_hotkey, netuid, is_network_member);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));

// 9.2 Swap Uids + Keys.
// 10.2 Swap Uids + Keys.
// Keys( netuid, hotkey ) -> uid -- the uid the hotkey has in the network if it is a member.
// Uids( netuid, hotkey ) -> uid -- the uids that the hotkey has.
if is_network_member {
// 9.2.1 Swap the UIDS
// 10.2.1 Swap the UIDS
if let Ok(old_uid) = Uids::<T>::try_get(netuid, old_hotkey) {
Uids::<T>::remove(netuid, old_hotkey);
Uids::<T>::insert(netuid, new_hotkey, old_uid);
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 2));

// 9.2.2 Swap the keys.
// 10.2.2 Swap the keys.
Keys::<T>::insert(netuid, old_uid, new_hotkey.clone());
weight.saturating_accrue(T::DbWeight::get().reads_writes(0, 1));
}
}

// 9.3 Swap Prometheus.
// 10.3 Swap Prometheus.
// Prometheus( netuid, hotkey ) -> prometheus -- the prometheus data that a hotkey has in the network.
if is_network_member {
if let Ok(old_prometheus_info) = Prometheus::<T>::try_get(netuid, old_hotkey) {
Expand All @@ -242,7 +251,7 @@ impl<T: Config> Pallet<T> {
}
}

// 9.4. Swap axons.
// 10.4. Swap axons.
// Axons( netuid, hotkey ) -> axon -- the axon that the hotkey has.
if is_network_member {
if let Ok(old_axon_info) = Axons::<T>::try_get(netuid, old_hotkey) {
Expand All @@ -252,7 +261,7 @@ impl<T: Config> Pallet<T> {
}
}

// 9.5 Swap WeightCommits
// 10.5 Swap WeightCommits
// WeightCommits( hotkey ) --> Vec<u64> -- the weight commits for the hotkey.
if is_network_member {
if let Ok(old_weight_commits) = WeightCommits::<T>::try_get(netuid, old_hotkey) {
Expand All @@ -262,7 +271,7 @@ impl<T: Config> Pallet<T> {
}
}

// 9.6. Swap the subnet loaded emission.
// 10.6. Swap the subnet loaded emission.
// LoadedEmission( netuid ) --> Vec<(hotkey, u64)> -- the loaded emission for the subnet.
if is_network_member {
if let Some(mut old_loaded_emission) = LoadedEmission::<T>::get(netuid) {
Expand All @@ -277,7 +286,7 @@ impl<T: Config> Pallet<T> {
}
}

// 9.7. Swap neuron TLS certificates.
// 10.7. Swap neuron TLS certificates.
// NeuronCertificates( netuid, hotkey ) -> Vec<u8> -- the neuron certificate for the hotkey.
if is_network_member {
if let Ok(old_neuron_certificates) =
Expand All @@ -290,7 +299,7 @@ impl<T: Config> Pallet<T> {
}
}

// 10. Swap Stake.
// 11. Swap Stake.
// Stake( hotkey, coldkey ) -> stake -- the stake that the hotkey controls on behalf of the coldkey.
let stakes: Vec<(T::AccountId, u64)> = Stake::<T>::iter_prefix(old_hotkey).collect();
// Clear the entire old prefix here.
Expand Down Expand Up @@ -320,7 +329,7 @@ impl<T: Config> Pallet<T> {
weight.saturating_accrue(T::DbWeight::get().reads_writes(1, 1));
}

// 11. Swap ChildKeys.
// 12. Swap ChildKeys.
// ChildKeys( parent, netuid ) --> Vec<(proportion,child)> -- the child keys of the parent.
for netuid in Self::get_all_subnet_netuids() {
// Get the children of the old hotkey for this subnet
Expand All @@ -331,7 +340,7 @@ impl<T: Config> Pallet<T> {
ChildKeys::<T>::insert(new_hotkey, netuid, my_children);
}

// 12. Swap ParentKeys.
// 13. Swap ParentKeys.
// ParentKeys( child, netuid ) --> Vec<(proportion,parent)> -- the parent keys of the child.
for netuid in Self::get_all_subnet_netuids() {
// Get the parents of the old hotkey for this subnet
Expand All @@ -355,6 +364,19 @@ impl<T: Config> Pallet<T> {
}
}

// 14. Swap Stake Delta for all coldkeys.
for (coldkey, stake_delta) in StakeDeltaSinceLastEmissionDrain::<T>::iter_prefix(old_hotkey)
{
let new_stake_delta = StakeDeltaSinceLastEmissionDrain::<T>::get(new_hotkey, &coldkey);
StakeDeltaSinceLastEmissionDrain::<T>::insert(
new_hotkey,
&coldkey,
new_stake_delta.saturating_add(stake_delta),
);
StakeDeltaSinceLastEmissionDrain::<T>::remove(old_hotkey, &coldkey);
weight.saturating_accrue(T::DbWeight::get().reads_writes(2, 2));
}

// Return successful after swapping all the relevant terms.
Ok(())
}
Expand Down

0 comments on commit d81cbaa

Please sign in to comment.