Newer
Older
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin { }
}
decl_storage! {
pub trait Store for Module<T: Trait> as Staking {
pub SlotStake: BalanceOf<T>;
/// The currently elected validator set keyed by stash account ID.
pub CurrentElected: Vec<T::AccountId>;
/// The start of the current era.
pub CurrentEraStart: MomentOf<T>;
/// The session index at which the current era started.
pub CurrentEraStartSessionIndex: SessionIndex;
/// Rewards for the current era. Using indices of current elected set.
pub CurrentEraPointsEarned: EraPoints;
/// Nominators for a particular account that is in action right now. You can't iterate
/// through validators here, but you can find them in the Session module.
///
/// This is keyed by the stash account.
pub Stakers: map hasher(blake2_256) T::AccountId => Exposure<T::AccountId, BalanceOf<T>>;
}
#[derive(Encode, Decode)]
struct OldStakingLedger<AccountId, Balance: HasCompact> {
stash: AccountId,
#[codec(compact)]
total: Balance,
#[codec(compact)]
active: Balance,
unlocking: Vec<UnlockChunk<Balance>>,
}
let current_era_start_index = deprecated::CurrentEraStartSessionIndex::get();
let current_era = <Module<T> as Store>::CurrentEra::get().unwrap_or(0);
let current_era_start = deprecated::CurrentEraStart::<T>::get();
<Module<T> as Store>::ErasStartSessionIndex::insert(current_era, current_era_start_index);
<Module<T> as Store>::ActiveEra::put(ActiveEraInfo {
index: current_era,
start: Some(current_era_start),
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
let current_elected = deprecated::CurrentElected::<T>::get();
let mut current_total_stake = <BalanceOf<T>>::zero();
for validator in ¤t_elected {
let exposure = deprecated::Stakers::<T>::get(validator);
current_total_stake += exposure.total;
<Module<T> as Store>::ErasStakers::insert(current_era, validator, &exposure);
let mut exposure_clipped = exposure;
let clipped_max_len = T::MaxNominatorRewardedPerValidator::get() as usize;
if exposure_clipped.others.len() > clipped_max_len {
exposure_clipped.others.sort_unstable_by(|a, b| a.value.cmp(&b.value).reverse());
exposure_clipped.others.truncate(clipped_max_len);
}
<Module<T> as Store>::ErasStakersClipped::insert(current_era, validator, exposure_clipped);
let pref = <Module<T> as Store>::Validators::get(validator);
<Module<T> as Store>::ErasValidatorPrefs::insert(current_era, validator, pref);
}
<Module<T> as Store>::ErasTotalStake::insert(current_era, current_total_stake);
let points = deprecated::CurrentEraPointsEarned::get();
<Module<T> as Store>::ErasRewardPoints::insert(current_era, EraRewardPoints {
total: points.total,
individual: current_elected.iter().cloned().zip(points.individual.iter().cloned()).collect(),
});
let res = <Module<T> as Store>::Ledger::translate_values(
|old: OldStakingLedger<T::AccountId, BalanceOf<T>>| StakingLedger {
stash: old.stash,
total: old.total,
active: old.active,
unlocking: old.unlocking,
last_reward: None,
}
);
if let Err(e) = res {
frame_support::print("Encountered error in migration of Staking::Ledger map.");
frame_support::print("The number of removed key/value is:");
frame_support::print(e);
// Kill old storages
deprecated::Stakers::<T>::remove_all();
deprecated::SlotStake::<T>::kill();
deprecated::CurrentElected::<T>::kill();
deprecated::CurrentEraStart::<T>::kill();
deprecated::CurrentEraStartSessionIndex::kill();
deprecated::CurrentEraPointsEarned::kill();
/// In this implementation `new_session(session)` must be called before `end_session(session-1)`
/// i.e. the new session must be planned before the ending of the previous session.
///
/// Once the first new_session is planned, all session must start and then end in order, though
/// some session can lag in between the newest session planned and the latest session started.
impl<T: Trait> pallet_session::SessionManager<T::AccountId> for Module<T> {
fn new_session(new_index: SessionIndex) -> Option<Vec<T::AccountId>> {
Self::ensure_storage_upgraded();
Self::new_session(new_index)
}
fn start_session(start_index: SessionIndex) {
Self::start_session(start_index)
}
fn end_session(end_index: SessionIndex) {
Self::end_session(end_index)
/// This implementation has the same constrains as the implementation of
/// `pallet_session::SessionManager`.
impl<T: Trait> SessionManager<T::AccountId, Exposure<T::AccountId, BalanceOf<T>>> for Module<T> {
fn new_session(new_index: SessionIndex)
-> Option<Vec<(T::AccountId, Exposure<T::AccountId, BalanceOf<T>>)>>
<Self as pallet_session::SessionManager<_>>::new_session(new_index).map(|validators| {
let current_era = Self::current_era()
// Must be some as a new era has been created.
.unwrap_or(0);
(v, exposure)
}).collect()
})
}
fn start_session(start_index: SessionIndex) {
<Self as pallet_session::SessionManager<_>>::start_session(start_index)
}
fn end_session(end_index: SessionIndex) {
<Self as pallet_session::SessionManager<_>>::end_session(end_index)
/// Add reward points to block authors:
/// * 20 points to the block producer for producing a (non-uncle) block in the relay chain,
/// * 2 points to the block producer for each reference to a previously unreferenced uncle, and
/// * 1 point to the producer of each referenced uncle block.
impl<T> pallet_authorship::EventHandler<T::AccountId, T::BlockNumber> for Module<T>
where
T: Trait + pallet_authorship::Trait + pallet_session::Trait
{
fn note_author(author: T::AccountId) {
}
fn note_uncle(author: T::AccountId, _age: T::BlockNumber) {
(<pallet_authorship::Module<T>>::author(), 2),
/// A `Convert` implementation that finds the stash of the given controller account,
/// if any.
pub struct StashOf<T>(sp_std::marker::PhantomData<T>);
impl<T: Trait> Convert<T::AccountId, Option<T::AccountId>> for StashOf<T> {
fn convert(controller: T::AccountId) -> Option<T::AccountId> {
<Module<T>>::ledger(&controller).map(|l| l.stash)
}
}
/// A typed conversion from stash account ID to the active exposure of nominators
/// on that account.
///
/// 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`.
pub struct ExposureOf<T>(sp_std::marker::PhantomData<T>);
impl<T: Trait> Convert<T::AccountId, Option<Exposure<T::AccountId, BalanceOf<T>>>>
for ExposureOf<T>
{
fn convert(validator: T::AccountId) -> Option<Exposure<T::AccountId, BalanceOf<T>>> {
if let Some(active_era) = <Module<T>>::active_era() {
Some(<Module<T>>::eras_stakers(active_era.index, &validator))
} else {
None
}
/// This is intended to be used with `FilterHistoricalOffences`.
impl <T: Trait> OnOffenceHandler<T::AccountId, pallet_session::historical::IdentificationTuple<T>> for Module<T> where
T: pallet_session::Trait<ValidatorId = <T as frame_system::Trait>::AccountId>,
T: pallet_session::historical::Trait<
FullIdentification = Exposure<<T as frame_system::Trait>::AccountId, BalanceOf<T>>,
FullIdentificationOf = ExposureOf<T>,
>,
T::SessionHandler: pallet_session::SessionHandler<<T as frame_system::Trait>::AccountId>,
T::SessionManager: pallet_session::SessionManager<<T as frame_system::Trait>::AccountId>,
T::ValidatorIdOf: Convert<<T as frame_system::Trait>::AccountId, Option<<T as frame_system::Trait>::AccountId>>
offenders: &[OffenceDetails<T::AccountId, pallet_session::historical::IdentificationTuple<T>>],
slash_session: SessionIndex,
<Module<T>>::ensure_storage_upgraded();
let reward_proportion = SlashRewardFraction::get();
let active_era = {
let active_era = Self::active_era();
if active_era.is_none() {
return
}
active_era.unwrap().index
};
let active_era_start_session_index = Self::eras_start_session_index(active_era)
.unwrap_or_else(|| {
frame_support::print("Error: start_session_index must be set for current_era");
0
});
let window_start = active_era.saturating_sub(T::BondingDuration::get());
// fast path for active-era report - most likely.
// `slash_session` cannot be in a future active era. It must be in `active_era` or before.
let slash_era = if slash_session >= active_era_start_session_index {
active_era
} else {
let eras = BondedEras::get();
// reverse because it's more likely to find reports from recent eras.
match eras.iter().rev().filter(|&&(_, ref sesh)| sesh <= &slash_session).next() {
None => return, // before bonding period. defensive - should be filtered out.
Some(&(ref slash_era, _)) => *slash_era,
}
};
<Self as Store>::EarliestUnappliedSlash::mutate(|earliest| {
if earliest.is_none() {
}
});
let slash_defer_duration = T::SlashDeferDuration::get();
for (details, slash_fraction) in offenders.iter().zip(slash_fraction) {
let stash = &details.offender.0;
let exposure = &details.offender.1;
// Skip if the validator is invulnerable.
if Self::invulnerables().contains(stash) {
continue
}
let unapplied = slashing::compute_slash::<T>(slashing::SlashParams {
stash,
slash: *slash_fraction,
exposure,
slash_era,
window_start,
reward_proportion,
});
if let Some(mut unapplied) = unapplied {
unapplied.reporters = details.reporters.clone();
if slash_defer_duration == 0 {
// apply right away.
slashing::apply_slash::<T>(unapplied);
} else {
// defer to end of some `slash_defer_duration` from now.
<Self as Store>::UnappliedSlashes::mutate(
move |for_later| for_later.push(unapplied),
);
}
}
}
}
}
/// Filter historical offences out and only allow those from the bonding period.
pub struct FilterHistoricalOffences<T, R> {
_inner: sp_std::marker::PhantomData<(T, R)>,
}
impl<T, Reporter, Offender, R, O> ReportOffence<Reporter, Offender, O>
for FilterHistoricalOffences<Module<T>, R> where
T: Trait,
R: ReportOffence<Reporter, Offender, O>,
O: Offence<Offender>,
{
fn report_offence(reporters: Vec<Reporter>, offence: O) -> Result<(), OffenceError> {
<Module<T>>::ensure_storage_upgraded();
// disallow any slashing from before the current bonding period.
let offence_session = offence.session_index();
let bonded_eras = BondedEras::get();
if bonded_eras.first().filter(|(_, start)| offence_session >= *start).is_some() {
R::report_offence(reporters, offence)
} else {
<Module<T>>::deposit_event(
RawEvent::OldSlashingReportDiscarded(offence_session)