diff --git a/pallets/subtensor/src/coinbase/run_coinbase.rs b/pallets/subtensor/src/coinbase/run_coinbase.rs index 1e74298a56..5d59e25cf6 100644 --- a/pallets/subtensor/src/coinbase/run_coinbase.rs +++ b/pallets/subtensor/src/coinbase/run_coinbase.rs @@ -292,7 +292,7 @@ impl Pallet { // --- 8 Iterate over each nominator and get all viable stake. let mut total_viable_nominator_stake: u64 = total_hotkey_stake; for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { - if LastAddStakeIncrease::::get(hotkey, nominator) > last_emission_drain { + if false && LastAddStakeIncrease::::get(hotkey, nominator) > last_emission_drain { total_viable_nominator_stake = total_viable_nominator_stake.saturating_sub(nominator_stake); } @@ -303,7 +303,7 @@ impl Pallet { for (nominator, nominator_stake) in Stake::::iter_prefix(hotkey) { // --- 10 Check if the stake was manually increased by the user since the last emission drain for this hotkey. // If it was, skip this nominator as they will not receive their proportion of the emission. - if LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_emission_drain { + if false && LastAddStakeIncrease::::get(hotkey, nominator.clone()) > last_emission_drain { continue; } diff --git a/pallets/subtensor/tests/coinbase.rs b/pallets/subtensor/tests/coinbase.rs index a6c1acde1b..d327ed19b5 100644 --- a/pallets/subtensor/tests/coinbase.rs +++ b/pallets/subtensor/tests/coinbase.rs @@ -1,7 +1,8 @@ #![allow(unused, clippy::indexing_slicing, clippy::panic, clippy::unwrap_used)] use crate::mock::*; mod mock; -// use frame_support::{assert_err, assert_ok}; +use frame_support::{assert_err, assert_ok}; +use frame_system::Config; use sp_core::U256; // Test the ability to hash all sorts of hotkeys. @@ -154,3 +155,144 @@ fn test_set_and_get_hotkey_emission_tempo() { assert_eq!(updated_tempo, new_tempo); }); } + +#[test] +fn test_coinbase_nominator_drainage() { + new_test_ext(1).execute_with(|| { + // 1. Set up the network and accounts + let netuid: u16 = 1; + let hotkey = U256::from(0); + let coldkey = U256::from(3); + let nominator1 = U256::from(1); + let nominator2 = U256::from(2); + + log::debug!("Setting up network with netuid: {}", netuid); + log::debug!("Hotkey: {:?}, Coldkey: {:?}", hotkey, coldkey); + log::debug!("Nominators: {:?}, {:?}", nominator1, nominator2); + + // 2. Create network and register neuron + add_network(netuid, 1, 0); + register_ok_neuron(netuid, hotkey, coldkey, 100000); + SubtensorModule::create_account_if_non_existent(&coldkey, &hotkey); + + log::debug!("Network created and neuron registered"); + + // 3. Set up balances and stakes + SubtensorModule::add_balance_to_coldkey_account(&coldkey, 1000); + SubtensorModule::add_balance_to_coldkey_account(&nominator1, 1500); + SubtensorModule::add_balance_to_coldkey_account(&nominator2, 1500); + + log::debug!("Balances added to accounts"); + + // 4. Make the hotkey a delegate + assert_ok!(SubtensorModule::do_become_delegate( + <::RuntimeOrigin>::signed(coldkey), + hotkey, + (u16::MAX as u64 / 10) as u16 + )); + + log::debug!("Hotkey became a delegate with minimum take"); + + // Add stakes for nominators + SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(nominator1), + hotkey, + 100, + ); + + SubtensorModule::add_stake( + <::RuntimeOrigin>::signed(nominator2), + hotkey, + 100, + ); + + // Log the stakes for hotkey, nominator1, and nominator2 + log::debug!( + "Initial stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", + SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey), + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey), + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey) + ); + log::debug!("Stakes added for nominators"); + + // 5. Set emission and verify initial states + SubtensorModule::set_emission_values(&[netuid], vec![10]).unwrap(); + assert_eq!(SubtensorModule::get_subnet_emission_value(netuid), 10); + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + assert_eq!(SubtensorModule::get_total_stake_for_hotkey(&hotkey), 200); + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); + + log::debug!("Emission set and initial states verified"); + + // 6. Set hotkey emission tempo + SubtensorModule::set_hotkey_emission_tempo(1); + log::debug!("Hotkey emission tempo set to 1"); + + // 7. Simulate blocks and check emissions + next_block(); + assert_eq!(SubtensorModule::get_pending_emission(netuid), 10); + log::debug!( + "After first block, pending emission: {}", + SubtensorModule::get_pending_emission(netuid) + ); + + next_block(); + assert_eq!(SubtensorModule::get_pending_emission(netuid), 0); + assert_eq!(SubtensorModule::get_pending_hotkey_emission(&hotkey), 0); + log::debug!("After second block, pending emission drained"); + + // 8. Check final stakes + let hotkey_stake = SubtensorModule::get_stake_for_coldkey_and_hotkey(&coldkey, &hotkey); + let nominator1_stake = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator1, &hotkey); + let nominator2_stake = + SubtensorModule::get_stake_for_coldkey_and_hotkey(&nominator2, &hotkey); + + log::debug!( + "Final stakes - Hotkey: {}, Nominator1: {}, Nominator2: {}", + hotkey_stake, + nominator1_stake, + nominator2_stake + ); + + // 9. Verify distribution + let min_take = SubtensorModule::get_min_delegate_take() as u64; + let total_emission = 20; // 10 per block for 2 blocks + let hotkey_emission = total_emission * min_take / u16::MAX as u64; + let remaining_emission = total_emission - hotkey_emission; + let nominator_emission = remaining_emission / 2; + + log::debug!( + "Calculated emissions - Hotkey: {}, Each Nominator: {}", + hotkey_emission, + nominator_emission + ); + + // Debug: Print the actual stakes + log::debug!("Actual hotkey stake: {}", hotkey_stake); + log::debug!("Actual nominator1 stake: {}", nominator1_stake); + log::debug!("Actual nominator2 stake: {}", nominator2_stake); + + // Debug: Check the total stake for the hotkey + let total_stake = SubtensorModule::get_total_stake_for_hotkey(&hotkey); + log::debug!("Total stake for hotkey: {}", total_stake); + + // Assertions + assert_eq!(hotkey_stake, 2, "Hotkey stake mismatch"); + assert_eq!( + nominator1_stake, + 100 + nominator_emission, + "Nominator1 stake mismatch" + ); + assert_eq!( + nominator2_stake, + 100 + nominator_emission, + "Nominator2 stake mismatch" + ); + + // 10. Check total stake + assert_eq!(total_stake, 200 + total_emission, "Total stake mismatch"); + + log::debug!("Test completed"); + }); +} diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 5ffb0863ac..28a3953e2c 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -142,7 +142,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 196, + spec_version: 199, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,