Skip to content

Commit 14102b6

Browse files
committed
Fix childkey take and miner emission distribution
1 parent c1a9211 commit 14102b6

File tree

5 files changed

+728
-31
lines changed

5 files changed

+728
-31
lines changed

pallets/subtensor/src/coinbase/run_coinbase.rs

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -199,59 +199,73 @@ impl<T: Config> Pallet<T> {
199199
mining_emission: u64,
200200
) {
201201
// --- 1. First, calculate the hotkey's share of the emission.
202-
let take_proportion: I64F64 = I64F64::from_num(Self::get_childkey_take(hotkey, netuid))
203-
.saturating_div(I64F64::from_num(u16::MAX));
204-
let hotkey_take: u64 = take_proportion
205-
.saturating_mul(I64F64::from_num(validating_emission))
206-
.to_num::<u64>();
207-
// NOTE: Only the validation emission should be split amongst parents.
208-
209-
// --- 2. Compute the remaining emission after the hotkey's share is deducted.
210-
let emission_minus_take: u64 = validating_emission.saturating_sub(hotkey_take);
211-
212-
// --- 3. Track the remaining emission for accounting purposes.
213-
let mut remaining_emission: u64 = emission_minus_take;
214-
215-
// --- 4. Calculate the total stake of the hotkey, adjusted by the stakes of parents and children.
202+
let childkey_take_proportion: I64F64 =
203+
I64F64::from_num(Self::get_childkey_take(hotkey, netuid))
204+
.saturating_div(I64F64::from_num(u16::MAX));
205+
let mut total_childkey_take: u64 = 0;
206+
207+
// --- 2. Track the remaining emission for accounting purposes.
208+
let mut remaining_emission: u64 = validating_emission;
209+
210+
// --- 3. Calculate the total stake of the hotkey, adjusted by the stakes of parents and children.
216211
// Parents contribute to the stake, while children reduce it.
217212
// If this value is zero, no distribution to anyone is necessary.
218213
let total_hotkey_stake: u64 = Self::get_stake_for_hotkey_on_subnet(hotkey, netuid);
219214
if total_hotkey_stake != 0 {
220-
// --- 5. If the total stake is not zero, iterate over each parent to determine their contribution to the hotkey's stake,
215+
// --- 4. If the total stake is not zero, iterate over each parent to determine their contribution to the hotkey's stake,
221216
// and calculate their share of the emission accordingly.
222217
for (proportion, parent) in Self::get_parents(hotkey, netuid) {
223-
// --- 5.1 Retrieve the parent's stake. This is the raw stake value including nominators.
218+
// --- 4.1 Retrieve the parent's stake. This is the raw stake value including nominators.
224219
let parent_stake: u64 = Self::get_total_stake_for_hotkey(&parent);
225220

226-
// --- 5.2 Calculate the portion of the hotkey's total stake contributed by this parent.
221+
// --- 4.2 Calculate the portion of the hotkey's total stake contributed by this parent.
227222
// Then, determine the parent's share of the remaining emission.
228223
let stake_from_parent: I96F32 = I96F32::from_num(parent_stake).saturating_mul(
229224
I96F32::from_num(proportion).saturating_div(I96F32::from_num(u64::MAX)),
230225
);
231226
let proportion_from_parent: I96F32 =
232227
stake_from_parent.saturating_div(I96F32::from_num(total_hotkey_stake));
233-
let parent_emission_take: u64 = proportion_from_parent
234-
.saturating_mul(I96F32::from_num(emission_minus_take))
228+
let parent_emission: u64 = proportion_from_parent
229+
.saturating_mul(I96F32::from_num(validating_emission))
235230
.to_num::<u64>();
236231

237-
// --- 5.5. Accumulate emissions for the parent hotkey.
232+
// --- 4.3 Childkey take as part of parent emission
233+
let child_emission_take: u64 = childkey_take_proportion
234+
.saturating_mul(I64F64::from_num(parent_emission))
235+
.to_num::<u64>();
236+
total_childkey_take = total_childkey_take.saturating_add(child_emission_take);
237+
// NOTE: Only the validation emission should be split amongst parents.
238+
239+
// --- 4.4 Compute the remaining parent emission after the childkey's share is deducted.
240+
let parent_emission_take: u64 = parent_emission.saturating_sub(child_emission_take);
241+
242+
// --- 4.5. Accumulate emissions for the parent hotkey.
238243
PendingdHotkeyEmission::<T>::mutate(parent, |parent_accumulated| {
239244
*parent_accumulated = parent_accumulated.saturating_add(parent_emission_take)
240245
});
241246

242-
// --- 5.6. Subtract the parent's share from the remaining emission for this hotkey.
243-
remaining_emission = remaining_emission.saturating_sub(parent_emission_take);
247+
// --- 4.6. Subtract the parent's share from the remaining emission for this hotkey.
248+
remaining_emission = remaining_emission
249+
.saturating_sub(parent_emission_take)
250+
.saturating_sub(child_emission_take);
244251
}
245252
}
246253

247-
// --- 6. Add the remaining emission plus the hotkey's initial take to the pending emission for this hotkey.
254+
// --- 5. Add the remaining emission plus the hotkey's initial take to the pending emission for this hotkey.
248255
PendingdHotkeyEmission::<T>::mutate(hotkey, |hotkey_pending| {
249256
*hotkey_pending = hotkey_pending.saturating_add(
250257
remaining_emission
251-
.saturating_add(hotkey_take)
258+
.saturating_add(total_childkey_take)
252259
.saturating_add(mining_emission),
253260
)
254261
});
262+
263+
// --- 6. Update untouchable part of hotkey emission (that will not be distributed to nominators)
264+
// This doesn't include remaining_emission, which should be distributed in drain_hotkey_emission
265+
PendingdHotkeyEmissionUntouchable::<T>::mutate(hotkey, |hotkey_pending| {
266+
*hotkey_pending =
267+
hotkey_pending.saturating_add(total_childkey_take.saturating_add(mining_emission))
268+
});
255269
}
256270

