Newer
Older
/// Call when a validator is determined to be offline. `count` is the
/// number of offenses the validator has committed.
///
/// NOTE: This is called with the controller (not the stash) account id.
pub fn on_offline_validator(controller: T::AccountId, count: usize) {
use primitives::traits::CheckedShl;
if let Some(l) = Self::ledger(&controller) {
let stash = l.stash;
// Early exit if validator is invulnerable.
if Self::invulnerables().contains(&stash) {
return
}
let slash_count = Self::slash_count(&stash);
let new_slash_count = slash_count + count as u32;
<SlashCount<T>>::insert(&stash, new_slash_count);
let grace = Self::offline_slash_grace();
if RECENT_OFFLINE_COUNT > 0 {
let item = (stash.clone(), <system::Module<T>>::block_number(), count as u32);
<RecentlyOffline<T>>::mutate(|v| if v.len() >= RECENT_OFFLINE_COUNT {
let index = v.iter()
.enumerate()
.min_by_key(|(_, (_, block, _))| block)
.expect("v is non-empty; qed")
.0;
v[index] = item;
} else {
v.push(item);
});
}
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
let prefs = Self::validators(&stash);
let unstake_threshold = prefs.unstake_threshold.min(MAX_UNSTAKE_THRESHOLD);
let max_slashes = grace + unstake_threshold;
let event = if new_slash_count > max_slashes {
let slash_exposure = Self::stakers(&stash).total;
let offline_slash_base = Self::offline_slash() * slash_exposure;
// They're bailing.
let slash = offline_slash_base
// Multiply slash_mantissa by 2^(unstake_threshold with upper bound)
.checked_shl(unstake_threshold)
.map(|x| x.min(slash_exposure))
.unwrap_or(slash_exposure);
let _ = Self::slash_validator(&stash, slash);
<Validators<T>>::remove(&stash);
let _ = Self::apply_force_new_era(false);
RawEvent::OfflineSlash(stash.clone(), slash)
} else {
RawEvent::OfflineWarning(stash.clone(), slash_count)
};
Self::deposit_event(event);
}
impl<T: Trait> OnSessionChange<T::Moment> for Module<T> {
fn on_session_change(elapsed: T::Moment, should_reward: bool) {
Self::new_session(elapsed, should_reward);
impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
fn on_free_balance_zero(stash: &T::AccountId) {
if let Some(controller) = <Bonded<T>>::take(stash) {
<Ledger<T>>::remove(&controller);
}
<Payee<T>>::remove(stash);
<SlashCount<T>>::remove(stash);
<Validators<T>>::remove(stash);
<Nominators<T>>::remove(stash);
impl<T: Trait> consensus::OnOfflineReport<Vec<u32>> for Module<T> {
fn handle_report(reported_indices: Vec<u32>) {
for validator_index in reported_indices {
let v = <session::Module<T>>::validators()[validator_index as usize].clone();
Self::on_offline_validator(v, 1);
}