Skip to content
Merged
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
53 changes: 49 additions & 4 deletions pallets/subtensor/src/coinbase/subnet_emissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,19 +243,64 @@ impl<T: Config> Pallet<T> {
#[allow(dead_code)]
fn get_shares_flow(subnets_to_emit_to: &[NetUid]) -> BTreeMap<NetUid, U64F64> {
let net_flow_enabled = NetTaoFlowEnabled::<T>::get();
let zero = I64F64::saturating_from_num(0);

// Always update the protocol EMA (keeps it warm for when toggled on)
let ema_flows: BTreeMap<NetUid, I64F64> = subnets_to_emit_to
// Always update both EMAs (keeps protocol EMA warm for when toggled on).
// Fixes #2667: protocol EMA accumulator was only drained when enabled,
// causing a shock on toggle.
let subnet_emas: Vec<(NetUid, I64F64, I64F64)> = subnets_to_emit_to
.iter()
.map(|netuid| {
let user_ema = Self::get_ema_flow(*netuid);
let protocol_ema = Self::update_ema_protocol_flow(*netuid);
(*netuid, user_ema, protocol_ema)
})
.collect();

// When net flow is enabled, normalize protocol EMA so that its
// positive total matches the user EMA positive total. This prevents
// subsidy concentration: as emissions concentrate on fewer subnets,
// their protocol EMA grows, but the normalization factor shrinks to
// compensate, keeping the deduction proportional to user demand.
let norm_factor = if net_flow_enabled {
let (user_positive_ema_sum, protocol_positive_ema_sum) =
subnet_emas
.iter()
.fold((zero, zero), |(su, sp), (_, u, p)| {
(
su.saturating_add((*u).max(zero)),
sp.saturating_add((*p).max(zero)),
)
});
let one = I64F64::saturating_from_num(1);
if protocol_positive_ema_sum > zero {
user_positive_ema_sum
.safe_div(protocol_positive_ema_sum)
.min(one)
} else {
zero
}
} else {
zero
};
log::debug!("Protocol normalization factor: {norm_factor:?}");

let ema_flows: BTreeMap<NetUid, I64F64> = subnet_emas
.into_iter()
.map(|(netuid, user_ema, protocol_ema)| {
let net = if net_flow_enabled {
user_ema.saturating_sub(protocol_ema)
// Only scale positive protocol cost by norm_factor. Negative
// protocol cost (root drain > emissions) is a benefit, kept as-is.
let scaled_protocol = if protocol_ema > zero {
norm_factor.saturating_mul(protocol_ema)
} else {
protocol_ema
};
user_ema.saturating_sub(scaled_protocol)
} else {
user_ema
};
(*netuid, net)
(netuid, net)
})
.collect();
log::debug!("EMA flows (net_flow_enabled={net_flow_enabled}): {ema_flows:?}");
Expand Down
Loading