Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Commit

Permalink
Beefy pallet test (#74)
Browse files Browse the repository at this point in the history
* setup mock

* test session change

* silence beefy

* clippy still

* no change - no log

* clippy again

* Apply suggestions from code review

Co-authored-by: Tomasz Drwięga <[email protected]>

* code review changes, added additional test

Co-authored-by: Tomasz Drwięga <[email protected]>
  • Loading branch information
adoerr and tomusdrw authored Feb 2, 2021
1 parent 7bd2795 commit 85d81b2
Show file tree
Hide file tree
Showing 4 changed files with 277 additions and 0 deletions.
7 changes: 7 additions & 0 deletions frame/beefy/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,17 @@ beefy-primitives = { path = "../primitives", default-features = false }

frame-support = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
frame-system = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

sp-runtime = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }
sp-std = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

pallet-session = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "master" }

[dev-dependencies]
sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
sp-staking = { git = "https://github.com/paritytech/substrate.git", branch = "master" }

[features]
default = ["std"]
std = [
Expand Down
6 changes: 6 additions & 0 deletions frame/beefy/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,12 @@ use sp_runtime::{
};
use sp_std::prelude::*;

#[cfg(test)]
mod mock;

#[cfg(test)]
mod tests;

pub trait Config: frame_system::Config {
/// The identifier type for an authority.
type AuthorityId: Member + Parameter + RuntimeAppPublic + Default;
Expand Down
161 changes: 161 additions & 0 deletions frame/beefy/src/mock.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// Copyright (C) 2020 - 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use std::vec;

use frame_support::{parameter_types, sp_io::TestExternalities, BasicExternalities};

use sp_core::H256;
use sp_runtime::{
app_crypto::ecdsa::Public,
impl_opaque_keys,
testing::Header,
traits::{BlakeTwo256, ConvertInto, IdentityLookup, OpaqueKeys},
Perbill,
};

use crate as pallet_beefy;

pub use beefy_primitives::{ecdsa::AuthorityId as BeefyId, ConsensusLog, BEEFY_ENGINE_ID};

impl_opaque_keys! {
pub struct MockSessionKeys {
pub dummy: pallet_beefy::Module<Test>,
}
}

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
type Block = frame_system::mocking::MockBlock<Test>;

frame_support::construct_runtime!(
pub enum Test where
Block = Block,
NodeBlock = Block,
UncheckedExtrinsic = UncheckedExtrinsic,
{
System: frame_system::{Module, Call, Config, Storage, Event<T>},
Beefy: pallet_beefy::{Module, Call, Config<T>, Storage},
Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
}
);

parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const SS58Prefix: u8 = 42;
}

impl frame_system::Config for Test {
type BaseCallFilter = ();
type BlockWeights = ();
type BlockLength = ();
type DbWeight = ();
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Call = Call;
type Hashing = BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = Event;
type BlockHashCount = BlockHashCount;
type Version = ();
type PalletInfo = PalletInfo;
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
type SystemWeightInfo = ();
type SS58Prefix = SS58Prefix;
}

impl pallet_beefy::Config for Test {
type AuthorityId = BeefyId;
}

parameter_types! {
pub const Period: u64 = 1;
pub const Offset: u64 = 0;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(33);
}

impl pallet_session::Config for Test {
type Event = Event;
type ValidatorId = u64;
type ValidatorIdOf = ConvertInto;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = MockSessionManager;
type SessionHandler = <MockSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = MockSessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
}

pub struct MockSessionManager;

impl pallet_session::SessionManager<u64> for MockSessionManager {
fn end_session(_: sp_staking::SessionIndex) {}
fn start_session(_: sp_staking::SessionIndex) {}
fn new_session(idx: sp_staking::SessionIndex) -> Option<Vec<u64>> {
if idx == 0 || idx == 1 {
Some(vec![1, 2])
} else if idx == 2 {
Some(vec![3, 4])
} else {
None
}
}
}

// Note, that we can't use `UintAuthorityId` here. Reason is that the implementation
// of `to_public_key()` assumes, that a public key is 32 bytes long. This is true for
// ed25519 and sr25519 but *not* for ecdsa. An ecdsa public key is 33 bytes.
pub fn mock_beefy_id(id: u8) -> BeefyId {
let buf: [u8; 33] = [id; 33];
let pk = Public::from_raw(buf);
BeefyId::from(pk)
}

pub fn mock_authorities(vec: Vec<u8>) -> Vec<(u64, BeefyId)> {
vec.into_iter().map(|id| ((id as u64), mock_beefy_id(id))).collect()
}

pub fn new_test_ext(ids: Vec<u8>) -> TestExternalities {
new_test_ext_raw_authorities(mock_authorities(ids))
}

pub fn new_test_ext_raw_authorities(authorities: Vec<(u64, BeefyId)>) -> TestExternalities {
let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();

let session_keys: Vec<_> = authorities
.iter()
.enumerate()
.map(|(_, id)| (id.0 as u64, id.0 as u64, MockSessionKeys { dummy: id.1.clone() }))
.collect();

BasicExternalities::execute_with_storage(&mut t, || {
for (ref id, ..) in &session_keys {
frame_system::Module::<Test>::inc_providers(id);
}
});

pallet_session::GenesisConfig::<Test> { keys: session_keys }
.assimilate_storage(&mut t)
.unwrap();

t.into()
}
103 changes: 103 additions & 0 deletions frame/beefy/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// Copyright (C) 2020 - 2021 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program 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.

// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.

use std::vec;

use codec::Encode;

use sp_core::H256;
use sp_runtime::DigestItem;

use frame_support::traits::OnInitialize;

use crate::mock::*;

fn init_block(block: u64) {
System::set_block_number(block);
Session::on_initialize(block);
}

pub fn beefy_log(log: ConsensusLog<BeefyId>) -> DigestItem<H256> {
DigestItem::Consensus(BEEFY_ENGINE_ID, log.encode())
}

#[test]
fn genesis_session_initializes_authorities() {
let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)];

