subtensor icon indicating copy to clipboard operation
subtensor copied to clipboard

Running STAO and DTAO concurrently

Open gztensor opened this issue 1 year ago • 3 comments

  1. change the emission calculation to the following:
    sum_tao = sum([p.tao_in for p in pools])
    sum_prices = sum([p.price for p in pools])
    emission = [p.tao_in/sum_tao for p in pools]
    for i, p in enumerate(pools):
        if sum_prices > 1.0:
            p.inject( tao_in = 0, alpha_in = 1, alpha_out = 1 )
        else:
            p.inject( tao_in = emission[i], alpha_in = 0, alpha_out = 1 )

Note that the emission is now p.tao_in/sum_tao which is the ratio of TAO in the pool to the total TAO in the pools. This is the exact same calculation for STAO, where the emission for the subnet is tao_in_network/sum_tao_in_networks

TotalSubnetStake and DynamicTAOReserve are the same values in an STAO/DTAO environment

  1. When we migrate from STAO --> DTAO we will need to unstake everyone
  // --- 5. Iterate over all stakes and unstake them if they are in 
        // this subnet. The subnet is not dynamic so this is all clean unstakes.
        SubStake::<T>::iter().for_each(|((cold_i, hot_i, subnet_i), stake_amount_i)| {
            if subnet_i == netuid {
                // Unstake everyone from this subnet.
                Self::decrease_stake_on_coldkey_hotkey_account( cold_i, hot_i, subnet_i, stake_amount_i );
            }
        });
        TotalSubnetStake::<T>::insert( netuid, 0 ); // We have cleared all the stake on this subnet.
  1. Prices no longer are required except here:
if sum_prices > 1.0:
            p.inject( tao_in = 0, alpha_in = 1, alpha_out = 1 )
        else:
            p.inject( tao_in = emission[i], alpha_in = 0, alpha_out = 1 )

For STAO subnets we just always emit TAO (as if prices were > 1)

gztensor avatar May 22 '24 23:05 gztensor

Test plan

Definition: Price threshold = SUM( Emission( subnet ) for subnet in DTAO_SUBNETS )/ SUM( Emission( subnet ) for subnet in ALL_SUBNETS )

For STAO subnets:

  • DynamicTAOReserve gets increased by stake amount on add stake
  • DynamicTAOReserve gets decreased by stake amount on remove stake
  • DynamicTAOReserve gets increased by proportion of this subnet's DynamicTAOReserve to total stake in block_step in every block, no matter what the sub of prices is (greater or lower than threshold)
  • PendingEmission gets increased by the same value on every block (within an epoch)
  • At the end of every epoch PendingEmission gets distributed to delegates' and delegators' stake, and is reset to 0
  • Delegates and delegators can then turn their stake into TAO by removing stake, which will be converted to TAO 1:1.

For DTAO subnets

  • DynamicTAOReserve gets increased by stake amount on add stake
  • DynamicTAOReserve gets decreased by stake amount on remove stake
  • DynamicTAOReserve gets increased by proportion of this subnet's DynamicTAOReserve to total stake in block_step in every block, if the sum of dynamic prices is greater than or equal to threshold, by 0 otherwise
  • DynamicAlphaReserve gets increased by proportion of this subnet's DynamicTAOReserve to total stake in block_step in every block, if the sum of dynamic prices is lower than threshold, by 0 otherwise
  • PendingAlphaEmission gets increased by the same value on every block (within an epoch)

Corner cases

  • If there are no DTAO subnets, STAO subnets keep working as above
  • If there is no stake in DTAO subnets (sum of prices == 0), the sum of DTAO emissions is 0, so the threshold is 0, so all DTAO subnets get nothing in DynamicTAOReserve and DynamicAlphaReserve
  • If there is zero total stake, everybody gets punished and emissions just go drained and burned

Sanity checks

  • After epoch emission, the common wealth (total balance on all coldkeys of delegates and delegators + total stake) gets increased by sum of what get_block_emission function returns for every block in the epoch.

gztensor avatar May 24 '24 23:05 gztensor

Converting a subnet from STAO to DTAO

  • Only subnet owner can do it
  • A conversion job is scheduled to run in on_initialize hook to avoid block overweighing. It performs all following steps.
  • Wait until the end of subnet tempo so that PendingEmission is drained (set to 0)
  • Halt all operations on this subnet that increase stake, which includes:
    • Staking
    • Epoch emissions
    • Increasing PendingEmission in run_coinbase block handling
  • Own stake of subnet owner key is converted to dynamic pool as if it was the creation of the dynamic subnet.
    • "If the staked balance is lower than the current subnet lock cost, the difference will be taken from the subnet owner free balance (already reserved/withdrawn by now)" - this is questionable because Subnet already exists and has been locked for a while.
  • Because of slippage, if we add existing delegators' stakes to the pool, the alpha amount granted to stakers will depend on the order, which will not be fair. So, all delegators will be forcefully unstaked and welcomed to stake back after conversion.
    • After all stakers are unstaked, the StaoToDtaoConversionUnstakeCompleted event will be emitted.
  • Subnet tempo is set to default value
  • TotalSubnetTAO will be reduced by the amount of forcefully unstaked TAO (test)
  • DynamicTAOReserve will be set to equal the new value of TotalSubnetTAO (test)

Branch: feat/stao-dtao-transition

gztensor avatar May 25 '24 00:05 gztensor

Transition check list:

  • [ ] Benchmark for starting extrinsic
  • [ ] Add Events as needed

gztensor avatar Jun 03 '24 23:06 gztensor

closed as no longer required

distributedstatemachine avatar Sep 02 '24 11:09 distributedstatemachine