257271
//. --- 4. Drains the accumulated hotkey emission through to the nominators. The hotkey takes a proportion of the emission.
@@ -270,8 +284,14 @@ impl<T: Config> Pallet<T> {
270284
// --- 0. For accounting purposes record the total new added stake.
271285
let mut total_new_tao: u64 = 0;
272286

287+
// Get the untouchable part of pending hotkey emission, so that we don't distribute this part of
288+
// PendingdHotkeyEmission to nominators
289+
let untouchable_emission = PendingdHotkeyEmissionUntouchable::<T>::get(hotkey);
290+
let emission_to_distribute = emission.saturating_sub(untouchable_emission);
291+
273292
// --- 1.0 Drain the hotkey emission.
274293
PendingdHotkeyEmission::<T>::insert(hotkey, 0);
294+
PendingdHotkeyEmissionUntouchable::<T>::insert(hotkey, 0);
275295

276296
// --- 2 Update the block value to the current block number.
277297
LastHotkeyEmissionDrain::<T>::insert(hotkey, block_number);
@@ -280,13 +300,16 @@ impl<T: Config> Pallet<T> {
280300
let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey);
281301

282302
// --- 4 Calculate the emission take for the hotkey.
303+
// This is only the hotkey take. Childkey take was already deducted from validator emissions in
304+
// accumulate_hotkey_emission and now it is included in untouchable_emission.
283305
let take_proportion: I64F64 = I64F64::from_num(Delegates::<T>::get(hotkey))
284306
.saturating_div(I64F64::from_num(u16::MAX));
285-
let hotkey_take: u64 =
286-
(take_proportion.saturating_mul(I64F64::from_num(emission))).to_num::<u64>();
307+
let hotkey_take: u64 = (take_proportion
308+
.saturating_mul(I64F64::from_num(emission_to_distribute)))
309+
.to_num::<u64>();
287310

288-
// --- 5 Compute the remaining emission after deducting the hotkey's take.
289-
let emission_minus_take: u64 = emission.saturating_sub(hotkey_take);
311+
// --- 5 Compute the remaining emission after deducting the hotkey's take and untouchable_emission.
312+
let emission_minus_take: u64 = emission_to_distribute.saturating_sub(hotkey_take);
290313

291314
// --- 6 Calculate the remaining emission after the hotkey's take.
292315
let mut remainder: u64 = emission_minus_take;
@@ -327,8 +350,11 @@ impl<T: Config> Pallet<T> {
327350
}
328351
}
329352

330-
// --- 13 Finally, add the stake to the hotkey itself, including its take and the remaining emission.
331-
let hotkey_new_tao: u64 = hotkey_take.saturating_add(remainder);
353+
// --- 13 Finally, add the stake to the hotkey itself, including its take, the remaining emission, and
354+
// the untouchable_emission (part of pending hotkey emission that consists of mining emission and childkey take)
355+
let hotkey_new_tao: u64 = hotkey_take
356+
.saturating_add(remainder)
357+
.saturating_add(untouchable_emission);
332358
Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao);
333359

334360
// --- 14 Reset the stake delta for the hotkey.

pallets/subtensor/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,6 +796,16 @@ pub mod pallet {
796796
DefaultAccumulatedEmission<T>,
797797
>;
798798
#[pallet::storage]
799+
/// Map ( hot ) --> emission | Part of accumulated hotkey emission that will not be distributed to nominators.
800+
pub type PendingdHotkeyEmissionUntouchable<T: Config> = StorageMap<
801+
_,
802+
Blake2_128Concat,
803+
T::AccountId,
804+
u64,
805+
ValueQuery,
806+
DefaultAccumulatedEmission<T>,
807+
>;
808+
#[pallet::storage]
799809
/// Map ( hot, cold ) --> stake: i128 | Stake added/removed since last emission drain.
800810
pub type StakeDeltaSinceLastEmissionDrain<T: Config> = StorageDoubleMap<
801811
_,

0 commit comments

Comments
 (0)