Skip to content
Open
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
9 changes: 4 additions & 5 deletions pallets/subtensor/src/coinbase/block_step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
Self::run_auto_claim_root_divs(last_block_hash);
// --- 9. Populate root coldkey maps.
Self::populate_root_coldkey_staking_maps();

// Return ok.
Ok(())
}
Expand Down Expand Up @@ -229,9 +228,9 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
if next_value >= U110F18::saturating_from_num(Self::get_max_difficulty(netuid)) {
Self::get_max_difficulty(netuid)
} else if next_value <= U110F18::saturating_from_num(Self::get_min_difficulty(netuid)) {
Self::get_min_difficulty(netuid)
return Self::get_min_difficulty(netuid);
} else {
next_value.saturating_to_num::<u64>()
return next_value.saturating_to_num::<u64>();
}
}

Expand Down Expand Up @@ -263,9 +262,9 @@ impl<T: Config + pallet_drand::Config> Pallet<T> {
if next_value >= U110F18::saturating_from_num(Self::get_max_burn(netuid)) {
Self::get_max_burn(netuid)
} else if next_value <= U110F18::saturating_from_num(Self::get_min_burn(netuid)) {
Self::get_min_burn(netuid)
return Self::get_min_burn(netuid);
} else {
next_value.saturating_to_num::<u64>().into()
return next_value.saturating_to_num::<u64>().into();
}
}

