-
Notifications
You must be signed in to change notification settings - Fork 708
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
Adds stake-tracker
pallet and integrates with the staking pallet
#1933
Conversation
bot fmt |
@gpestana https://gitlab.parity.io/parity/mirrors/polkadot-sdk/-/jobs/6746153 was started for your command Comment |
We are migrating the command bot to be a GitHub Action |
@gpestana Command |
scale-info = { features = ["derive", "serde"], workspace = true } | ||
|
||
sp-runtime = { features = ["serde"], workspace = true } | ||
sp-staking = { features = ["serde"], workspace = true } |
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.
why do you import with serde features here? I see no usage in the pallet.
@@ -291,7 +291,7 @@ pub mod benchmarking; | |||
pub mod testing_utils; | |||
|
|||
#[cfg(test)] | |||
pub(crate) mod mock; |
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.
does it need to be public?
/// Fired when an existng nominator becomes idle. | ||
/// | ||
/// An idle nominator stops nominating but its stake state should not be removed. | ||
fn on_nominator_idle(_who: &AccountId, _prev_nominations: Vec<AccountId>) {} |
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.
pallet-staking never call this and directly calls on_nominator_removed
.
pallet-stake-tracker just calls on_nominator_removed
inside its implementation.
maybe it is not useful?
EDIT: but it is fine to me
/// A dandling target is a target that is part of the target list but is unbonded. | ||
NotDanglingTarget, | ||
/// Not a nominator. | ||
NotNominator, |
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.
maybe better to put them at the end of the enum to avoid unnecessary breaking change.
/// The duplicate nominations will be implicitly removed. Only validators or idle stakers | ||
/// are valid targets. If successful, the effects of this call will be felt at the | ||
/// beginning of the next era. |
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.
/// The duplicate nominations will be implicitly removed. Only validators or idle stakers | |
/// are valid targets. If successful, the effects of this call will be felt at the | |
/// beginning of the next era. | |
/// The duplicate nominations will be implicitly removed. Only validators or idle stakers | |
/// are valid targets. If successful, the effects of this call will be felt at the | |
/// beginning of the next era. |
@@ -1749,6 +1768,10 @@ pub mod pallet { | |||
if let Some(ref mut nom) = maybe_nom { | |||
if let Some(pos) = nom.targets.iter().position(|v| v == stash) { | |||
nom.targets.swap_remove(pos); | |||
|
|||
// update nominations and trickle down to target list score. | |||
Self::do_add_nominator(&nom_stash, nom.clone()); |
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.
calling a function that inserts into Nominators
inside a Nominators::mutate
callback feels scary.
|
||
crates: | ||
- name: pallet-staking | ||
bump: minor |
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.
strictly speaking, pallet_staking::Pallet
implements publicly StakingInterface
which is from a crate with a major breaking change. So I guess it is a major breaking change in regards to semver.
}; | ||
|
||
#[cfg(test)] | ||
pub(crate) mod mock; |
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.
I'm curious why not just this?
pub(crate) mod mock; | |
mod mock; |
<T::Staking as StakingInterface>::CurrencyToVote::to_vote( | ||
balance, | ||
T::Currency::total_issuance(), | ||
) |
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.
total_issuance
is not constant, can this lead to error? like the inserted vote weight is different from the vote weight calculated with the new total issuance and so the list is unordered in regards to actual staked amount?
|
||
/// Removes nomination of a non-active validator. | ||
/// | ||
/// In the case that an unboded target still has nominations lingering, the approvals stake |
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.
/// In the case that an unboded target still has nominations lingering, the approvals stake | |
/// In the case that an unbonded target still has nominations lingering, the approvals stake |
…ytech/polkadot-sdk into gpestana/stake-tracker_integration
This PR adds target stake updates buffering to `stake-tracker`. It exposes a configuration that defines a threshold below which the target score *should not* be updated automatically in the target list. The `Config::ScoreStrictUpdateThreshold` defines said threshold. If a target stake update is below the threshold, the stake update is buffered in the `UnsettledTargetScore` storage map while the target list is not affected. Multiple approvals updates can be buffered for the same target. Calling `Call::settle` will setttle the buffered approvals tally for a given target. Setting `Config::ScoreStrictUpdateThreshold` to `None` disables the stake approvals buffering. - [x] benchmarks - [x] `try-state` checks considering the unsettled score - [x] docs --------- Co-authored-by: command-bot <>
The CI pipeline was cancelled due to failure one of the required jobs. |
closing as it is stale. |
This PR adds and integrates the
stake-tracker
pallet in the staking system.Goals:
TargetList
list of validators strictly and always sorted by their approval votes. Approvals consist of validator's self-vote and the sum of all the corresponding nominations across all the system.TargetList
sorting must be always kept up to date, even in the event of new nomination updates, nominator/validator slashes and rewards. Thestake-tracker
pallet must ensure that the scores of the targets are always up to date and the targets are sorted by score at all time.VoterList
list of voters that may be either 1) strictly and always sorted by their score (i.e. bonded stake of an individual voter) or 2) loosely sorted list. Choosing between mode 1) and 2) can be done through stake-tracker configurations.TL;DR 2nd order changes
T::TargetList
, insofar as there are still nominators nominating it;Staking::nominate
will fail;Staking::nominate
will remove all the duplicate nominations implicitly, if any.Why?
Currently, we select up to
N
registered validators to be part of the snapshot for the next election. When the number of registered validators in the system exceeds that number, we'll need to have an efficient way to select the top validators with more approvals stake to construct the snapshot.Thus, we need to keep list of validators sorted by their approval stakes at all time. This means that any update to nominations and their stake (due to slashing, bonding extra, rewards, etc) needs to be reflected in the targets nominated by the stake. Enters the
pallet-stake-tracker
: this pallet keeps track of relevant staking events (through implementing thetrait OnStakingEvent
) and updates the target bags list with the target's approvals stake accordingly.In order to achieve this, the target list must keep track of all target stashes that have at least one nomination in the system (i.e. their
approval_stake > 0
), regardless of their state. This means that it needs to keep track of the stake of active validators, idle validator and even targets that are not validators anymore but have still nominations lingering.How?
The
stake-tracker
pallet implements theOnStakingUpdate
trait to listen to staking events and multiplexes those events to one or multiple types (e.g. pallets). The stake tracker pallet is used as a degree of indirection to maintain the target and voter semi-sorted lists (implemented by the bags list pallet) up to date.The main goal is that all the updates to the targets and voters lists are performed at each relevant staking event through the stake-tracker pallet. However, the voter and target list reads are performed directly through the
SortedListProvider
set in the staking's config.Changes to assumptions in chilled and removed stakers
This PR changes some assumptions behind chilled stakers: the chilled/idle validators will be kept in the
Target
lists, and only removed from the target list when:This allows the
stake-tracker
to keep track of the chilled validators's and respective score after the validator is chilled and completely unbonds. This way, when a validator sets the intention to re-validate, the target's score is brought up with the correct sum of approvals in the system (i.e. self stake + all current nominations, which have been set previous to the re-validation).Changes to
Call::nominate
New nominations can only be performed on active or chilling validators. "Moot" nominations still exist (i.e. nominations that points at an inactive/inexistent validator), but only when a validator stops nominating or is chilled (in which case it may remain in the target list if the approvals are higher than 0).
In addition, the runtime ensures that each nominator does not nominates a target more than once at a time. This is achieved by deduplicating the nominations in the extrinsic
Staking::nominate
.Changes to
OnStakingUpdate
1. New methods
Added a couple more methods to the
OnStakingUpdate
trait in order to differentiate removed stakers from idle (chilling) stakers. For a rationale on why this is needed see in this discussion #1933 (comment).2. Refactor existing methods for safety
With this refactor, the event emitter needs to explicitly call the events with more information about the event. The advantage is that this new interface design prevents potential issues with data sync, e.g. the event emitter does not necessarily need to update the staking state before emitting the events and the OnStakingUpdate implementor does not need to rely as much on the staking interface, making the interface less error prone.
Changes to
SortedListProvider
Added a new method to the trait, gated by
try-runtime
, which returns whether a given node is in the correct position in the list or not given its current score. This method will help with the try state checks for the target list.Migrations
The migration code has been validated against the Polkadot using the externalities tests in polkadot/runtime/westend/src/lib.rs. Upon running the migrations, we ensure that:
Check #4673 for more info on migrations and related tests.
Note that the migrations will "clean" the current nominations in the system namely:
Weight complexity
Keeping both target and voter list sorted based on their scores requires their scores to be up to date after single operations (add nominator/validator, update stake, etc) and composite staking events (validator slashing and payouts). See https://hackmd.io/FH8Uhi2aQ5mD0aMm-BbqMQ for more details and back of the envelope calculations.
This PR #4686 shows how the target list affects the staking's
MaxExposurePageSize
based on benchmarks with different modes. In sum:To do later
A. Remove legacy
CurrencyToVote
CurrencyToVote
in staking #4725Remove the need for the
CurrencyToVote
converter type in the pallet-staking. This type converts coverts fromBalanceOf<T>
to au64
"vote" type, and from a safeu128
(i.e.ExtendedBalance
) back toBalanceOf<T>
. In both conversion directions, the total issuance of the system must be provided.The main reason for this convertion is that the current phragmen implementation does not correctly support types
u128
as the main type. Thus, the conversion between balance (u128
) and the supported "vote"u64
type.Relying on the current issuance will be a problem with the staking parachain (let's assume that the staking runtime is not deployed in AH). In addition, it removing the need for this conversion will simplify and make it cheaper to run the stake-tracker and the associated list updates.
To finish
stake-tracker
pallet and integration with the Staking palletvalidate
try-runtime
checks instake-tracker
which also run after the staking pallet testsCall::drop_dangling_nomination
target_list
bucket limitsCloses #442