Skip to content

Commit 2b80315

Browse files
authored
Merge pull request #950 from opentensor/fix/childkey-emission-distibution
Fix/childkey emission distribution
2 parents b903817 + 81c8905 commit 2b80315

File tree

5 files changed

+727
-29
lines changed

5 files changed

+727
-29
lines changed

pallets/subtensor/src/coinbase/run_coinbase.rs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -199,59 +199,74 @@ 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);
202+
let childkey_take_proportion: I96F32 =
203+
I96F32::from_num(Self::get_childkey_take(hotkey, netuid))
204+
.saturating_div(I96F32::from_num(u16::MAX));
205+
let mut total_childkey_take: u64 = 0;
211206

212-
// --- 3. Track the remaining emission for accounting purposes.
213-
let mut remaining_emission: u64 = emission_minus_take;
207+
// --- 2. Track the remaining emission for accounting purposes.
208+
let mut remaining_emission: u64 = validating_emission;
214209

215-
// --- 4. Calculate the total stake of the hotkey, adjusted by the stakes of parents and children.
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: I96F32 =
229+
proportion_from_parent.saturating_mul(I96F32::from_num(validating_emission));
230+
231+
// --- 4.3 Childkey take as part of parent emission
232+
let child_emission_take: u64 = childkey_take_proportion
233+
.saturating_mul(parent_emission)
235234
.to_num::<u64>();
235+
total_childkey_take = total_childkey_take.saturating_add(child_emission_take);
236+
// NOTE: Only the validation emission should be split amongst parents.
237+
238+
// --- 4.4 Compute the remaining parent emission after the childkey's share is deducted.
239+
let parent_emission_take: u64 = parent_emission
240+
.to_num::<u64>()
241+
.saturating_sub(child_emission_take);
236242

237-
// --- 5.5. Accumulate emissions for the parent hotkey.
243+
// --- 4.5. Accumulate emissions for the parent hotkey.
238244
PendingdHotkeyEmission::<T>::mutate(parent, |parent_accumulated| {
239245
*parent_accumulated = parent_accumulated.saturating_add(parent_emission_take)
240246
});
241247

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);
248+
// --- 4.6. Subtract the parent's share from the remaining emission for this hotkey.
249+
remaining_emission = remaining_emission
250+
.saturating_sub(parent_emission_take)
251+
.saturating_sub(child_emission_take);
244252
}
245253
}
246254

247-
// --- 6. Add the remaining emission plus the hotkey's initial take to the pending emission for this hotkey.
255+
// --- 5. Add the remaining emission plus the hotkey's initial take to the pending emission for this hotkey.
248256
PendingdHotkeyEmission::<T>::mutate(hotkey, |hotkey_pending| {
249257
*hotkey_pending = hotkey_pending.saturating_add(
250258
remaining_emission
251-
.saturating_add(hotkey_take)
259+
.saturating_add(total_childkey_take)
252260
.saturating_add(mining_emission),
253261
)
254262
});
263+
264+
// --- 6. Update untouchable part of hotkey emission (that will not be distributed to nominators)
265+
// This doesn't include remaining_emission, which should be distributed in drain_hotkey_emission
266+
PendingdHotkeyEmissionUntouchable::<T>::mutate(hotkey, |hotkey_pending| {
267+
*hotkey_pending =
268+
hotkey_pending.saturating_add(total_childkey_take.saturating_add(mining_emission))
269+
});
255270
}
256271

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

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

276297
// --- 2 Update the block value to the current block number.
277298
LastHotkeyEmissionDrain::<T>::insert(hotkey, block_number);
@@ -280,13 +301,16 @@ impl<T: Config> Pallet<T> {
280301
let total_hotkey_stake: u64 = Self::get_total_stake_for_hotkey(hotkey);
281302

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

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

291315
// --- 6 Calculate the remaining emission after the hotkey's take.
292316
let mut remainder: u64 = emission_minus_take;
@@ -327,8 +351,11 @@ impl<T: Config> Pallet<T> {
327351
}
328352
}
329353

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);
354+
// --- 13 Finally, add the stake to the hotkey itself, including its take, the remaining emission, and
355+
// the untouchable_emission (part of pending hotkey emission that consists of mining emission and childkey take)
356+
let hotkey_new_tao: u64 = hotkey_take
357+
.saturating_add(remainder)
358+
.saturating_add(untouchable_emission);
332359
Self::increase_stake_on_hotkey_account(hotkey, hotkey_new_tao);
333360

334361
// --- 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)