Expand Down
1 change: 1 addition & 0 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ impl<T: Config> Pallet<T> {
pub fn run_coinbase(block_emission: U96F32) {
// --- 0. Get current block.
let current_block: u64 = Self::get_current_block_as_u64();
Self::update_flows(current_block);
log::debug!(
"Running coinbase for block {current_block:?} with block emission: {block_emission:?}"
);
Expand Down
90 changes: 61 additions & 29 deletions pallets/subtensor/src/coinbase/subnet_emissions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,62 @@ impl<T: Config> Pallet<T> {
.collect::<BTreeMap<NetUid, U96F32>>()
}

pub fn update_flows(block_u64: u64) {
let subnets: Vec<NetUid> = Self::get_all_subnet_netuids()
.into_iter()
.filter(|netuid| *netuid != NetUid::ROOT)
.collect();
for netuid_i in subnets.iter() {
Self::update_delayed_flows(*netuid_i, block_u64);
}
}

pub fn update_delayed_flows(netuid: NetUid, block_u64: u64) {
let tick_len: u64 = FlowTickLen::<T>::get();
if tick_len == 0 { return; }

let delay_len: u64 = FlowDelay::<T>::get();

// Drain flow for this block (per-block semantics)
let block_flow: i64 = SubnetTaoFlow::<T>::take(netuid);

// Schedule maturity (rounded up using current tick_len)
if block_flow != 0 {
let delayed_until = block_u64.saturating_add(delay_len);
let maturity_block =
((delayed_until.saturating_add(tick_len - 1)) / tick_len).saturating_mul(tick_len);

SubnetFlowAccumulator::<T>::mutate(netuid, maturity_block, |v| {
*v = v.saturating_add(block_flow);
});
}

// Pop matured flow for this exact block number
let delayed_flow: i64 = SubnetFlowAccumulator::<T>::take(netuid, block_u64);

// Per-step alpha in [0,1]
let alpha: I64F64 = I64F64::saturating_from_num(FlowEmaSmoothingFactor::<T>::get())
.safe_div(I64F64::saturating_from_num(i64::MAX));
let one: I64F64 = I64F64::saturating_from_num(1);

// Load previous EMA (or initialize)
let ema_prev: I64F64 = match SubnetEmaTaoFlow::<T>::get(netuid) {
Some((_b, prev)) => prev,
None => {
let init = I64F64::saturating_from_num(delayed_flow);
SubnetEmaTaoFlow::<T>::insert(netuid, (block_u64, init));
return;
}
};

// Standard EMA step
let ema_next: I64F64 =
(one.saturating_sub(alpha)).saturating_mul(ema_prev)
.saturating_add(alpha.saturating_mul(I64F64::saturating_from_num(delayed_flow)));

SubnetEmaTaoFlow::<T>::insert(netuid, (block_u64, ema_next));
}

pub fn record_tao_inflow(netuid: NetUid, tao: TaoCurrency) {
SubnetTaoFlow::<T>::mutate(netuid, |flow| {
*flow = flow.saturating_add(u64::from(tao) as i64);
Expand All @@ -47,43 +103,19 @@ impl<T: Config> Pallet<T> {

pub fn record_tao_outflow(netuid: NetUid, tao: TaoCurrency) {
SubnetTaoFlow::<T>::mutate(netuid, |flow| {
*flow = flow.saturating_sub(u64::from(tao) as i64)
*flow = flow.saturating_sub(u64::from(tao) as i64);
});
}

pub fn reset_tao_outflow(netuid: NetUid) {
SubnetTaoFlow::<T>::remove(netuid);
}

// Update SubnetEmaTaoFlow if needed and return its value for
// the current block
#[allow(dead_code)]
fn get_ema_flow(netuid: NetUid) -> I64F64 {
let current_block: u64 = Self::get_current_block_as_u64();

// Calculate net ema flow for the next block
let block_flow = I64F64::saturating_from_num(SubnetTaoFlow::<T>::get(netuid));
let (last_block, last_block_ema) =
SubnetEmaTaoFlow::<T>::get(netuid).unwrap_or((0, I64F64::saturating_from_num(0)));

// EMA flow already initialized
if last_block != current_block {
let flow_alpha = I64F64::saturating_from_num(FlowEmaSmoothingFactor::<T>::get())
.safe_div(I64F64::saturating_from_num(i64::MAX));
let one = I64F64::saturating_from_num(1);
let ema_flow = (one.saturating_sub(flow_alpha))
.saturating_mul(last_block_ema)
.saturating_add(flow_alpha.saturating_mul(block_flow));
SubnetEmaTaoFlow::<T>::insert(netuid, (current_block, ema_flow));

// Drop the accumulated flow in the last block
Self::reset_tao_outflow(netuid);
ema_flow
} else {
last_block_ema
}
pub fn get_ema_flow(netuid: NetUid) -> I64F64 {
let (_, last_block_ema) = SubnetEmaTaoFlow::<T>::get(netuid).unwrap_or((0, I64F64::saturating_from_num(0)));
last_block_ema
}


// Either the minimal EMA flow L = min{Si}, or an artificial
// cut off at some higher value A (TaoFlowCutoff)
// L = max {A, min{min{S[i], 0}}}
Expand Down
40 changes: 40 additions & 0 deletions pallets/subtensor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1457,6 +1457,46 @@ pub mod pallet {
pub type SubnetEmaTaoFlow<T: Config> =
StorageMap<_, Identity, NetUid, (u64, I64F64), OptionQuery>;

/// Flow tick len
#[pallet::type_value]
pub fn DefaultFlowTickLen<T: Config>() -> u64 {
1
}
/// --- ITEM ( flow tick len )
#[pallet::storage]
pub type FlowTickLen<T> = StorageValue<_, u64, ValueQuery, DefaultFlowTickLen<T>>;

/// Flow delay
#[pallet::type_value]
pub fn DefaultFlowDelay<T: Config>() -> u64 {
0
}
/// --- ITEM ( flow tick len )
#[pallet::storage]
pub type FlowDelay<T> = StorageValue<_, u64, ValueQuery, DefaultFlowDelay<T>>;

// Per-day Tao flow for subnets
#[pallet::storage]
pub type SubnetFlowAccumulator<T: Config> = StorageDoubleMap<
_,
Identity,
NetUid, // subnet id
Identity,
u64, // day
i64, // taoflow
ValueQuery,
DefaultZeroI64<T>
>;

/// Flow delay
#[pallet::type_value]
pub fn DefaultEmissionCap<T: Config>() -> u16 {
u16::MAX
}
/// --- ITEM ( max emission value )
#[pallet::storage]
pub type EmissionCap<T> = StorageValue<_, u16, ValueQuery, DefaultEmissionCap<T>>;

/// Default value for flow cutoff.
#[pallet::type_value]
pub fn DefaultFlowCutoff<T: Config>() -> I64F64 {
Expand Down
Loading