diff --git a/pallets/subtensor/src/staking/stake_utils.rs b/pallets/subtensor/src/staking/stake_utils.rs index 0a3659b6a..b69160a9a 100644 --- a/pallets/subtensor/src/staking/stake_utils.rs +++ b/pallets/subtensor/src/staking/stake_utils.rs @@ -57,7 +57,14 @@ impl Pallet { } } pub fn update_moving_price(netuid: u16) { - let alpha: I96F32 = SubnetMovingAlpha::::get(); + let blocks_since_registration = I96F32::saturating_from_num( + Self::get_current_block_as_u64().saturating_sub(NetworkRegisteredAt::::get(netuid)), + ); + // 7200 * 14 = 100_800 is the halving time + let alpha: I96F32 = + SubnetMovingAlpha::::get().saturating_mul(blocks_since_registration.safe_div( + blocks_since_registration.saturating_add(I96F32::saturating_from_num(100_800)), + )); let minus_alpha: I96F32 = I96F32::saturating_from_num(1.0).saturating_sub(alpha); let current_price: I96F32 = alpha .saturating_mul(Self::get_alpha_price(netuid).min(I96F32::saturating_from_num(1.0))); diff --git a/pallets/subtensor/src/tests/coinbase.rs b/pallets/subtensor/src/tests/coinbase.rs index 2deea02f9..f5c188a8b 100644 --- a/pallets/subtensor/src/tests/coinbase.rs +++ b/pallets/subtensor/src/tests/coinbase.rs @@ -190,11 +190,16 @@ fn test_coinbase_moving_prices() { SubnetAlphaIn::::insert(netuid, 1_000_000); SubnetMechanism::::insert(netuid, 1); SubnetMovingPrice::::insert(netuid, I96F32::from_num(1)); + NetworkRegisteredAt::::insert(netuid, 1); + // Updating the moving price keeps it the same. assert_eq!( SubtensorModule::get_moving_alpha_price(netuid), I96F32::from_num(1) ); + // Skip some blocks so that EMA price is not slowed down + System::set_block_number(7_200_000); + SubtensorModule::update_moving_price(netuid); assert_eq!( SubtensorModule::get_moving_alpha_price(netuid), @@ -206,29 +211,78 @@ fn test_coinbase_moving_prices() { SubnetMovingAlpha::::set(I96F32::from_num(1.0)); // Run moving 1 times. SubtensorModule::update_moving_price(netuid); - // Assert price is == 100% of the real price. - assert_eq!( - SubtensorModule::get_moving_alpha_price(netuid), - I96F32::from_num(1.0) - ); + // Assert price is ~ 100% of the real price. + assert!(I96F32::from_num(1.0) - SubtensorModule::get_moving_alpha_price(netuid) < 0.05); // Set price to zero. SubnetMovingPrice::::insert(netuid, I96F32::from_num(0)); SubnetMovingAlpha::::set(I96F32::from_num(0.1)); - // Run moving 6 times. - SubtensorModule::update_moving_price(netuid); - SubtensorModule::update_moving_price(netuid); - SubtensorModule::update_moving_price(netuid); - SubtensorModule::update_moving_price(netuid); - SubtensorModule::update_moving_price(netuid); - SubtensorModule::update_moving_price(netuid); + + // EMA price 14 days after registration + System::set_block_number(7_200 * 14); + + // Run moving 14 times. + for _ in 0..14 { + SubtensorModule::update_moving_price(netuid); + } + // Assert price is > 50% of the real price. - assert_eq!( - SubtensorModule::get_moving_alpha_price(netuid), - I96F32::from_num(0.468559) + assert!( + (I96F32::from_num(0.512325) - SubtensorModule::get_moving_alpha_price(netuid)).abs() + < 0.001 ); }); } +// Test moving price updates slow down at the beginning. +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_update_moving_price_initial --exact --show-output --nocapture +#[test] +fn test_update_moving_price_initial() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + // Set current price to 1.0 + SubnetTAO::::insert(netuid, 1_000_000); + SubnetAlphaIn::::insert(netuid, 1_000_000); + SubnetMechanism::::insert(netuid, 1); + SubnetMovingAlpha::::set(I96F32::from_num(0.5)); + SubnetMovingPrice::::insert(netuid, I96F32::from_num(0)); + + // Registered recently + System::set_block_number(510); + NetworkRegisteredAt::::insert(netuid, 500); + + SubtensorModule::update_moving_price(netuid); + + let new_price = SubnetMovingPrice::::get(netuid); + assert!(new_price.to_num::() < 0.001); + }); +} + +// Test moving price updates slow down at the beginning. +// SKIP_WASM_BUILD=1 RUST_LOG=debug cargo test --package pallet-subtensor --lib -- tests::coinbase::test_update_moving_price_after_time --exact --show-output --nocapture +#[test] +fn test_update_moving_price_after_time() { + new_test_ext(1).execute_with(|| { + let netuid: u16 = 1; + add_network(netuid, 1, 0); + // Set current price to 1.0 + SubnetTAO::::insert(netuid, 1_000_000); + SubnetAlphaIn::::insert(netuid, 1_000_000); + SubnetMechanism::::insert(netuid, 1); + SubnetMovingAlpha::::set(I96F32::from_num(0.5)); + SubnetMovingPrice::::insert(netuid, I96F32::from_num(0)); + + // Registered long time ago + System::set_block_number(72_000_500); + NetworkRegisteredAt::::insert(netuid, 500); + + SubtensorModule::update_moving_price(netuid); + + let new_price = SubnetMovingPrice::::get(netuid); + assert!((new_price.to_num::() - 0.5).abs() < 0.001); + }); +} + // Test basic alpha issuance in coinbase mechanism. // This test verifies that: // - Alpha issuance is initialized to 0 for new subnets diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 80413dc9f..909207e14 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -205,7 +205,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: 245, + spec_version: 246, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,