-
Notifications
You must be signed in to change notification settings - Fork 857
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
[AHM] Replace Validator FullIdentification from Exposure
to Existence
#7936
base: master
Are you sure you want to change the base?
Changes from all commits
8619582
5c8b2bc
0be27ce
e043ded
a9eb1d2
74220bd
6f0f00a
a73ce62
97ec539
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 |
---|---|---|
@@ -0,0 +1,27 @@ | ||
title: '[AHM] Replace Validator FullIdentification from `Exposure` to `Existence`' | ||
doc: | ||
- audience: Todo | ||
description: |- | ||
closes https://github.com/paritytech/polkadot-sdk/issues/6344. | ||
|
||
## TODO | ||
- [ ] TryStateCheck to see existing offence report decodes correctly. | ||
crates: | ||
- name: pallet-babe | ||
bump: major | ||
- name: pallet-beefy | ||
bump: major | ||
- name: pallet-grandpa | ||
bump: major | ||
- name: pallet-offences-benchmarking | ||
bump: major | ||
- name: pallet-root-offences | ||
bump: major | ||
- name: pallet-session-benchmarking | ||
bump: major | ||
- name: pallet-staking | ||
bump: major | ||
- name: westend-runtime | ||
bump: major | ||
- name: pallet-staking-ah-client | ||
bump: major |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -344,7 +344,9 @@ mod pallet; | |||||||||||||||||||||||||||||||||
extern crate alloc; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
use alloc::{collections::btree_map::BTreeMap, vec, vec::Vec}; | ||||||||||||||||||||||||||||||||||
use codec::{Decode, DecodeWithMemTracking, Encode, HasCompact, MaxEncodedLen}; | ||||||||||||||||||||||||||||||||||
use codec::{ | ||||||||||||||||||||||||||||||||||
Decode, DecodeWithMemTracking, Encode, EncodeLike, HasCompact, Input, MaxEncodedLen, Output, | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
use frame_election_provider_support::ElectionProvider; | ||||||||||||||||||||||||||||||||||
use frame_support::{ | ||||||||||||||||||||||||||||||||||
defensive, defensive_assert, | ||||||||||||||||||||||||||||||||||
|
@@ -653,7 +655,7 @@ impl<T: Config> StakingLedger<T> { | |||||||||||||||||||||||||||||||||
// first we try to remove stake from active | ||||||||||||||||||||||||||||||||||
if self.active >= to_withdraw { | ||||||||||||||||||||||||||||||||||
self.active -= to_withdraw; | ||||||||||||||||||||||||||||||||||
return self | ||||||||||||||||||||||||||||||||||
return self; | ||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||
withdrawn += self.active; | ||||||||||||||||||||||||||||||||||
self.active = BalanceOf::<T>::zero(); | ||||||||||||||||||||||||||||||||||
|
@@ -671,7 +673,7 @@ impl<T: Config> StakingLedger<T> { | |||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if withdrawn >= to_withdraw { | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
@@ -698,7 +700,7 @@ impl<T: Config> StakingLedger<T> { | |||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if unlocking_balance >= value { | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
@@ -735,7 +737,7 @@ impl<T: Config> StakingLedger<T> { | |||||||||||||||||||||||||||||||||
slash_era: EraIndex, | ||||||||||||||||||||||||||||||||||
) -> BalanceOf<T> { | ||||||||||||||||||||||||||||||||||
if slash_amount.is_zero() { | ||||||||||||||||||||||||||||||||||
return Zero::zero() | ||||||||||||||||||||||||||||||||||
return Zero::zero(); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
use sp_runtime::PerThing as _; | ||||||||||||||||||||||||||||||||||
|
@@ -828,15 +830,15 @@ impl<T: Config> StakingLedger<T> { | |||||||||||||||||||||||||||||||||
let mut slashed_unlocking = BTreeMap::<_, _>::new(); | ||||||||||||||||||||||||||||||||||
for i in slash_chunks_priority { | ||||||||||||||||||||||||||||||||||
if remaining_slash.is_zero() { | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
if let Some(chunk) = self.unlocking.get_mut(i).defensive() { | ||||||||||||||||||||||||||||||||||
slash_out_of(&mut chunk.value, &mut remaining_slash); | ||||||||||||||||||||||||||||||||||
// write the new slashed value of this chunk to the map. | ||||||||||||||||||||||||||||||||||
slashed_unlocking.insert(chunk.era, chunk.value); | ||||||||||||||||||||||||||||||||||
} else { | ||||||||||||||||||||||||||||||||||
break | ||||||||||||||||||||||||||||||||||
break; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
@@ -1116,8 +1118,10 @@ impl<T: Config> Convert<T::AccountId, Option<T::AccountId>> for StashOf<T> { | |||||||||||||||||||||||||||||||||
/// | ||||||||||||||||||||||||||||||||||
/// Active exposure is the exposure of the validator set currently validating, i.e. in | ||||||||||||||||||||||||||||||||||
/// `active_era`. It can differ from the latest planned exposure in `current_era`. | ||||||||||||||||||||||||||||||||||
#[deprecated(note = "Use `ExistenceOf` or `ExistenceOrLegacyExposureOf` instead")] | ||||||||||||||||||||||||||||||||||
pub struct ExposureOf<T>(core::marker::PhantomData<T>); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#[allow(deprecated)] | ||||||||||||||||||||||||||||||||||
impl<T: Config> Convert<T::AccountId, Option<Exposure<T::AccountId, BalanceOf<T>>>> | ||||||||||||||||||||||||||||||||||
for ExposureOf<T> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
|
@@ -1127,10 +1131,64 @@ impl<T: Config> Convert<T::AccountId, Option<Exposure<T::AccountId, BalanceOf<T> | |||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
pub struct NullIdentity; | ||||||||||||||||||||||||||||||||||
impl<T> Convert<T, Option<()>> for NullIdentity { | ||||||||||||||||||||||||||||||||||
fn convert(_: T) -> Option<()> { | ||||||||||||||||||||||||||||||||||
Some(()) | ||||||||||||||||||||||||||||||||||
/// A marker type representing the presence of a validator. Encodes as a unit type. | ||||||||||||||||||||||||||||||||||
pub type Existence = (); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
/// A converter type that returns `Some(())` if the validator exists in the current active era, | ||||||||||||||||||||||||||||||||||
/// otherwise `None`. This serves as a lightweight presence check for validators. | ||||||||||||||||||||||||||||||||||
pub struct ExistenceOf<T>(core::marker::PhantomData<T>); | ||||||||||||||||||||||||||||||||||
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. We should move this to
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. We need them only in staking-classic, right? We don't strictly need |
||||||||||||||||||||||||||||||||||
impl<T: Config> Convert<T::AccountId, Option<Existence>> for ExistenceOf<T> { | ||||||||||||||||||||||||||||||||||
fn convert(validator: T::AccountId) -> Option<Existence> { | ||||||||||||||||||||||||||||||||||
Validators::<T>::contains_key(&validator).then_some(()) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
/// A compatibility wrapper type used to represent the presence of a validator in the current era. | ||||||||||||||||||||||||||||||||||
/// Encodes as type [`Existence`] but can decode from legacy [`Exposure`] values for backward | ||||||||||||||||||||||||||||||||||
/// compatibility. | ||||||||||||||||||||||||||||||||||
#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, RuntimeDebug, TypeInfo, DecodeWithMemTracking)] | ||||||||||||||||||||||||||||||||||
pub enum ExistenceOrLegacyExposure<A, B: HasCompact> { | ||||||||||||||||||||||||||||||||||
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. Could have just used Option but this is more readable. |
||||||||||||||||||||||||||||||||||
/// Validator exists in the current era. | ||||||||||||||||||||||||||||||||||
Exists, | ||||||||||||||||||||||||||||||||||
/// Legacy `Exposure` data, retained for decoding compatibility. | ||||||||||||||||||||||||||||||||||
Exposure(Exposure<A, B>), | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
/// Converts a validator account ID to a Some([`ExistenceOrLegacyExposure::Exists`]) if the | ||||||||||||||||||||||||||||||||||
/// validator exists in the current era, otherwise `None`. | ||||||||||||||||||||||||||||||||||
pub struct ExistenceOrLegacyExposureOf<T>(core::marker::PhantomData<T>); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
impl<T: Config> Convert<T::AccountId, Option<ExistenceOrLegacyExposure<T::AccountId, BalanceOf<T>>>> | ||||||||||||||||||||||||||||||||||
for ExistenceOrLegacyExposureOf<T> | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
fn convert( | ||||||||||||||||||||||||||||||||||
validator: T::AccountId, | ||||||||||||||||||||||||||||||||||
) -> Option<ExistenceOrLegacyExposure<T::AccountId, BalanceOf<T>>> { | ||||||||||||||||||||||||||||||||||
Validators::<T>::contains_key(&validator).then_some(ExistenceOrLegacyExposure::Exists) | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
impl<A, B: HasCompact> Encode for ExistenceOrLegacyExposure<A, B> { | ||||||||||||||||||||||||||||||||||
fn encode_to<T: Output + ?Sized>(&self, _: &mut T) {} | ||||||||||||||||||||||||||||||||||
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. Should encode it the same as |
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
impl<A, B: HasCompact> MaxEncodedLen for ExistenceOrLegacyExposure<A, B> { | ||||||||||||||||||||||||||||||||||
fn max_encoded_len() -> usize { | ||||||||||||||||||||||||||||||||||
0 | ||||||||||||||||||||||||||||||||||
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.
Suggested change
|
||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
impl<A, B: HasCompact> EncodeLike for ExistenceOrLegacyExposure<A, B> {} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
impl<A, B: HasCompact> Decode for ExistenceOrLegacyExposure<A, B> | ||||||||||||||||||||||||||||||||||
where | ||||||||||||||||||||||||||||||||||
Exposure<A, B>: Decode, | ||||||||||||||||||||||||||||||||||
{ | ||||||||||||||||||||||||||||||||||
fn decode<I: Input>(input: &mut I) -> Result<Self, codec::Error> { | ||||||||||||||||||||||||||||||||||
match input.remaining_len() { | ||||||||||||||||||||||||||||||||||
Ok(Some(x)) if x > 0 => Ok(ExistenceOrLegacyExposure::Exposure(Decode::decode(input)?)), | ||||||||||||||||||||||||||||||||||
_ => Ok(ExistenceOrLegacyExposure::Exists), | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
|
@@ -1278,7 +1336,7 @@ impl<T: Config> EraInfo<T> { | |||||||||||||||||||||||||||||||||
if claimed_pages.contains(&page) { | ||||||||||||||||||||||||||||||||||
defensive!("Trying to set an already claimed reward"); | ||||||||||||||||||||||||||||||||||
// nevertheless don't do anything since the page already exist in claimed rewards. | ||||||||||||||||||||||||||||||||||
return | ||||||||||||||||||||||||||||||||||
return; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// add page to claimed entries | ||||||||||||||||||||||||||||||||||
|
@@ -1418,3 +1476,55 @@ impl BenchmarkingConfig for TestBenchmarkingConfig { | |||||||||||||||||||||||||||||||||
type MaxValidators = frame_support::traits::ConstU32<100>; | ||||||||||||||||||||||||||||||||||
type MaxNominators = frame_support::traits::ConstU32<100>; | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#[cfg(test)] | ||||||||||||||||||||||||||||||||||
mod test { | ||||||||||||||||||||||||||||||||||
use crate::ExistenceOrLegacyExposure; | ||||||||||||||||||||||||||||||||||
use codec::{Decode, Encode}; | ||||||||||||||||||||||||||||||||||
use sp_staking::{Exposure, IndividualExposure}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||
fn existence_encodes_decodes_correctly() { | ||||||||||||||||||||||||||||||||||
let encoded_existence = ExistenceOrLegacyExposure::<u32, u32>::Exists.encode(); | ||||||||||||||||||||||||||||||||||
assert!(encoded_existence.is_empty()); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// try decoding the existence | ||||||||||||||||||||||||||||||||||
let decoded_existence = | ||||||||||||||||||||||||||||||||||
ExistenceOrLegacyExposure::<u32, u32>::decode(&mut encoded_existence.as_slice()) | ||||||||||||||||||||||||||||||||||
.unwrap(); | ||||||||||||||||||||||||||||||||||
assert!(matches!(decoded_existence, ExistenceOrLegacyExposure::Exists)); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// check that round-trip encoding works | ||||||||||||||||||||||||||||||||||
assert_eq!(encoded_existence, decoded_existence.encode()); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
#[test] | ||||||||||||||||||||||||||||||||||
fn legacy_existence_encodes_decodes_correctly() { | ||||||||||||||||||||||||||||||||||
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. Also you are missing a test to make sure |
||||||||||||||||||||||||||||||||||
let legacy_exposure = Exposure::<u32, u32> { | ||||||||||||||||||||||||||||||||||
total: 1, | ||||||||||||||||||||||||||||||||||
own: 2, | ||||||||||||||||||||||||||||||||||
others: vec![IndividualExposure { who: 3, value: 4 }], | ||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
let encoded_legacy_exposure = legacy_exposure.encode(); | ||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// try decoding the legacy exposure | ||||||||||||||||||||||||||||||||||
let decoded_legacy_exposure = | ||||||||||||||||||||||||||||||||||
ExistenceOrLegacyExposure::<u32, u32>::decode(&mut encoded_legacy_exposure.as_slice()) | ||||||||||||||||||||||||||||||||||
.unwrap(); | ||||||||||||||||||||||||||||||||||
assert!(matches!( | ||||||||||||||||||||||||||||||||||
decoded_legacy_exposure, | ||||||||||||||||||||||||||||||||||
ExistenceOrLegacyExposure::Exposure(Exposure { | ||||||||||||||||||||||||||||||||||
total: 1, | ||||||||||||||||||||||||||||||||||
own: 2, | ||||||||||||||||||||||||||||||||||
others: ref i | ||||||||||||||||||||||||||||||||||
}) if *i == vec![IndividualExposure { who: 3, value: 4 }] | ||||||||||||||||||||||||||||||||||
)); | ||||||||||||||||||||||||||||||||||
Comment on lines
+1515
to
+1522
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.
Suggested change
nit: I think |
||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||
// encoding again removes the exposure. | ||||||||||||||||||||||||||||||||||
assert_eq!( | ||||||||||||||||||||||||||||||||||
ExistenceOrLegacyExposure::<u32, u32>::Exists.encode(), | ||||||||||||||||||||||||||||||||||
decoded_legacy_exposure.encode() | ||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||
} |
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.
fwiw this is a type alias to
()
, what we usually call a marker type is actually a different type, which doesn't inherit any of the impls of the original type, such aspub struct Existence