Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

devnet deploy 3/25/2025 #1465

Merged
merged 12 commits into from
Mar 26, 2025
2 changes: 1 addition & 1 deletion pallets/admin-utils/src/tests/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ parameter_types! {
pub const InitialImmunityPeriod: u16 = 2;
pub const InitialMaxAllowedUids: u16 = 2;
pub const InitialBondsMovingAverage: u64 = 900_000;
pub const InitialBondsPenalty: u16 = 0;
pub const InitialBondsPenalty: u16 = u16::MAX;
pub const InitialStakePruningMin: u16 = 0;
pub const InitialFoundationDistribution: u64 = 0;
pub const InitialDefaultDelegateTake: u16 = 11_796; // 18% honest number.
Expand Down
26 changes: 18 additions & 8 deletions pallets/subtensor/src/coinbase/run_coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,17 +37,24 @@ impl<T: Config> Pallet<T> {
let current_block: u64 = Self::get_current_block_as_u64();
log::debug!("Current block: {:?}", current_block);

// --- 1. Get all netuids (filter out root and new subnet without first emission block)
// --- 1. Get all netuids (filter out root)
let subnets: Vec<u16> = Self::get_all_subnet_netuids()
.into_iter()
.filter(|netuid| *netuid != 0)
.filter(|netuid| FirstEmissionBlockNumber::<T>::get(*netuid).is_some())
.collect();
log::debug!("All subnet netuids: {:?}", subnets);
// Filter out subnets with no first emission block number.
let subnets_to_emit_to: Vec<u16> = subnets
.clone()
.into_iter()
.filter(|netuid| FirstEmissionBlockNumber::<T>::get(*netuid).is_some())
.collect();
log::debug!("Subnets to emit to: {:?}", subnets_to_emit_to);

// --- 2. Get sum of tao reserves ( in a later version we will switch to prices. )
let mut total_moving_prices: I96F32 = I96F32::saturating_from_num(0.0);
for netuid_i in subnets.iter() {
// Only get price EMA for subnets that we emit to.
for netuid_i in subnets_to_emit_to.iter() {
// Get and update the moving price of each subnet adding the total together.
total_moving_prices =
total_moving_prices.saturating_add(Self::get_moving_alpha_price(*netuid_i));
Expand All @@ -59,7 +66,8 @@ impl<T: Config> Pallet<T> {
let mut tao_in: BTreeMap<u16, I96F32> = BTreeMap::new();
let mut alpha_in: BTreeMap<u16, I96F32> = BTreeMap::new();
let mut alpha_out: BTreeMap<u16, I96F32> = BTreeMap::new();
for netuid_i in subnets.iter() {
// Only calculate for subnets that we are emitting to.
for netuid_i in subnets_to_emit_to.iter() {
// Get subnet price.
let price_i: I96F32 = Self::get_alpha_price(*netuid_i);
log::debug!("price_i: {:?}", price_i);
Expand Down Expand Up @@ -104,7 +112,7 @@ impl<T: Config> Pallet<T> {
// --- 4. Injection.
// Actually perform the injection of alpha_in, alpha_out and tao_in into the subnet pool.
// This operation changes the pool liquidity each block.
for netuid_i in subnets.iter() {
for netuid_i in subnets_to_emit_to.iter() {
// Inject Alpha in.
let alpha_in_i: u64 = tou64!(*alpha_in.get(netuid_i).unwrap_or(&asfloat!(0)));
SubnetAlphaInEmission::<T>::insert(*netuid_i, alpha_in_i);
Expand Down Expand Up @@ -136,7 +144,7 @@ impl<T: Config> Pallet<T> {
// Owner cuts are accumulated and then fed to the drain at the end of this func.
let cut_percent: I96F32 = Self::get_float_subnet_owner_cut();
let mut owner_cuts: BTreeMap<u16, I96F32> = BTreeMap::new();
for netuid_i in subnets.iter() {
for netuid_i in subnets_to_emit_to.iter() {
// Get alpha out.
let alpha_out_i: I96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0));
log::debug!("alpha_out_i: {:?}", alpha_out_i);
Expand All @@ -155,7 +163,7 @@ impl<T: Config> Pallet<T> {

// --- 6. Seperate out root dividends in alpha and sell them into tao.
// Then accumulate those dividends for later.
for netuid_i in subnets.iter() {
for netuid_i in subnets_to_emit_to.iter() {
// Get remaining alpha out.
let alpha_out_i: I96F32 = *alpha_out.get(netuid_i).unwrap_or(&asfloat!(0.0));
log::debug!("alpha_out_i: {:?}", alpha_out_i);
Expand Down Expand Up @@ -200,12 +208,14 @@ impl<T: Config> Pallet<T> {
}

// --- 7 Update moving prices after using them in the emission calculation.
for netuid_i in subnets.iter() {
// Only update price EMA for subnets that we emit to.
for netuid_i in subnets_to_emit_to.iter() {
// Update moving prices after using them above.
Self::update_moving_price(*netuid_i);
}

// --- 7. Drain pending emission through the subnet based on tempo.
// Run the epoch for *all* subnets, even if we don't emit anything.
for &netuid in subnets.iter() {
// Pass on subnets that have not reached their tempo.
if Self::should_run_epoch(netuid, current_block) {
Expand Down
242 changes: 242 additions & 0 deletions pallets/subtensor/src/tests/coinbase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1889,3 +1889,245 @@ fn test_drain_pending_emission_no_miners_all_drained() {
assert_abs_diff_eq!(new_stake, emission.saturating_add(init_stake), epsilon = 1);
});
}

#[test]
fn test_drain_pending_emission_zero_emission() {
new_test_ext(1).execute_with(|| {
let netuid = add_dynamic_network(&U256::from(1), &U256::from(2));
let hotkey = U256::from(3);
let coldkey = U256::from(4);
let miner_hk = U256::from(5);
let miner_ck = U256::from(6);
let init_stake: u64 = 100_000_000_000_000;
let tempo = 2;
SubtensorModule::set_tempo(netuid, tempo);
// Set weight-set limit to 0.
SubtensorModule::set_weights_set_rate_limit(netuid, 0);

register_ok_neuron(netuid, hotkey, coldkey, 0);
register_ok_neuron(netuid, miner_hk, miner_ck, 0);
// Give non-zero stake
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
&hotkey, &coldkey, netuid, init_stake,
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey),
init_stake
);

// Set the weight of root TAO to be 0%, so only alpha is effective.
SubtensorModule::set_tao_weight(0);

run_to_block_no_epoch(netuid, 50);

// Run epoch for initial setup.
SubtensorModule::epoch(netuid, 0);

// Set weights on miner
assert_ok!(SubtensorModule::set_weights(
RuntimeOrigin::signed(hotkey),
netuid,
vec![0, 1, 2],
vec![0, 0, 1],
0,
));

run_to_block_no_epoch(netuid, 50);

// Clear incentive and dividends.
Incentive::<Test>::remove(netuid);
Dividends::<Test>::remove(netuid);

// Set the emission to be ZERO.
SubtensorModule::drain_pending_emission(netuid, 0, 0, 0, 0);

// Get the new stake of the hotkey.
let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey);
// We expect the stake to remain unchanged.
assert_eq!(new_stake, init_stake);

// Check that the incentive and dividends are set by epoch.
assert!(Incentive::<Test>::get(netuid).iter().sum::<u16>() > 0);
assert!(Dividends::<Test>::get(netuid).iter().sum::<u16>() > 0);
});
}

#[test]
fn test_run_coinbase_not_started() {
new_test_ext(1).execute_with(|| {
let netuid = 1;
let tempo = 2;

let sn_owner_hk = U256::from(7);
let sn_owner_ck = U256::from(8);

add_network_without_emission_block(netuid, tempo, 0);
assert_eq!(FirstEmissionBlockNumber::<Test>::get(netuid), None);

SubnetOwner::<Test>::insert(netuid, sn_owner_ck);
SubnetOwnerHotkey::<Test>::insert(netuid, sn_owner_hk);

let hotkey = U256::from(3);
let coldkey = U256::from(4);
let miner_hk = U256::from(5);
let miner_ck = U256::from(6);
let init_stake: u64 = 100_000_000_000_000;
let tempo = 2;
SubtensorModule::set_tempo(netuid, tempo);
// Set weight-set limit to 0.
SubtensorModule::set_weights_set_rate_limit(netuid, 0);

register_ok_neuron(netuid, hotkey, coldkey, 0);
register_ok_neuron(netuid, miner_hk, miner_ck, 0);
register_ok_neuron(netuid, sn_owner_hk, sn_owner_ck, 0);
// Give non-zero stake
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
&hotkey, &coldkey, netuid, init_stake,
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey),
init_stake
);

// Set the weight of root TAO to be 0%, so only alpha is effective.
SubtensorModule::set_tao_weight(0);

run_to_block_no_epoch(netuid, 30);

// Run epoch for initial setup.
SubtensorModule::epoch(netuid, 0);

// Set weights on miner
assert_ok!(SubtensorModule::set_weights(
RuntimeOrigin::signed(hotkey),
netuid,
vec![0, 1, 2],
vec![0, 0, 1],
0,
));

// Clear incentive and dividends.
Incentive::<Test>::remove(netuid);
Dividends::<Test>::remove(netuid);

// Step so tempo should run.
next_block_no_epoch(netuid);
next_block_no_epoch(netuid);
next_block_no_epoch(netuid);
let current_block = System::block_number();
assert!(SubtensorModule::should_run_epoch(netuid, current_block));

// Run coinbase with emission.
SubtensorModule::run_coinbase(I96F32::saturating_from_num(100_000_000));

// We expect that the epoch ran.
assert_eq!(BlocksSinceLastStep::<Test>::get(netuid), 0);

// Get the new stake of the hotkey. We expect no emissions.
let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey);
// We expect the stake to remain unchanged.
assert_eq!(new_stake, init_stake);

// Check that the incentive and dividends are set.
assert!(Incentive::<Test>::get(netuid).iter().sum::<u16>() > 0);
assert!(Dividends::<Test>::get(netuid).iter().sum::<u16>() > 0);
});
}

#[test]
fn test_run_coinbase_not_started_start_after() {
new_test_ext(1).execute_with(|| {
let netuid = 1;
let tempo = 2;

let sn_owner_hk = U256::from(7);
let sn_owner_ck = U256::from(8);

add_network_without_emission_block(netuid, tempo, 0);
assert_eq!(FirstEmissionBlockNumber::<Test>::get(netuid), None);

SubnetOwner::<Test>::insert(netuid, sn_owner_ck);
SubnetOwnerHotkey::<Test>::insert(netuid, sn_owner_hk);

let hotkey = U256::from(3);
let coldkey = U256::from(4);
let miner_hk = U256::from(5);
let miner_ck = U256::from(6);
let init_stake: u64 = 100_000_000_000_000;
let tempo = 2;
SubtensorModule::set_tempo(netuid, tempo);
// Set weight-set limit to 0.
SubtensorModule::set_weights_set_rate_limit(netuid, 0);

register_ok_neuron(netuid, hotkey, coldkey, 0);
register_ok_neuron(netuid, miner_hk, miner_ck, 0);
register_ok_neuron(netuid, sn_owner_hk, sn_owner_ck, 0);
// Give non-zero stake
SubtensorModule::increase_stake_for_hotkey_and_coldkey_on_subnet(
&hotkey, &coldkey, netuid, init_stake,
);
assert_eq!(
SubtensorModule::get_total_stake_for_hotkey(&hotkey),
init_stake
);

// Set the weight of root TAO to be 0%, so only alpha is effective.
SubtensorModule::set_tao_weight(0);

run_to_block_no_epoch(netuid, 30);

// Run epoch for initial setup.
SubtensorModule::epoch(netuid, 0);

// Set weights on miner
assert_ok!(SubtensorModule::set_weights(
RuntimeOrigin::signed(hotkey),
netuid,
vec![0, 1, 2],
vec![0, 0, 1],
0,
));

// Clear incentive and dividends.
Incentive::<Test>::remove(netuid);
Dividends::<Test>::remove(netuid);

// Step so tempo should run.
next_block_no_epoch(netuid);
next_block_no_epoch(netuid);
next_block_no_epoch(netuid);
let current_block = System::block_number();
assert!(SubtensorModule::should_run_epoch(netuid, current_block));

// Run coinbase with emission.
SubtensorModule::run_coinbase(I96F32::saturating_from_num(100_000_000));
// We expect that the epoch ran.
assert_eq!(BlocksSinceLastStep::<Test>::get(netuid), 0);

let block_number = DurationOfStartCall::get();
run_to_block_no_epoch(netuid, block_number);

let current_block = System::block_number();

// Run start call.
assert_ok!(SubtensorModule::start_call(
RuntimeOrigin::signed(sn_owner_ck),
netuid
));
assert_eq!(
FirstEmissionBlockNumber::<Test>::get(netuid),
Some(current_block + 1)
);

// Run coinbase with emission.
SubtensorModule::run_coinbase(I96F32::saturating_from_num(100_000_000));
// We expect that the epoch ran.
assert_eq!(BlocksSinceLastStep::<Test>::get(netuid), 0);

// Get the new stake of the hotkey. We expect no emissions.
let new_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey);
// We expect the stake to remain unchanged.
assert!(new_stake > init_stake);
log::info!("new_stake: {}", new_stake);
});
}
22 changes: 0 additions & 22 deletions pallets/subtensor/src/tests/epoch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -983,28 +983,6 @@ fn test_512_graph_random_weights() {
// });
// }

fn next_block_no_epoch(netuid: u16) -> u64 {
// high tempo to skip automatic epochs in on_initialize
let high_tempo: u16 = u16::MAX - 1;
let old_tempo: u16 = SubtensorModule::get_tempo(netuid);

SubtensorModule::set_tempo(netuid, high_tempo);
let new_block = next_block();
SubtensorModule::set_tempo(netuid, old_tempo);

new_block
}

fn run_to_block_no_epoch(netuid: u16, n: u64) {
// high tempo to skip automatic epochs in on_initialize
let high_tempo: u16 = u16::MAX - 1;
let old_tempo: u16 = SubtensorModule::get_tempo(netuid);

SubtensorModule::set_tempo(netuid, high_tempo);
run_to_block(n);
SubtensorModule::set_tempo(netuid, old_tempo);
}

// Test bonds exponential moving average over a sequence of epochs.
#[test]
fn test_bonds() {
Expand Down
Loading
Loading