new_test_ext(vec![1, 2, 3, 4]).execute_with(|| {
let authorities = Beefy::authorities();

assert!(authorities.len() == 2);
assert_eq!(want[0], authorities[0]);
assert_eq!(want[1], authorities[1]);

assert!(Beefy::validator_set_id() == 0);

let next_authorities = Beefy::next_authorities();

assert!(next_authorities.len() == 2);
assert_eq!(want[0], next_authorities[0]);
assert_eq!(want[1], next_authorities[1]);
});
}

#[test]
fn session_change_updates_authorities() {
new_test_ext(vec![1, 2, 3, 4]).execute_with(|| {
init_block(1);

assert!(0 == Beefy::validator_set_id());

// no change - no log
assert!(System::digest().logs.is_empty());

init_block(2);

assert!(1 == Beefy::validator_set_id());

let want = beefy_log(ConsensusLog::AuthoritiesChange(vec![
mock_beefy_id(3),
mock_beefy_id(4),
]));

let log = System::digest().logs[0].clone();

assert_eq!(want, log);
});
}
#[test]
fn session_change_updates_next_authorities() {
let want = vec![mock_beefy_id(1), mock_beefy_id(2), mock_beefy_id(3), mock_beefy_id(4)];

new_test_ext(vec![1, 2, 3, 4]).execute_with(|| {
init_block(1);

let next_authorities = Beefy::next_authorities();

assert!(next_authorities.len() == 2);
assert_eq!(want[0], next_authorities[0]);
assert_eq!(want[1], next_authorities[1]);

init_block(2);

let next_authorities = Beefy::next_authorities();

assert!(next_authorities.len() == 2);
assert_eq!(want[2], next_authorities[0]);
assert_eq!(want[3], next_authorities[1]);
});
}

0 comments on commit 85d81b2

Please sign in to comment.