Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ impl timestamp::Trait for Runtime {
impl session::Trait for Runtime {
type ConvertAccountIdToSessionKey = ();
type OnSessionChange = (Staking, grandpa::SyncedAuthorities<Runtime>);
type OnDisable = Staking;
type CheckRotateSession = session::AuraCheckRotateSession<Self>;
type Event = Event;
}

Expand Down
86 changes: 72 additions & 14 deletions srml/session/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@
use rstd::prelude::*;
use primitives::traits::{Zero, One, Convert};
use srml_support::{StorageValue, StorageMap, for_each_tuple, decl_module, decl_event, decl_storage};
use srml_support::{dispatch::Result, traits::OnFreeBalanceZero};
use srml_support::traits::OnFreeBalanceZero;
use system::ensure_signed;
use rstd::ops::Mul;

Expand All @@ -128,6 +128,12 @@ pub trait OnSessionChange<T> {
fn on_session_change(time_elapsed: T, should_reward: bool);
}

/// A validator was disabled.
pub trait OnDisable<T> {
/// Validator was disabled.
fn on_disable(account_id: T);
}

macro_rules! impl_session_change {
() => (
impl<T> OnSessionChange<T> for () {
Expand All @@ -146,13 +152,58 @@ macro_rules! impl_session_change {

for_each_tuple!(impl_session_change);

macro_rules! impl_disable {
() => (
impl<T> OnDisable<T> for () {
fn on_disable(_: T) {}
}
);

( $($t:ident)* ) => {
impl<T: Clone, $($t: OnDisable<T>),*> OnDisable<T> for ($($t,)*) {
fn on_disable(account_id: T) {
$($t::on_disable(account_id.clone());)*
}
}
}
}

for_each_tuple!(impl_disable);

pub trait CheckRotateSession<BlockNumber> {
fn check_rotate_session(block_number: BlockNumber);
}

pub struct AuraCheckRotateSession<T>(rstd::marker::PhantomData<T>);

impl<T: Trait> CheckRotateSession<T::BlockNumber> for AuraCheckRotateSession<T> {
/// Hook to be called after transaction processing.
fn check_rotate_session(block_number: T::BlockNumber) {
// Do this last, after the staking system has had the chance to switch out the authorities for the
// new set.
// Check block number and call `rotate_session` if necessary.
let is_final_block = ((block_number - <Module<T>>::last_length_change()) % <Module<T>>::length()).is_zero();
let (should_end_session, apply_rewards) = <ForcingNewSession<T>>::take()
.map_or((is_final_block, is_final_block), |apply_rewards| (true, apply_rewards));
if should_end_session {
<Module<T>>::rotate_session(is_final_block, apply_rewards);
}
}
}

pub trait Trait: timestamp::Trait + consensus::Trait {
/// Create a session key from an account key.
type ConvertAccountIdToSessionKey: Convert<Self::AccountId, Option<Self::SessionKey>>;

/// Handler when a session changes.
type OnSessionChange: OnSessionChange<Self::Moment>;

/// Handler when a validator is disabled.
type OnDisable: OnDisable<Self::AccountId>;

/// Hook for rotating sessions.
type CheckRotateSession: CheckRotateSession<Self::BlockNumber>;

/// The overarching event type.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
Expand All @@ -175,8 +226,8 @@ decl_module! {
}

/// Forces a new session.
fn force_new_session(apply_rewards: bool) -> Result {
Self::apply_force_new_session(apply_rewards)
fn force_new_session(apply_rewards: bool) {
Self::apply_force_new_session(apply_rewards);
}

/// Called when a block is finalized. Will rotate session if it is the last
Expand Down Expand Up @@ -237,9 +288,8 @@ impl<T: Trait> Module<T> {

// INTERNAL API (available to other runtime modules)
/// Forces a new session, no origin.
pub fn apply_force_new_session(apply_rewards: bool) -> Result {
pub fn apply_force_new_session(apply_rewards: bool) {
<ForcingNewSession<T>>::put(apply_rewards);
Ok(())
}

/// Set the current set of validators.
Expand All @@ -252,15 +302,7 @@ impl<T: Trait> Module<T> {

/// Hook to be called after transaction processing.
pub fn check_rotate_session(block_number: T::BlockNumber) {
// Do this last, after the staking system has had the chance to switch out the authorities for the
// new set.
// Check block number and call `rotate_session` if necessary.
let is_final_block = ((block_number - Self::last_length_change()) % Self::length()).is_zero();
let (should_end_session, apply_rewards) = <ForcingNewSession<T>>::take()
.map_or((is_final_block, is_final_block), |apply_rewards| (true, apply_rewards));
if should_end_session {
Self::rotate_session(is_final_block, apply_rewards);
}
T::CheckRotateSession::check_rotate_session(block_number);
}

/// Move on to next session: register the new authority set.
Expand Down Expand Up @@ -318,6 +360,11 @@ impl<T: Trait> Module<T> {
let block_number = <system::Module<T>>::block_number();
length_minus_1 - (block_number - Self::last_length_change() + length_minus_1) % length
}

/// Disables a validator.
pub fn disable_validator(val: T::AccountId) {
T::OnDisable::on_disable(val);
}
}

impl<T: Trait> OnFreeBalanceZero<T::AccountId> for Module<T> {
Expand All @@ -343,12 +390,21 @@ mod tests {

thread_local!{
static NEXT_VALIDATORS: RefCell<Vec<u64>> = RefCell::new(vec![1, 2, 3]);
static DISABLED_VALIDATORS: RefCell<Vec<u64>> = RefCell::new(vec![]);
}

pub struct TestOnSessionChange;
impl OnSessionChange<u64> for TestOnSessionChange {
fn on_session_change(_elapsed: u64, _should_reward: bool) {
NEXT_VALIDATORS.with(|v| Session::set_validators(&*v.borrow()));
DISABLED_VALIDATORS.with(|v| v.borrow_mut().clear());
}
}

pub struct TestOnDisable;
impl OnDisable<u64> for TestOnDisable {
fn on_disable(account_id: u64) {
DISABLED_VALIDATORS.with(|v| v.borrow_mut().push(account_id));
}
}

Expand Down Expand Up @@ -379,6 +435,8 @@ mod tests {
impl Trait for Test {
type ConvertAccountIdToSessionKey = ConvertUintAuthorityId;
type OnSessionChange = TestOnSessionChange;
type OnDisable = TestOnDisable;
type CheckRotateSession = AuraCheckRotateSession<Self>;
type Event = ();
}

Expand Down
18 changes: 12 additions & 6 deletions srml/staking/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@
use runtime_io::with_storage;
use rstd::{prelude::*, result, collections::btree_map::BTreeMap};
use parity_codec::{HasCompact, Encode, Decode};
use srml_support::{StorageValue, StorageMap, EnumerableStorageMap, dispatch::Result};
use srml_support::{StorageValue, StorageMap, EnumerableStorageMap};
use srml_support::{decl_module, decl_event, decl_storage, ensure};
use srml_support::traits::{
Currency, OnFreeBalanceZero, OnDilution, LockIdentifier, LockableCurrency, WithdrawReasons,
Expand Down Expand Up @@ -750,8 +750,8 @@ decl_module! {

/// Force there to be a new era. This also forces a new session immediately after.
/// `apply_rewards` should be true for validators to get the session reward.
fn force_new_era(apply_rewards: bool) -> Result {
Self::apply_force_new_era(apply_rewards)
fn force_new_era(apply_rewards: bool) {
Self::apply_force_new_era(apply_rewards);
}

/// Set the offline slash grace period.
Expand Down Expand Up @@ -780,9 +780,9 @@ decl_event!(

impl<T: Trait> Module<T> {
/// Just force_new_era without origin check.
fn apply_force_new_era(apply_rewards: bool) -> Result {
fn apply_force_new_era(apply_rewards: bool) {
<ForcingNewEra<T>>::put(());
<session::Module<T>>::apply_force_new_session(apply_rewards)
<session::Module<T>>::apply_force_new_session(apply_rewards);
}

// PUBLIC IMMUTABLES
Expand Down Expand Up @@ -1104,7 +1104,7 @@ impl<T: Trait> Module<T> {
.unwrap_or(slash_exposure);
let _ = Self::slash_validator(&stash, slash);
<Validators<T>>::remove(&stash);
let _ = Self::apply_force_new_era(false);
<session::Module<T>>::disable_validator(controller);

RawEvent::OfflineSlash(stash.clone(), slash)
} else {
Expand All @@ -1122,6 +1122,12 @@ impl<T: Trait> OnSessionChange<T::Moment> for Module<T> {
}
}

impl<T: Trait> session::OnDisable<T::AccountId> for Module<T> {
fn on_disable(_account: T::AccountId) {
Self::apply_force_new_era(false);
}
}

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) {
Expand Down
2 changes: 2 additions & 0 deletions srml/staking/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ impl balances::Trait for Test {
impl session::Trait for Test {
type ConvertAccountIdToSessionKey = ConvertUintAuthorityId;
type OnSessionChange = Staking;
type OnDisable = Staking;
type CheckRotateSession = session::AuraCheckRotateSession<Self>;
type Event = ();
}
impl timestamp::Trait for Test {
Expand Down