Newer
Older
let offence_session = offence.session_index();
let bonded_eras = BondedEras::<T>::get();
if bonded_eras.first().filter(|(_, start)| offence_session >= *start).is_some() {
R::report_offence(reporters, offence)
} else {
<Pallet<T>>::deposit_event(Event::<T>::OldSlashingReportDiscarded {
session_index: offence_session,
});
fn is_known_offence(offenders: &[Offender], time_slot: &O::TimeSlot) -> bool {
R::is_known_offence(offenders, time_slot)
/// Wrapper struct for Era related information. It is not a pure encapsulation as these storage
/// items can be accessed directly but nevertheless, its recommended to use `EraInfo` where we
/// can and add more functions to it as needed.
pub struct EraInfo<T>(sp_std::marker::PhantomData<T>);
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
impl<T: Config> EraInfo<T> {
/// Temporary function which looks at both (1) passed param `T::StakingLedger` for legacy
/// non-paged rewards, and (2) `T::ClaimedRewards` for paged rewards. This function can be
/// removed once `T::HistoryDepth` eras have passed and none of the older non-paged rewards
/// are relevant/claimable.
// Refer tracker issue for cleanup: #13034
pub(crate) fn is_rewards_claimed_with_legacy_fallback(
era: EraIndex,
ledger: &StakingLedger<T>,
validator: &T::AccountId,
page: Page,
) -> bool {
ledger.legacy_claimed_rewards.binary_search(&era).is_ok() ||
Self::is_rewards_claimed(era, validator, page)
}
/// Check if the rewards for the given era and page index have been claimed.
///
/// This is only used for paged rewards. Once older non-paged rewards are no longer
/// relevant, `is_rewards_claimed_with_legacy_fallback` can be removed and this function can
/// be made public.
fn is_rewards_claimed(era: EraIndex, validator: &T::AccountId, page: Page) -> bool {
ClaimedRewards::<T>::get(era, validator).contains(&page)
}
/// Get exposure for a validator at a given era and page.
///
/// This builds a paged exposure from `PagedExposureMetadata` and `ExposurePage` of the
/// validator. For older non-paged exposure, it returns the clipped exposure directly.
pub fn get_paged_exposure(
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
era: EraIndex,
validator: &T::AccountId,
page: Page,
) -> Option<PagedExposure<T::AccountId, BalanceOf<T>>> {
let overview = <ErasStakersOverview<T>>::get(&era, validator);
// return clipped exposure if page zero and paged exposure does not exist
// exists for backward compatibility and can be removed as part of #13034
if overview.is_none() && page == 0 {
return Some(PagedExposure::from_clipped(<ErasStakersClipped<T>>::get(era, validator)))
}
// no exposure for this validator
if overview.is_none() {
return None
}
let overview = overview.expect("checked above; qed");
// validator stake is added only in page zero
let validator_stake = if page == 0 { overview.own } else { Zero::zero() };
// since overview is present, paged exposure will always be present except when a
// validator has only own stake and no nominator stake.
let exposure_page = <ErasStakersPaged<T>>::get((era, validator, page)).unwrap_or_default();
// build the exposure
Some(PagedExposure {
exposure_metadata: PagedExposureMetadata { own: validator_stake, ..overview },
exposure_page,
})
}
/// Get full exposure of the validator at a given era.
pub fn get_full_exposure(
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
era: EraIndex,
validator: &T::AccountId,
) -> Exposure<T::AccountId, BalanceOf<T>> {
let overview = <ErasStakersOverview<T>>::get(&era, validator);
if overview.is_none() {
return ErasStakers::<T>::get(era, validator)
}
let overview = overview.expect("checked above; qed");
let mut others = Vec::with_capacity(overview.nominator_count as usize);
for page in 0..overview.page_count {
let nominators = <ErasStakersPaged<T>>::get((era, validator, page));
others.append(&mut nominators.map(|n| n.others).defensive_unwrap_or_default());
}
Exposure { total: overview.total, own: overview.own, others }
}
/// Returns the number of pages of exposure a validator has for the given era.
///
/// For eras where paged exposure does not exist, this returns 1 to keep backward compatibility.
pub(crate) fn get_page_count(era: EraIndex, validator: &T::AccountId) -> Page {
<ErasStakersOverview<T>>::get(&era, validator)
.map(|overview| {
if overview.page_count == 0 && overview.own > Zero::zero() {
// Even though there are no nominator pages, there is still validator's own
// stake exposed which needs to be paid out in a page.
1
} else {
overview.page_count
}
})
// Always returns 1 page for older non-paged exposure.
// FIXME: Can be cleaned up with issue #13034.
.unwrap_or(1)
}
/// Returns the next page that can be claimed or `None` if nothing to claim.
pub(crate) fn get_next_claimable_page(
era: EraIndex,
validator: &T::AccountId,
ledger: &StakingLedger<T>,
) -> Option<Page> {
if Self::is_non_paged_exposure(era, validator) {
return match ledger.legacy_claimed_rewards.binary_search(&era) {
// already claimed
Ok(_) => None,
// Non-paged exposure is considered as a single page
Err(_) => Some(0),
}
}
// Find next claimable page of paged exposure.
let page_count = Self::get_page_count(era, validator);
let all_claimable_pages: Vec<Page> = (0..page_count).collect();
let claimed_pages = ClaimedRewards::<T>::get(era, validator);
all_claimable_pages.into_iter().find(|p| !claimed_pages.contains(p))
}
/// Checks if exposure is paged or not.
fn is_non_paged_exposure(era: EraIndex, validator: &T::AccountId) -> bool {
<ErasStakersClipped<T>>::contains_key(&era, validator)
}
/// Returns validator commission for this era and page.
pub(crate) fn get_validator_commission(
era: EraIndex,
validator_stash: &T::AccountId,
) -> Perbill {
<ErasValidatorPrefs<T>>::get(&era, validator_stash).commission
}
/// Creates an entry to track validator reward has been claimed for a given era and page.
/// Noop if already claimed.
pub(crate) fn set_rewards_as_claimed(era: EraIndex, validator: &T::AccountId, page: Page) {
let mut claimed_pages = ClaimedRewards::<T>::get(era, validator);
// this should never be called if the reward has already been claimed
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
}
// add page to claimed entries
claimed_pages.push(page);
ClaimedRewards::<T>::insert(era, validator, claimed_pages);
}
/// Store exposure for elected validators at start of an era.
pub fn set_exposure(
era: EraIndex,
validator: &T::AccountId,
exposure: Exposure<T::AccountId, BalanceOf<T>>,
) {
let page_size = T::MaxExposurePageSize::get().defensive_max(1);
let nominator_count = exposure.others.len();
// expected page count is the number of nominators divided by the page size, rounded up.
let expected_page_count = nominator_count
.defensive_saturating_add((page_size as usize).defensive_saturating_sub(1))
.saturating_div(page_size as usize);
let (exposure_metadata, exposure_pages) = exposure.into_pages(page_size);
defensive_assert!(exposure_pages.len() == expected_page_count, "unexpected page count");
<ErasStakersOverview<T>>::insert(era, &validator, &exposure_metadata);
exposure_pages.iter().enumerate().for_each(|(page, paged_exposure)| {
<ErasStakersPaged<T>>::insert((era, &validator, page as Page), &paged_exposure);
});
}
/// Store total exposure for all the elected validators in the era.
pub(crate) fn set_total_stake(era: EraIndex, total_stake: BalanceOf<T>) {
<ErasTotalStake<T>>::insert(era, total_stake);
}
}
/// Configurations of the benchmarking of the pallet.
pub trait BenchmarkingConfig {
/// The maximum number of validators to use.
type MaxValidators: Get<u32>;
/// The maximum number of nominators to use.
type MaxNominators: Get<u32>;
}
/// A mock benchmarking config for pallet-staking.
///
/// Should only be used for testing.
#[cfg(feature = "std")]
pub struct TestBenchmarkingConfig;
#[cfg(feature = "std")]
impl BenchmarkingConfig for TestBenchmarkingConfig {
Georges
committed
type MaxValidators = frame_support::traits::ConstU32<100>;
type MaxNominators = frame_support::traits::ConstU32<100>;