-
Notifications
You must be signed in to change notification settings - Fork 317
Hotfixes: Locked transfer flags to control locked alpha transfers + ema-price based emissions #2780
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -444,6 +444,29 @@ impl ConvictionModel { | |
| } | ||
|
|
||
| impl<T: Config> Pallet<T> { | ||
| pub fn account_rejects_locked_alpha(coldkey: &T::AccountId) -> bool { | ||
| AccountFlags::<T>::get(coldkey) & crate::ACCOUNT_FLAGS_ACCEPT_LOCKED_ALPHA != 1 | ||
| } | ||
|
|
||
| pub fn ensure_can_receive_locked_alpha( | ||
| coldkey: &T::AccountId, | ||
| amount: AlphaBalance, | ||
| ) -> DispatchResult { | ||
| let rejects_locked_alpha = Self::account_rejects_locked_alpha(coldkey); | ||
| Self::ensure_can_receive_locked_alpha_with_flag(rejects_locked_alpha, amount) | ||
| } | ||
|
|
||
| fn ensure_can_receive_locked_alpha_with_flag( | ||
| rejects_locked_alpha: bool, | ||
| amount: AlphaBalance, | ||
| ) -> DispatchResult { | ||
| if amount.is_zero() { | ||
| return Ok(()); | ||
| } | ||
| ensure!(!rejects_locked_alpha, Error::<T>::AccountRejectsLockedAlpha); | ||
| Ok(()) | ||
| } | ||
|
|
||
| pub fn insert_lock_state( | ||
| coldkey: &T::AccountId, | ||
| netuid: NetUid, | ||
|
|
@@ -1331,32 +1354,51 @@ impl<T: Config> Pallet<T> { | |
| Self::ensure_no_active_locks(new_coldkey)?; | ||
|
|
||
| let mut locks_to_transfer: Vec<(NetUid, T::AccountId, LockState)> = Vec::new(); | ||
| let now = Self::get_current_block_as_u64(); | ||
| let unlock_rate = UnlockRate::<T>::get(); | ||
| let maturity_rate = MaturityRate::<T>::get(); | ||
| let new_coldkey_rejects_locked_alpha = Self::account_rejects_locked_alpha(new_coldkey); | ||
| let decaying_locks_to_transfer: Vec<(NetUid, bool)> = | ||
| DecayingLock::<T>::iter_prefix(old_coldkey).collect(); | ||
|
|
||
| // Gather locks for old coldkey | ||
| for ((netuid, hotkey), lock) in Lock::<T>::iter_prefix((old_coldkey,)) { | ||
| locks_to_transfer.push((netuid, hotkey, lock)); | ||
| } | ||
|
|
||
| // Remove locks for old coldkey and insert for new | ||
| for (netuid, decaying) in decaying_locks_to_transfer.iter() { | ||
| DecayingLock::<T>::insert(new_coldkey, *netuid, *decaying); | ||
| } | ||
|
Comment on lines
+1369
to
+1371
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. [LOW] Validate locked-alpha receipt before copying decaying flags
|
||
|
|
||
| let mut rolled_locks_to_transfer: Vec<(NetUid, T::AccountId, LockState, bool)> = Vec::new(); | ||
| for (netuid, hotkey, lock) in locks_to_transfer { | ||
| let now = Self::get_current_block_as_u64(); | ||
| let unlock_rate = UnlockRate::<T>::get(); | ||
| let maturity_rate = MaturityRate::<T>::get(); | ||
| let perpetual_lock = decaying_locks_to_transfer | ||
| .iter() | ||
| .any(|(decaying_netuid, decaying)| *decaying_netuid == netuid && !*decaying); | ||
| let old_lock = ConvictionModel::roll_forward_lock( | ||
| lock, | ||
| now, | ||
| unlock_rate, | ||
| maturity_rate, | ||
| Self::is_subnet_owner_hotkey(netuid, &hotkey), | ||
| Self::is_perpetual_lock(old_coldkey, netuid), | ||
| perpetual_lock, | ||
| ); | ||
| Self::ensure_can_receive_locked_alpha_with_flag( | ||
| new_coldkey_rejects_locked_alpha, | ||
| old_lock.locked_mass, | ||
| )?; | ||
| rolled_locks_to_transfer.push((netuid, hotkey, old_lock, perpetual_lock)); | ||
| } | ||
|
|
||
| // Remove locks for old coldkey and insert for new | ||
| for (netuid, hotkey, old_lock, perpetual_lock) in rolled_locks_to_transfer { | ||
| let new_lock = ConvictionModel::roll_forward_lock( | ||
| old_lock.clone(), | ||
| now, | ||
| unlock_rate, | ||
| maturity_rate, | ||
| Self::is_subnet_owner_hotkey(netuid, &hotkey), | ||
| Self::is_perpetual_lock(new_coldkey, netuid), | ||
| perpetual_lock, | ||
| ); | ||
| Lock::<T>::remove((old_coldkey.clone(), netuid, hotkey.clone())); | ||
| Self::reduce_aggregate_lock( | ||
|
|
@@ -1780,6 +1822,7 @@ impl<T: Config> Pallet<T> { | |
| .conviction | ||
| .saturating_add(conviction_transfer); | ||
| } | ||
| Self::ensure_can_receive_locked_alpha(destination_coldkey, locked_transfer)?; | ||
|
|
||
| source_lock = ConvictionModel::roll_forward_lock( | ||
| source_lock, | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[LOW] Validate locked-alpha receipt before copying decaying flags
swap_coldkey_lockscopiesDecayingLockentries tonew_coldkeybefore the newAccountRejectsLockedAlphacheck runs. Ifold_coldkeyhas a decaying/perpetual flag and a non-zero rolled lock, a direct helper failure can leave the destinationDecayingLockmutated even though the function returns an error. The public extrinsic path appears to rely on storage-layer rollback, but the helper's own no-mutation-on-error invariant and test do not cover these flags, and a stale flag can affect the mode of later locks for that coldkey/netuid. Buildrolled_locks_to_transferand run all rejection checks first, then insert theDecayingLockentries in the commit phase with the lock moves.