New sessions, kill consensus module (#2802)

* Draft of new sessions

* Reintroduce tuple impls

* Move staking module to new session API

* More work on staking and grandpa.

* Use iterator to avoid cloning and tuple macro

* Make runtime build again

* Polish the OpaqueKeys devex

* Move consensus logic into system & aura.

* Fix up system module

* Get build mostly going. Stuck at service.rs

* Building again

* Update srml/staking/src/lib.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Refactoring out Consensus module, AuthorityIdOf, &c.

* Refactored out DigestItem::AuthoritiesChanged. Building.

* Remove tentative code

* Remove invalid comment

* Make Seal opaque and introduce nice methods for handling opaque items.

* Start to use proper digest for Aura authorities tracking.

* Fix up grandpa, remove system::Raw/Log

* Refactor Grandpa to use new logging infrastructure.

Also make authorityid/sessionkey static. Switch over to storing
authorities in a straight Vec.

* Building again

* Tidy up some AuthorityIds

* Expunge most of the rest of the AuthorityKey confusion.

Also, de-generify Babe and re-generify Aura.

* Remove cruft

* Untangle last of the `AuthorityId`s.

* Sort out finality_tracker

* Refactor median getting

* Apply suggestions from code review

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Session tests works

* Update core/sr-primitives/src/generic/digest.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Session tests works

* Fix for staking from @dvc94ch

* log an error

* fix test runtime build

* Some test fixes

* Staking mock update to new session api.

* Fix build.

* Move OpaqueKeys to primitives.

* Use on_initialize instead of check_rotate_session.

* Update tests to new staking api.

* fixup mock

* Fix bond_extra_and_withdraw_unbonded_works.

* Fix bond_with_little_staked_value_bounded_by_slot_stake.

* Fix bond_with_no_staked_value.

* Fix change_controller_works.

* Fix less_than_needed_candidates_works.

* Fix multi_era_reward_should_work.

* Fix nominating_and_rewards_should_work.

* Fix nominators_also_get_slashed.

* Fix phragmen_large_scale_test.

* Fix phragmen_poc_works.

* Fix phragmen_score_should_be_accurate_on_large_stakes.

* Fix phragmen_should_not_overflow.

* Fix reward_destination_works.

* Fix rewards_should_work.

* Fix sessions_and_eras_should_work.

* Fix slot_stake_is_least_staked_validator.

* Fix too_many_unbond_calls_should_not_work.

* Fix wrong_vote_is_null.

* Fix runtime.

* Fix wasm runtime build.

* Update Cargo.lock

* Fix warnings.

* Fix grandpa tests.

* Fix test-runtime build.

* Fix template node build.

* Fix stuff.

* Update Cargo.lock to fix CI

* Re-add missing AuRa logs

Runtimes are required to know about every digest they receive ― they
panic otherwise.  This re-adds support for AuRa pre-runtime digests.

* Update core/consensus/babe/src/digest.rs

Co-Authored-By: DemiMarie-parity <48690212+DemiMarie-parity@users.noreply.github.com>

* Kill log trait and all that jazz.

* Refactor staking tests.

* Fix ci runtime wasm check.

* Line length 120.

* Make tests build again

* Remove trailing commas in function declarations

The `extern_functions!` macro doesn’t like them, perhaps due to a bug in
rustc.

* Fix type error

* Fix compilation errors

* Fix a test

* Another couple of fixes

* Fix another test

* More test fixes

* Another test fix

* Bump runtime.

* Wrap long line

* Fix build, remove redundant code.

* Issue to track TODO

* Leave the benchmark code alone.

* Fix missing `std::time::{Instant, Duration}`

* Indentation

* Aura ConsensusLog as enum
This commit is contained in:
Gavin Wood
2019-06-14 16:34:34 +02:00
committed by GitHub
parent 0f44a28ce3
commit bda8641892
128 changed files with 2646 additions and 3671 deletions
-2
View File
@@ -14,7 +14,6 @@ primitives = { package = "sr-primitives", path = "../../core/sr-primitives", def
srml-support = { path = "../support", default-features = false }
system = { package = "srml-system", path = "../system", default-features = false }
session = { package = "srml-session", path = "../session", default-features = false }
consensus = { package = "srml-consensus", path = "../consensus", default-features = false }
finality-tracker = { package = "srml-finality-tracker", path = "../finality-tracker", default-features = false }
[dev-dependencies]
@@ -31,7 +30,6 @@ std = [
"srml-support/std",
"primitives/std",
"system/std",
"consensus/std",
"session/std",
"finality-tracker/std",
]
+93 -172
View File
@@ -33,136 +33,84 @@ pub use substrate_finality_grandpa_primitives as fg_primitives;
#[cfg(feature = "std")]
use serde::Serialize;
use rstd::prelude::*;
use parity_codec as codec;
use codec::{Encode, Decode};
use fg_primitives::ScheduledChange;
use srml_support::{Parameter, decl_event, decl_storage, decl_module};
use srml_support::dispatch::Result;
use srml_support::storage::StorageValue;
use srml_support::storage::unhashed::StorageVec;
use primitives::traits::CurrentHeight;
use substrate_primitives::ed25519;
use system::ensure_signed;
use primitives::traits::MaybeSerializeDebug;
use ed25519::Public as AuthorityId;
use parity_codec::{self as codec, Encode, Decode};
use srml_support::{
decl_event, decl_storage, decl_module, dispatch::Result, storage::StorageValue
};
use primitives::{
generic::{DigestItem, OpaqueDigestItemId}, traits::CurrentHeight
};
use fg_primitives::{ScheduledChange, GRANDPA_ENGINE_ID};
pub use fg_primitives::{AuthorityId, AuthorityWeight};
use system::{ensure_signed, DigestOf};
mod mock;
mod tests;
struct AuthorityStorageVec<S: codec::Codec + Default>(rstd::marker::PhantomData<S>);
impl<S: codec::Codec + Default> StorageVec for AuthorityStorageVec<S> {
type Item = (S, u64);
const PREFIX: &'static [u8] = crate::fg_primitives::well_known_keys::AUTHORITY_PREFIX;
}
/// The log type of this crate, projected from module trait type.
pub type Log<T> = RawLog<
<T as system::Trait>::BlockNumber,
<T as Trait>::SessionKey,
>;
/// Logs which can be scanned by GRANDPA for authorities change events.
pub trait GrandpaChangeSignal<N> {
/// Try to cast the log entry as a contained signal.
fn as_signal(&self) -> Option<ScheduledChange<N>>;
/// Try to cast the log entry as a contained forced signal.
fn as_forced_signal(&self) -> Option<(N, ScheduledChange<N>)>;
}
/// A logs in this module.
/// Consensus log type of this module.
#[cfg_attr(feature = "std", derive(Serialize, Debug))]
#[derive(Encode, Decode, PartialEq, Eq, Clone)]
pub enum RawLog<N, SessionKey> {
pub enum Signal<N> {
/// Authorities set change has been signaled. Contains the new set of authorities
/// and the delay in blocks _to finalize_ before applying.
AuthoritiesChangeSignal(N, Vec<(SessionKey, u64)>),
AuthoritiesChange(ScheduledChange<N>),
/// A forced authorities set change. Contains in this order: the median last
/// finalized block when the change was signaled, the delay in blocks _to import_
/// before applying and the new set of authorities.
ForcedAuthoritiesChangeSignal(N, N, Vec<(SessionKey, u64)>),
ForcedAuthoritiesChange(N, ScheduledChange<N>),
}
impl<N: Clone, SessionKey> RawLog<N, SessionKey> {
impl<N> Signal<N> {
/// Try to cast the log entry as a contained signal.
pub fn as_signal(&self) -> Option<(N, &[(SessionKey, u64)])> {
match *self {
RawLog::AuthoritiesChangeSignal(ref delay, ref signal) => Some((delay.clone(), signal)),
RawLog::ForcedAuthoritiesChangeSignal(_, _, _) => None,
pub fn try_into_change(self) -> Option<ScheduledChange<N>> {
match self {
Signal::AuthoritiesChange(change) => Some(change),
Signal::ForcedAuthoritiesChange(_, _) => None,
}
}
/// Try to cast the log entry as a contained forced signal.
pub fn as_forced_signal(&self) -> Option<(N, N, &[(SessionKey, u64)])> {
match *self {
RawLog::ForcedAuthoritiesChangeSignal(ref median, ref delay, ref signal) => Some((median.clone(), delay.clone(), signal)),
RawLog::AuthoritiesChangeSignal(_, _) => None,
pub fn try_into_forced_change(self) -> Option<(N, ScheduledChange<N>)> {
match self {
Signal::ForcedAuthoritiesChange(median, change) => Some((median, change)),
Signal::AuthoritiesChange(_) => None,
}
}
}
impl<N, SessionKey> GrandpaChangeSignal<N> for RawLog<N, SessionKey>
where N: Clone, SessionKey: Clone + Into<AuthorityId>,
{
fn as_signal(&self) -> Option<ScheduledChange<N>> {
RawLog::as_signal(self).map(|(delay, next_authorities)| ScheduledChange {
delay,
next_authorities: next_authorities.iter()
.cloned()
.map(|(k, w)| (k.into(), w))
.collect(),
})
}
fn as_forced_signal(&self) -> Option<(N, ScheduledChange<N>)> {
RawLog::as_forced_signal(self).map(|(median, delay, next_authorities)| (median, ScheduledChange {
delay,
next_authorities: next_authorities.iter()
.cloned()
.map(|(k, w)| (k.into(), w))
.collect(),
}))
}
}
pub trait Trait: system::Trait {
/// Type for all log entries of this module.
type Log: From<Log<Self>> + Into<system::DigestItemOf<Self>>;
/// The session key type used by authorities.
type SessionKey: Parameter + Default + MaybeSerializeDebug;
/// The event type of this module.
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
type Event: From<Event> + Into<<Self as system::Trait>::Event>;
}
/// A stored pending change, old format.
// TODO: remove shim
// https://github.com/paritytech/substrate/issues/1614
#[derive(Encode, Decode)]
pub struct OldStoredPendingChange<N, SessionKey> {
pub struct OldStoredPendingChange<N> {
/// The block number this was scheduled at.
pub scheduled_at: N,
/// The delay in blocks until it will be applied.
pub delay: N,
/// The next authority set.
pub next_authorities: Vec<(SessionKey, u64)>,
pub next_authorities: Vec<(AuthorityId, u64)>,
}
/// A stored pending change.
#[derive(Encode)]
pub struct StoredPendingChange<N, SessionKey> {
pub struct StoredPendingChange<N> {
/// The block number this was scheduled at.
pub scheduled_at: N,
/// The delay in blocks until it will be applied.
pub delay: N,
/// The next authority set.
pub next_authorities: Vec<(SessionKey, u64)>,
pub next_authorities: Vec<(AuthorityId, u64)>,
/// If defined it means the change was forced and the given block number
/// indicates the median last finalized block when the change was signaled.
pub forced: Option<N>,
}
impl<N: Decode, SessionKey: Decode> Decode for StoredPendingChange<N, SessionKey> {
impl<N: Decode> Decode for StoredPendingChange<N> {
fn decode<I: codec::Input>(value: &mut I) -> Option<Self> {
let old = OldStoredPendingChange::decode(value)?;
let forced = <Option<N>>::decode(value).unwrap_or(None);
@@ -177,43 +125,31 @@ impl<N: Decode, SessionKey: Decode> Decode for StoredPendingChange<N, SessionKey
}
decl_event!(
pub enum Event<T> where <T as Trait>::SessionKey {
pub enum Event {
/// New authority set has been applied.
NewAuthorities(Vec<(SessionKey, u64)>),
NewAuthorities(Vec<(AuthorityId, u64)>),
}
);
decl_storage! {
trait Store for Module<T: Trait> as GrandpaFinality {
// Pending change: (signaled at, scheduled change).
PendingChange get(pending_change): Option<StoredPendingChange<T::BlockNumber, T::SessionKey>>;
// next block number where we can force a change.
/// The current authority set.
Authorities get(authorities) config(): Vec<(AuthorityId, AuthorityWeight)>;
/// Pending change: (signaled at, scheduled change).
PendingChange: Option<StoredPendingChange<T::BlockNumber>>;
/// next block number where we can force a change.
NextForced get(next_forced): Option<T::BlockNumber>;
}
add_extra_genesis {
config(authorities): Vec<(T::SessionKey, u64)>;
build(|storage: &mut primitives::StorageOverlay, _: &mut primitives::ChildrenStorageOverlay, config: &GenesisConfig<T>| {
use codec::{Encode, KeyedVec};
let auth_count = config.authorities.len() as u32;
config.authorities.iter().enumerate().for_each(|(i, v)| {
storage.insert((i as u32).to_keyed_vec(
crate::fg_primitives::well_known_keys::AUTHORITY_PREFIX),
v.encode()
);
});
storage.insert(
crate::fg_primitives::well_known_keys::AUTHORITY_COUNT.to_vec(),
auth_count.encode(),
);
});
/// `true` if we are currently stalled.
Stalled get(stalled): Option<(T::BlockNumber, T::BlockNumber)>;
}
}
decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {
fn deposit_event<T>() = default;
fn deposit_event() = default;
/// Report some misbehavior.
fn report_misbehavior(origin, _report: Vec<u8>) {
@@ -225,24 +161,28 @@ decl_module! {
if let Some(pending_change) = <PendingChange<T>>::get() {
if block_number == pending_change.scheduled_at {
if let Some(median) = pending_change.forced {
Self::deposit_log(RawLog::ForcedAuthoritiesChangeSignal(
Self::deposit_log(Signal::ForcedAuthoritiesChange(
median,
pending_change.delay,
pending_change.next_authorities.clone(),
));
ScheduledChange{
delay: pending_change.delay,
next_authorities: pending_change.next_authorities.clone(),
}
))
} else {
Self::deposit_log(RawLog::AuthoritiesChangeSignal(
pending_change.delay,
pending_change.next_authorities.clone(),
Self::deposit_log(Signal::AuthoritiesChange(
ScheduledChange{
delay: pending_change.delay,
next_authorities: pending_change.next_authorities.clone(),
}
));
}
}
if block_number == pending_change.scheduled_at + pending_change.delay {
<Authorities<T>>::put(&pending_change.next_authorities);
Self::deposit_event(
RawEvent::NewAuthorities(pending_change.next_authorities.clone())
Event::NewAuthorities(pending_change.next_authorities)
);
<AuthorityStorageVec<T::SessionKey>>::set_items(pending_change.next_authorities);
<PendingChange<T>>::kill();
}
}
@@ -252,8 +192,8 @@ decl_module! {
impl<T: Trait> Module<T> {
/// Get the current set of authorities, along with their respective weights.
pub fn grandpa_authorities() -> Vec<(T::SessionKey, u64)> {
<AuthorityStorageVec<T::SessionKey>>::items()
pub fn grandpa_authorities() -> Vec<(AuthorityId, u64)> {
<Authorities<T>>::get()
}
/// Schedule a change in the authorities.
@@ -271,11 +211,11 @@ impl<T: Trait> Module<T> {
/// No change should be signaled while any change is pending. Returns
/// an error if a change is already pending.
pub fn schedule_change(
next_authorities: Vec<(T::SessionKey, u64)>,
next_authorities: Vec<(AuthorityId, u64)>,
in_blocks: T::BlockNumber,
forced: Option<T::BlockNumber>,
) -> Result {
if Self::pending_change().is_none() {
if !<PendingChange<T>>::exists() {
let scheduled_at = system::ChainContext::<T>::default().current_height();
if let Some(_) = forced {
@@ -302,79 +242,60 @@ impl<T: Trait> Module<T> {
}
/// Deposit one of this module's logs.
fn deposit_log(log: Log<T>) {
<system::Module<T>>::deposit_log(<T as Trait>::Log::from(log).into());
fn deposit_log(log: Signal<T::BlockNumber>) {
let log: DigestItem<T::Hash> = DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode());
<system::Module<T>>::deposit_log(log.into());
}
}
impl<T: Trait> Module<T> where AuthorityId: core::convert::From<<T as Trait>::SessionKey> {
/// See if the digest contains any standard scheduled change.
pub fn scrape_digest_change(log: &Log<T>)
impl<T: Trait> Module<T> {
pub fn grandpa_log(digest: &DigestOf<T>) -> Option<Signal<T::BlockNumber>> {
let id = OpaqueDigestItemId::Consensus(&GRANDPA_ENGINE_ID);
digest.convert_first(|l| l.try_to::<Signal<T::BlockNumber>>(id))
}
pub fn pending_change(digest: &DigestOf<T>)
-> Option<ScheduledChange<T::BlockNumber>>
{
<Log<T> as GrandpaChangeSignal<T::BlockNumber>>::as_signal(log)
Self::grandpa_log(digest).and_then(|signal| signal.try_into_change())
}
/// See if the digest contains any forced scheduled change.
pub fn scrape_digest_forced_change(log: &Log<T>)
pub fn forced_change(digest: &DigestOf<T>)
-> Option<(T::BlockNumber, ScheduledChange<T::BlockNumber>)>
{
<Log<T> as GrandpaChangeSignal<T::BlockNumber>>::as_forced_signal(log)
Self::grandpa_log(digest).and_then(|signal| signal.try_into_forced_change())
}
}
/// Helper for authorities being synchronized with the general session authorities.
///
/// This is not the only way to manage an authority set for GRANDPA, but it is
/// a convenient one. When this is used, no other mechanism for altering authority
/// sets should be.
pub struct SyncedAuthorities<T>(::rstd::marker::PhantomData<T>);
// FIXME: remove when https://github.com/rust-lang/rust/issues/26925 is fixed
impl<T> Default for SyncedAuthorities<T> {
fn default() -> Self {
SyncedAuthorities(::rstd::marker::PhantomData)
}
}
impl<X, T> session::OnSessionChange<X> for SyncedAuthorities<T> where
T: Trait + consensus::Trait<SessionKey=<T as Trait>::SessionKey>,
<T as consensus::Trait>::Log: From<consensus::RawLog<<T as Trait>::SessionKey>>
{
fn on_session_change(_: X, _: bool) {
use primitives::traits::Zero;
let next_authorities = <consensus::Module<T>>::authorities()
.into_iter()
.map(|key| (key, 1)) // evenly-weighted.
.collect::<Vec<(<T as Trait>::SessionKey, u64)>>();
impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
type Key = AuthorityId;
fn on_new_session<'a, I: 'a>(changed: bool, validators: I)
where I: Iterator<Item=(&'a T::AccountId, AuthorityId)>
{
// instant changes
let last_authorities = <Module<T>>::grandpa_authorities();
if next_authorities != last_authorities {
let _ = <Module<T>>::schedule_change(next_authorities, Zero::zero(), None);
if changed {
let next_authorities = validators.map(|(_, k)| (k, 1u64)).collect::<Vec<_>>();
let last_authorities = <Module<T>>::grandpa_authorities();
if next_authorities != last_authorities {
use primitives::traits::Zero;
if let Some((further_wait, median)) = <Stalled<T>>::take() {
let _ = Self::schedule_change(next_authorities, further_wait, Some(median));
} else {
let _ = Self::schedule_change(next_authorities, Zero::zero(), None);
}
}
}
}
fn on_disabled(_i: usize) {
// ignore?
}
}
impl<T> finality_tracker::OnFinalizationStalled<T::BlockNumber> for SyncedAuthorities<T> where
T: Trait + consensus::Trait<SessionKey=<T as Trait>::SessionKey>,
<T as consensus::Trait>::Log: From<consensus::RawLog<<T as Trait>::SessionKey>>,
T: finality_tracker::Trait,
{
fn on_stalled(further_wait: T::BlockNumber) {
impl<T: Trait> finality_tracker::OnFinalizationStalled<T::BlockNumber> for Module<T> {
fn on_stalled(further_wait: T::BlockNumber, median: T::BlockNumber) {
// when we record old authority sets, we can use `finality_tracker::median`
// to figure out _who_ failed. until then, we can't meaningfully guard
// against `next == last` the way that normal session changes do.
let next_authorities = <consensus::Module<T>>::authorities()
.into_iter()
.map(|key| (key, 1)) // evenly-weighted.
.collect::<Vec<(<T as Trait>::SessionKey, u64)>>();
let median = <finality_tracker::Module<T>>::median();
// schedule a change for `further_wait` blocks.
let _ = <Module<T>>::schedule_change(next_authorities, further_wait, Some(median));
<Stalled<T>>::put((further_wait, median));
}
}
+16 -12
View File
@@ -18,21 +18,23 @@
#![cfg(test)]
use primitives::{BuildStorage, traits::IdentityLookup, testing::{Digest, DigestItem, Header}};
use primitives::generic::DigestItem as GenDigestItem;
use primitives::{
BuildStorage, DigestItem, traits::IdentityLookup, testing::{Header, UintAuthorityId}
};
use runtime_io;
use srml_support::{impl_outer_origin, impl_outer_event};
use substrate_primitives::{H256, Blake2Hasher};
use parity_codec::{Encode, Decode};
use crate::{GenesisConfig, Trait, Module, RawLog};
use crate::{AuthorityId, GenesisConfig, Trait, Module, Signal};
use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID;
impl_outer_origin!{
pub enum Origin for Test {}
}
impl From<RawLog<u64, u64>> for DigestItem {
fn from(log: RawLog<u64, u64>) -> DigestItem {
GenDigestItem::Other(log.encode())
impl From<Signal<u64>> for DigestItem<H256> {
fn from(log: Signal<u64>) -> DigestItem<H256> {
DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode())
}
}
@@ -40,9 +42,8 @@ impl From<RawLog<u64, u64>> for DigestItem {
#[derive(Clone, PartialEq, Eq, Debug, Decode, Encode)]
pub struct Test;
impl Trait for Test {
type Log = DigestItem;
type SessionKey = u64;
type Event = TestEvent;
}
impl system::Trait for Test {
type Origin = Origin;
@@ -50,12 +51,10 @@ impl system::Trait for Test {
type BlockNumber = u64;
type Hash = H256;
type Hashing = ::primitives::traits::BlakeTwo256;
type Digest = Digest;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = TestEvent;
type Log = DigestItem;
}
mod grandpa {
@@ -64,14 +63,19 @@ mod grandpa {
impl_outer_event!{
pub enum TestEvent for Test {
grandpa<T>,
grandpa,
}
}
pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> {
vec.into_iter().map(|(id, weight)| (UintAuthorityId(id).into(), weight)).collect()
}
pub fn new_test_ext(authorities: Vec<(u64, u64)>) -> runtime_io::TestExternalities<Blake2Hasher> {
let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap().0;
t.extend(GenesisConfig::<Test> {
authorities,
_genesis_phantom_data: Default::default(),
authorities: to_authorities(authorities),
}.build_storage().unwrap().0);
t.into()
}
+42 -38
View File
@@ -18,35 +18,37 @@
#![cfg(test)]
use primitives::{testing, traits::OnFinalize};
use primitives::traits::Header;
use primitives::testing::Digest;
use primitives::traits::{Header, OnFinalize};
use runtime_io::with_externalities;
use crate::mock::{Grandpa, System, new_test_ext};
use crate::mock::*;
use system::{EventRecord, Phase};
use crate::{RawLog, RawEvent};
use codec::{Decode, Encode};
use fg_primitives::ScheduledChange;
use super::*;
#[test]
fn authorities_change_logged() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialize(&1, &Default::default(), &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 0, None).unwrap();
Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 0, None).unwrap();
System::note_finished_extrinsics();
Grandpa::on_finalize(1);
let header = System::finalize();
assert_eq!(header.digest, testing::Digest {
assert_eq!(header.digest, Digest {
logs: vec![
RawLog::AuthoritiesChangeSignal(0, vec![(4, 1), (5, 1), (6, 1)]).into(),
Signal::AuthoritiesChange(
ScheduledChange { delay: 0, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) }
).into(),
],
});
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::Finalization,
event: RawEvent::NewAuthorities(vec![(4, 1), (5, 1), (6, 1)]).into(),
event: Event::NewAuthorities(to_authorities(vec![(4, 1), (5, 1), (6, 1)])).into(),
topics: vec![],
},
]);
@@ -57,12 +59,14 @@ fn authorities_change_logged() {
fn authorities_change_logged_after_delay() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialize(&1, &Default::default(), &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap();
Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap();
Grandpa::on_finalize(1);
let header = System::finalize();
assert_eq!(header.digest, testing::Digest {
assert_eq!(header.digest, Digest {
logs: vec![
RawLog::AuthoritiesChangeSignal(1, vec![(4, 1), (5, 1), (6, 1)]).into(),
Signal::AuthoritiesChange(
ScheduledChange { delay: 1, next_authorities: to_authorities(vec![(4, 1), (5, 1), (6, 1)]) }
).into(),
],
});
@@ -77,7 +81,7 @@ fn authorities_change_logged_after_delay() {
assert_eq!(System::events(), vec![
EventRecord {
phase: Phase::Finalization,
event: RawEvent::NewAuthorities(vec![(4, 1), (5, 1), (6, 1)]).into(),
event: Event::NewAuthorities(to_authorities(vec![(4, 1), (5, 1), (6, 1)])).into(),
topics: vec![],
},
]);
@@ -88,23 +92,23 @@ fn authorities_change_logged_after_delay() {
fn cannot_schedule_change_when_one_pending() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialize(&1, &Default::default(), &Default::default(), &Default::default());
Grandpa::schedule_change(vec![(4, 1), (5, 1), (6, 1)], 1, None).unwrap();
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
Grandpa::schedule_change(to_authorities(vec![(4, 1), (5, 1), (6, 1)]), 1, None).unwrap();
assert!(<PendingChange<Test>>::exists());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_err());
Grandpa::on_finalize(1);
let header = System::finalize();
System::initialize(&2, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
assert!(<PendingChange<Test>>::exists());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_err());
Grandpa::on_finalize(2);
let header = System::finalize();
System::initialize(&3, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok());
assert!(!<PendingChange<Test>>::exists());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_ok());
Grandpa::on_finalize(3);
let _header = System::finalize();
@@ -116,11 +120,11 @@ fn new_decodes_from_old() {
let old = OldStoredPendingChange {
scheduled_at: 5u32,
delay: 100u32,
next_authorities: vec![(1u64, 5), (2u64, 10), (3u64, 2)],
next_authorities: to_authorities(vec![(1, 5), (2, 10), (3, 2)]),
};
let encoded = old.encode();
let new = StoredPendingChange::<u32, u64>::decode(&mut &encoded[..]).unwrap();
let new = StoredPendingChange::<u32>::decode(&mut &encoded[..]).unwrap();
assert!(new.forced.is_none());
assert_eq!(new.scheduled_at, old.scheduled_at);
assert_eq!(new.delay, old.delay);
@@ -132,23 +136,23 @@ fn dispatch_forced_change() {
with_externalities(&mut new_test_ext(vec![(1, 1), (2, 1), (3, 1)]), || {
System::initialize(&1, &Default::default(), &Default::default(), &Default::default());
Grandpa::schedule_change(
vec![(4, 1), (5, 1), (6, 1)],
to_authorities(vec![(4, 1), (5, 1), (6, 1)]),
5,
Some(0),
).unwrap();
assert!(Grandpa::pending_change().is_some());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err());
assert!(<PendingChange<Test>>::exists());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, Some(0)).is_err());
Grandpa::on_finalize(1);
let mut header = System::finalize();
for i in 2..7 {
System::initialize(&i, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().unwrap().forced.is_some());
assert!(<PendingChange<Test>>::get().unwrap().forced.is_some());
assert_eq!(Grandpa::next_forced(), Some(11));
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, Some(0)).is_err());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_err());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, Some(0)).is_err());
Grandpa::on_finalize(i);
header = System::finalize();
@@ -158,9 +162,9 @@ fn dispatch_forced_change() {
// add a normal change.
{
System::initialize(&7, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]);
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_ok());
assert!(!<PendingChange<Test>>::exists());
assert_eq!(Grandpa::grandpa_authorities(), to_authorities(vec![(4, 1), (5, 1), (6, 1)]));
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_ok());
Grandpa::on_finalize(7);
header = System::finalize();
}
@@ -168,9 +172,9 @@ fn dispatch_forced_change() {
// run the normal change.
{
System::initialize(&8, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_some());
assert_eq!(Grandpa::grandpa_authorities(), vec![(4, 1), (5, 1), (6, 1)]);
assert!(Grandpa::schedule_change(vec![(5, 1)], 1, None).is_err());
assert!(<PendingChange<Test>>::exists());
assert_eq!(Grandpa::grandpa_authorities(), to_authorities(vec![(4, 1), (5, 1), (6, 1)]));
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1)]), 1, None).is_err());
Grandpa::on_finalize(8);
header = System::finalize();
}
@@ -179,18 +183,18 @@ fn dispatch_forced_change() {
// time.
for i in 9..11 {
System::initialize(&i, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert_eq!(Grandpa::grandpa_authorities(), vec![(5, 1)]);
assert!(!<PendingChange<Test>>::exists());
assert_eq!(Grandpa::grandpa_authorities(), to_authorities(vec![(5, 1)]));
assert_eq!(Grandpa::next_forced(), Some(11));
assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1)], 5, Some(0)).is_err());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1), (6, 1)]), 5, Some(0)).is_err());
Grandpa::on_finalize(i);
header = System::finalize();
}
{
System::initialize(&11, &header.hash(), &Default::default(), &Default::default());
assert!(Grandpa::pending_change().is_none());
assert!(Grandpa::schedule_change(vec![(5, 1), (6, 1), (7, 1)], 5, Some(0)).is_ok());
assert!(!<PendingChange<Test>>::exists());
assert!(Grandpa::schedule_change(to_authorities(vec![(5, 1), (6, 1), (7, 1)]), 5, Some(0)).is_ok());
assert_eq!(Grandpa::next_forced(), Some(21));
Grandpa::on_finalize(11);
header = System::finalize();