diff --git a/substrate/srml/consensus/src/lib.rs b/substrate/srml/consensus/src/lib.rs index 72ef1e7f5be809ae33bb20b06b4c8350eff04c9d..241f78ce199b40d6c1098d6d975ab654b4e99b2d 100644 --- a/substrate/srml/consensus/src/lib.rs +++ b/substrate/srml/consensus/src/lib.rs @@ -51,6 +51,9 @@ use primitives::bft::MisbehaviorReport; use substrate_primitives::storage::well_known_keys; use system::{ensure_signed, ensure_inherent}; +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; @@ -90,13 +93,13 @@ impl<SessionKey: Member> RawLog<SessionKey> { // Implementation for tests outside of this crate. #[cfg(any(feature = "std", test))] -impl<N> From<RawLog<N>> for primitives::testing::DigestItem { +impl<N> From<RawLog<N>> for primitives::testing::DigestItem where N: Into<u64> { fn from(log: RawLog<N>) -> primitives::testing::DigestItem { match log { RawLog::AuthoritiesChange(authorities) => primitives::generic::DigestItem::AuthoritiesChange ::<substrate_primitives::H256, u64>(authorities.into_iter() - .enumerate().map(|(i, _)| i as u64).collect()), + .map(Into::into).collect()), } } } @@ -211,13 +214,21 @@ impl<T: Trait> Module<T> { <OriginalAuthorities<T>>::put(current_authorities.unwrap_or_else(|| AuthorityStorageVec::<T::SessionKey>::items())); } + + /// 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()); + } } /// Finalization hook for the consensus module. impl<T: Trait> OnFinalise<T::BlockNumber> for Module<T> { fn on_finalise(_n: T::BlockNumber) { - if let Some(_) = <OriginalAuthorities<T>>::take() { - // TODO: call Self::deposit_log + if let Some(original_authorities) = <OriginalAuthorities<T>>::take() { + let current_authorities = AuthorityStorageVec::<T::SessionKey>::items(); + if current_authorities != original_authorities { + Self::deposit_log(RawLog::AuthoritiesChange(current_authorities)); + } } } } diff --git a/substrate/srml/consensus/src/mock.rs b/substrate/srml/consensus/src/mock.rs new file mode 100644 index 0000000000000000000000000000000000000000..e86731f52dbb7f6a47da03929b2c5cbb8eeba1b4 --- /dev/null +++ b/substrate/srml/consensus/src/mock.rs @@ -0,0 +1,62 @@ +// Copyright 2018 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see <http://www.gnu.org/licenses/>. + +//! Test utilities + +#![cfg(test)] + +use primitives::{BuildStorage, testing::{Digest, DigestItem, Header}}; +use runtime_io; +use substrate_primitives::{H256, Blake2Hasher, RlpCodec}; +use {GenesisConfig, Trait, Module, system}; + +impl_outer_origin!{ + pub enum Origin for Test {} +} + +// Workaround for https://github.com/rust-lang/rust/issues/26925 . Remove when sorted. +#[derive(Clone, PartialEq, Eq, Debug, Serialize, Deserialize)] +pub struct Test; +impl Trait for Test { + const NOTE_OFFLINE_POSITION: u32 = 1; + type Log = DigestItem; + type SessionKey = u64; + type OnOfflineValidator = (); +} +impl system::Trait for Test { + type Origin = Origin; + type Index = u64; + type BlockNumber = u64; + type Hash = H256; + type Hashing = ::primitives::traits::BlakeTwo256; + type Digest = Digest; + type AccountId = u64; + type Header = Header; + type Event = (); + type Log = DigestItem; +} + +pub fn new_test_ext(authorities: Vec<u64>) -> runtime_io::TestExternalities<Blake2Hasher, RlpCodec> { + let mut t = system::GenesisConfig::<Test>::default().build_storage().unwrap(); + t.extend(GenesisConfig::<Test>{ + code: vec![], + authorities, + }.build_storage().unwrap()); + t.into() +} + +pub type System = system::Module<Test>; +pub type Consensus = Module<Test>; diff --git a/substrate/srml/consensus/src/tests.rs b/substrate/srml/consensus/src/tests.rs new file mode 100644 index 0000000000000000000000000000000000000000..2e581759b5d983e501fc4c113508ec02d2a592ff --- /dev/null +++ b/substrate/srml/consensus/src/tests.rs @@ -0,0 +1,66 @@ +// Copyright 2017 Parity Technologies (UK) Ltd. +// This file is part of Substrate. + +// Substrate is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Substrate is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Substrate. If not, see <http://www.gnu.org/licenses/>. + +//! Tests for the module. + +#![cfg(test)] + +use super::*; +use primitives::{generic, testing}; +use runtime_io::with_externalities; +use substrate_primitives::H256; +use mock::{Consensus, System, new_test_ext}; + +#[test] +fn authorities_change_logged() { + with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { + System::initialise(&1, &Default::default(), &Default::default()); + Consensus::set_authorities(&[4, 5, 6]); + Consensus::on_finalise(1); + let header = System::finalise(); + assert_eq!(header.digest, testing::Digest { + logs: vec![ + generic::DigestItem::AuthoritiesChange::<H256, u64>(vec![4, 5, 6]), + ], + }); + }); +} + +#[test] +fn authorities_change_is_not_logged_when_not_changed() { + with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { + System::initialise(&1, &Default::default(), &Default::default()); + Consensus::on_finalise(1); + let header = System::finalise(); + assert_eq!(header.digest, testing::Digest { + logs: vec![], + }); + }); +} + +#[test] +fn authorities_change_is_not_logged_when_changed_back_to_original() { + with_externalities(&mut new_test_ext(vec![1, 2, 3]), || { + System::initialise(&1, &Default::default(), &Default::default()); + Consensus::set_authorities(&[4, 5, 6]); + Consensus::set_authorities(&[1, 2, 3]); + Consensus::on_finalise(1); + let header = System::finalise(); + assert_eq!(header.digest, testing::Digest { + logs: vec![], + }); + }); +}