-
Notifications
You must be signed in to change notification settings - Fork 336
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
staking multiple nominations #189
Conversation
@@ -111,17 +111,17 @@ impl<A, B: HasCompact> Into<IndividualExposure<A, B>> for Bond<A, B> { | |||
|
|||
#[derive(Copy, Clone, PartialEq, Eq, Encode, Decode, RuntimeDebug)] | |||
/// The activity status of the validator | |||
pub enum ValidatorStatus<BlockNumber> { | |||
pub enum ValidatorStatus { |
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.
ValidatorStatus
used to be generic over the inner variant of Leaving
, but it was only ever instantiated with the RoundIndex
type. So, the generic was removed and the inner variant of ValidatorStatus::Leaving
was defined to always be RoundIndex
. Earlier in this PR, something similar was done to remove RoundIndex as a generic parameter from CandidateState
.
pallets/stake/src/lib.rs
Outdated
T::Origin::from(Some(actor.clone()).into()), | ||
nominated_val.clone(), | ||
balance, | ||
) | ||
} else { | ||
<Module<T>>::join_candidates( | ||
<Module<T>>::join_candidates_no_fee( |
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.
This changes the default fee for validators registered at genesis to 0%. It was previously 2%.
We could also add a DefaultValidatorFee
config constant and use that here with the old join_candidates
method. Then, there's no need to create the join_candidates_no_fee
runtime method, but it does add a config constant and there are a few already.
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.
Never mind, changed this so didn't add a new runtime method. The default fee was still changed to 0% for validators registered at genesis. is this a suitable default?
type IssuancePerRound = IssuancePerRound; | ||
type MaxFee = MaxFee; | ||
type MinValidatorStk = MinValidatorStk; | ||
type MinNomination = MinNominatorStk; |
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.
This sets the minimum nomination as equal to MinNominatorStk = 5 * GLMR
, but it could be set at some value less than MinNominatorStk
. These limits exist to prevent trivial nominations from abusing runtime storage.
|
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 notes are awesome. Can we get those as doc comments or something?
What does it mean to go offline?
Why do we need seperate bond_more (same question about bond_less) methods for validators and nominators? Maybe you could have a single fn bond_more(origin, candidate, more: BalanceOf<T>)
and if the candidate is the same as the caller then treat it as a candidate bonding more. Or use an option like you did for the genesis config.
Design question: Can one account be a validator and also a nominator? If so can the account self nominate?
Concern: This pallet just ticked past 1k lines code, and some parts are deeply nested. I'm reassured by the thorough test coverage. But I wonder how this footprint compares to eg pallet staking.
Thanks, the reason I made those notes is because I had stuff that needed to be communicated but didn't know where to put the relevant doc comment. For example, the discussion of
Leave the pool of candidates so cannot be selected as a validator, but still bonded and can rejoin the candidate pool by calling if candidate.is_active() {
Self::update_active_candidate()
}
The validator and nominator roles are separate and no account is allowed to occupy both roles. So, when an account tries to So no validator can self-nominate. The validator has to be bonded > T::MinValidatorStk, but that value is stored separately from its nominations. It is the same as a self-nomination in practice, but it does not use the nominator runtime methods.
I could make this change, but I like having separate runtime methods for validator candidates and nominators because the storage items are separate. Also I generally try to avoid using Options as input params on runtime methods when it splits the path inside the runtime method and there is not a lot of shared logic between the branches. This changes fn validator_bond_more() {
_validator_bond_more()
}
fn nominator_bond_more() {
_nominator_bond_more()
} to this fn bond_more(Option) {
if let Some(_) = Option {
_nominator_bond_more()
} else {
_validator_bond_more()
}
} Because they have separate storage items, the branches don't share any logic so this change makes it more nested in order to combine them into a single method.
Still ~2500 loc less than pallet-staking/src/lib.rs and that doesn't count the other files in that pallet. To implement support for multiple nominations, I added another Vec that has to be iterated over whenever we add nominations, remove nominations, or change nominations. I think it's worth it, but agree that surface area has increased. |
Thanks for the answers. That all makes good sense to me. I think it makes sense to do another learning session where the team gets to stake and validate and nominate so we can develop a stronger intuition for the various code paths. This pallet is really nice. |
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.
LGTM
What does it do?
T::MaxValidatorsPerNominator
validators per nominator, such thateach nomination > T::MinNomination
andtotal nominated > T::MinNominatorStk
.stakers: Vec<(AccountId, Option<AccountId>, Balance)>
. For validators, it is(AccountId, None, Balance)
and for nominators it is(AccountId, Some(ValidatorAccountId), Balance)
. This logic can be found in thestake
pallet genesisbuild()
impl.switch_nomination
runtime methodWhat important points reviewers should know?
Here are some high-level docs, which should make the code easier to read/review.
Is there something left for follow-up PRs?
enforcing inflation schedule, which was an original goal of this PR
What alternative implementations were considered?
Are there relevant PRs or issues in other repositories (Substrate, Polkadot, Frontier, Cumulus)?
#179
What value does it bring to the blockchain users?
Checklist