Newer
Older
// This file is part of Substrate.
// Copyright (C) 2018-2020 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Test utilities
#![cfg(test)]
use crate::{AuthorityId, AuthorityList, ConsensusLog, Module, Trait};
use ::grandpa as finality_grandpa;
use codec::Encode;
use frame_support::{
impl_outer_dispatch, impl_outer_event, impl_outer_origin, parameter_types,
traits::{KeyOwnerProofSystem, OnFinalize, OnInitialize},
weights::Weight,
};
use pallet_staking::EraIndex;
use sp_core::{crypto::KeyTypeId, H256};
use sp_finality_grandpa::{RoundNumber, SetId, GRANDPA_ENGINE_ID};
use sp_keyring::Ed25519Keyring;
use sp_runtime::{
curve::PiecewiseLinear,
impl_opaque_keys,
testing::{Header, TestXt, UintAuthorityId},
traits::{Convert, IdentityLookup, OpaqueKeys, SaturatedConversion},
DigestItem, Perbill,
};
use sp_staking::SessionIndex;
impl_outer_origin! {
pub enum Origin for Test {}
impl_outer_dispatch! {
pub enum Call for Test where origin: Origin {
pallet_grandpa::Grandpa,
pallet_staking::Staking,
impl_opaque_keys! {
pub struct TestSessionKeys {
pub grandpa_authority: super::Module<Test>,
}
}
impl_outer_event! {
pub enum TestEvent for Test {
frame_system<T>,
pallet_balances<T>,
pallet_grandpa,
pallet_offences,
pallet_session,
pallet_staking<T>,
#[derive(Clone, Eq, PartialEq)]
pub struct Test;
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: Weight = 1024;
pub const MaximumBlockLength: u32 = 2 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::one();
impl frame_system::Trait for Test {
type Origin = Origin;
type Index = u64;
type BlockNumber = u64;
type Hash = H256;
type Hashing = sp_runtime::traits::BlakeTwo256;
type AccountId = u64;
type Lookup = IdentityLookup<Self::AccountId>;
type Header = Header;
type Event = TestEvent;
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type BlockExecutionWeight = ();
type ExtrinsicBaseWeight = ();
type MaximumExtrinsicWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
type Version = ();
type AccountData = pallet_balances::AccountData<u128>;
type SystemWeightInfo = ();
impl<C> frame_system::offchain::SendTransactionTypes<C> for Test
where
Call: From<C>,
{
type OverarchingCall = Call;
type Extrinsic = TestXt<Call, ()>;
}
parameter_types! {
pub const Period: u64 = 1;
pub const Offset: u64 = 0;
pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
}
/// Custom `SessionHandler` since we use `TestSessionKeys` as `Keys`.
impl pallet_session::Trait for Test {
type Event = TestEvent;
type ValidatorId = u64;
type ValidatorIdOf = pallet_staking::StashOf<Self>;
type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
type SessionHandler = <TestSessionKeys as OpaqueKeys>::KeyTypeIdProviders;
type Keys = TestSessionKeys;
type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
type WeightInfo = ();
impl pallet_session::historical::Trait for Test {
type FullIdentification = pallet_staking::Exposure<u64, u128>;
type FullIdentificationOf = pallet_staking::ExposureOf<Self>;
parameter_types! {
pub const UncleGenerations: u64 = 0;
}
impl pallet_authorship::Trait for Test {
type FindAuthor = ();
type UncleGenerations = UncleGenerations;
type FilterUncle = ();
type EventHandler = ();
}
parameter_types! {
pub const ExistentialDeposit: u128 = 1;
}
impl pallet_balances::Trait for Test {
type MaxLocks = ();
type Balance = u128;
type DustRemoval = ();
type Event = TestEvent;
type ExistentialDeposit = ExistentialDeposit;
type AccountStore = System;
type WeightInfo = ();
}
parameter_types! {
pub const MinimumPeriod: u64 = 3;
}
impl pallet_timestamp::Trait for Test {
type Moment = u64;
type OnTimestampSet = ();
type MinimumPeriod = MinimumPeriod;
type WeightInfo = ();
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
}
pallet_staking_reward_curve::build! {
const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
min_inflation: 0_025_000u64,
max_inflation: 0_100_000,
ideal_stake: 0_500_000,
falloff: 0_050_000,
max_piece_count: 40,
test_precision: 0_005_000,
);
}
parameter_types! {
pub const SessionsPerEra: SessionIndex = 3;
pub const BondingDuration: EraIndex = 3;
pub const SlashDeferDuration: EraIndex = 0;
pub const AttestationPeriod: u64 = 100;
pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
pub const MaxNominatorRewardedPerValidator: u32 = 64;
pub const ElectionLookahead: u64 = 0;
pub const StakingUnsignedPriority: u64 = u64::max_value() / 2;
}
pub struct CurrencyToVoteHandler;
impl Convert<u128, u128> for CurrencyToVoteHandler {
fn convert(x: u128) -> u128 {
x
}
}
impl Convert<u128, u64> for CurrencyToVoteHandler {
fn convert(x: u128) -> u64 {
x.saturated_into()
}
}
impl pallet_staking::Trait for Test {
type RewardRemainder = ();
type CurrencyToVote = CurrencyToVoteHandler;
type Event = TestEvent;
type Currency = Balances;
type Slash = ();
type Reward = ();
type SessionsPerEra = SessionsPerEra;
type BondingDuration = BondingDuration;
type SlashDeferDuration = SlashDeferDuration;
type SlashCancelOrigin = frame_system::EnsureRoot<Self::AccountId>;
type UnixTime = pallet_timestamp::Module<Test>;
type RewardCurve = RewardCurve;
type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
type NextNewSession = Session;
type ElectionLookahead = ElectionLookahead;
type Call = Call;
type UnsignedPriority = StakingUnsignedPriority;
type MaxIterations = ();
Kian Paimani
committed
type MinSolutionScoreBump = ();
type WeightInfo = ();
pub OffencesWeightSoftLimit: Weight = Perbill::from_percent(60) * MaximumBlockWeight::get();
impl pallet_offences::Trait for Test {
type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
type WeightSoftLimit = OffencesWeightSoftLimit;
type WeightInfo = ();
}
impl Trait for Test {
type Event = TestEvent;
type Call = Call;
type KeyOwnerProofSystem = Historical;
type KeyOwnerProof =
<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, AuthorityId)>>::Proof;
type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
KeyTypeId,
AuthorityId,
)>>::IdentificationTuple;
type HandleEquivocation = super::EquivocationHandler<Self::KeyOwnerIdentification, Offences>;
pub type Balances = pallet_balances::Module<Test>;
pub type Historical = pallet_session::historical::Module<Test>;
pub type Offences = pallet_offences::Module<Test>;
pub type Session = pallet_session::Module<Test>;
pub type Staking = pallet_staking::Module<Test>;
pub type System = frame_system::Module<Test>;
pub type Timestamp = pallet_timestamp::Module<Test>;
pub type Grandpa = Module<Test>;
pub fn grandpa_log(log: ConsensusLog<u64>) -> DigestItem<H256> {
DigestItem::Consensus(GRANDPA_ENGINE_ID, log.encode())
pub fn to_authorities(vec: Vec<(u64, u64)>) -> AuthorityList {
vec.into_iter()
.map(|(id, weight)| (UintAuthorityId(id).to_public_key::<AuthorityId>(), weight))
.collect()
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
pub fn extract_keyring(id: &AuthorityId) -> Ed25519Keyring {
let mut raw_public = [0; 32];
raw_public.copy_from_slice(id.as_ref());
Ed25519Keyring::from_raw_public(raw_public).unwrap()
}
pub fn new_test_ext(vec: Vec<(u64, u64)>) -> sp_io::TestExternalities {
new_test_ext_raw_authorities(to_authorities(vec))
}
pub fn new_test_ext_raw_authorities(authorities: AuthorityList) -> sp_io::TestExternalities {
let mut t = frame_system::GenesisConfig::default()
.build_storage::<Test>()
.unwrap();
// stashes are the index.
let session_keys: Vec<_> = authorities
.iter()
.enumerate()
.map(|(i, (k, _))| {
(
i as u64,
i as u64,
TestSessionKeys {
grandpa_authority: AuthorityId::from(k.clone()),
},
)
})
.collect();
// controllers are the index + 1000
let stakers: Vec<_> = (0..authorities.len())
.map(|i| {
(
i as u64,
i as u64 + 1000,
10_000,
pallet_staking::StakerStatus::<u64>::Validator,
)
})
.collect();
let balances: Vec<_> = (0..authorities.len())
.map(|i| (i as u64, 10_000_000))
.collect();
// NOTE: this will initialize the grandpa authorities
// through OneSessionHandler::on_genesis_session
pallet_session::GenesisConfig::<Test> { keys: session_keys }
.assimilate_storage(&mut t)
.unwrap();
pallet_balances::GenesisConfig::<Test> { balances }
.assimilate_storage(&mut t)
.unwrap();
let staking_config = pallet_staking::GenesisConfig::<Test> {
force_era: pallet_staking::Forcing::ForceNew,
minimum_validator_count: 0,
invulnerables: vec![],
..Default::default()
};
staking_config.assimilate_storage(&mut t).unwrap();
t.into()
}
pub fn start_session(session_index: SessionIndex) {
for i in Session::current_index()..session_index {
System::on_finalize(System::block_number());
Session::on_finalize(System::block_number());
Staking::on_finalize(System::block_number());
Grandpa::on_finalize(System::block_number());
let parent_hash = if System::block_number() > 1 {
hdr.hash()
} else {
System::parent_hash()
};
System::initialize(
&(i as u64 + 1),
&parent_hash,
&Default::default(),
&Default::default(),
Default::default(),
);
System::set_block_number((i + 1).into());
Timestamp::set_timestamp(System::block_number() * 6000);
System::on_initialize(System::block_number());
Session::on_initialize(System::block_number());
Staking::on_initialize(System::block_number());
Grandpa::on_initialize(System::block_number());
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
}
assert_eq!(Session::current_index(), session_index);
}
pub fn start_era(era_index: EraIndex) {
start_session((era_index * 3).into());
assert_eq!(Staking::current_era(), Some(era_index));
}
pub fn initialize_block(number: u64, parent_hash: H256) {
System::initialize(
&number,
&parent_hash,
&Default::default(),
&Default::default(),
Default::default(),
);
}
pub fn generate_equivocation_proof(
set_id: SetId,
vote1: (RoundNumber, H256, u64, &Ed25519Keyring),
vote2: (RoundNumber, H256, u64, &Ed25519Keyring),
) -> sp_finality_grandpa::EquivocationProof<H256, u64> {
let signed_prevote = |round, hash, number, keyring: &Ed25519Keyring| {
let prevote = finality_grandpa::Prevote {
target_hash: hash,
target_number: number,
};
let prevote_msg = finality_grandpa::Message::Prevote(prevote.clone());
let payload = sp_finality_grandpa::localized_payload(round, set_id, &prevote_msg);
let signed = keyring.sign(&payload).into();
(prevote, signed)
};
let (prevote1, signed1) = signed_prevote(vote1.0, vote1.1, vote1.2, vote1.3);
let (prevote2, signed2) = signed_prevote(vote2.0, vote2.1, vote2.2, vote2.3);
sp_finality_grandpa::EquivocationProof::new(
set_id,
sp_finality_grandpa::Equivocation::Prevote(finality_grandpa::Equivocation {
round_number: vote1.0,
identity: vote1.3.public().into(),
first: (prevote1, signed1),
second: (prevote2, signed2),
}),
)
}