// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// This file is part of Parity Bridges Common.
// Parity Bridges Common 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.
// Parity Bridges Common 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 Parity Bridges Common. If not, see .
use crate::finality::FinalityVotes;
use crate::validators::{ValidatorsConfiguration, ValidatorsSource};
use crate::{AuraConfiguration, GenesisConfig, HeaderToImport, HeadersByNumber, PruningStrategy, Storage, Trait};
use frame_support::StorageMap;
use frame_support::{impl_outer_origin, parameter_types, weights::Weight};
use parity_crypto::publickey::{sign, KeyPair, Secret};
use primitives::{rlp_encode, H520};
use primitives::{Address, Header, H256, U256};
use sp_runtime::{
testing::Header as SubstrateHeader,
traits::{BlakeTwo256, IdentityLookup},
Perbill,
};
pub type AccountId = u64;
#[derive(Clone, Eq, PartialEq, Debug)]
pub struct TestRuntime;
impl_outer_origin! {
pub enum Origin for TestRuntime where system = frame_system {}
}
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 TestRuntime {
type Origin = Origin;
type Index = u64;
type Call = ();
type BlockNumber = u64;
type Hash = H256;
type Hashing = BlakeTwo256;
type AccountId = AccountId;
type Lookup = IdentityLookup;
type Header = SubstrateHeader;
type Event = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type DbWeight = ();
type BlockExecutionWeight = ();
type ExtrinsicBaseWeight = ();
type MaximumExtrinsicWeight = ();
type AvailableBlockRatio = AvailableBlockRatio;
type MaximumBlockLength = MaximumBlockLength;
type Version = ();
type ModuleToIndex = ();
type AccountData = ();
type OnNewAccount = ();
type OnKilledAccount = ();
}
parameter_types! {
pub const TestFinalityVotesCachingInterval: Option = Some(16);
pub TestAuraConfiguration: AuraConfiguration = test_aura_config();
pub TestValidatorsConfiguration: ValidatorsConfiguration = test_validators_config();
}
impl Trait for TestRuntime {
type AuraConfiguration = TestAuraConfiguration;
type ValidatorsConfiguration = TestValidatorsConfiguration;
type FinalityVotesCachingInterval = TestFinalityVotesCachingInterval;
type PruningStrategy = KeepSomeHeadersBehindBest;
type OnHeadersSubmitted = ();
}
/// Step of genesis header.
pub const GENESIS_STEP: u64 = 42;
/// Aura configuration that is used in tests by default.
pub fn test_aura_config() -> AuraConfiguration {
AuraConfiguration {
empty_steps_transition: u64::max_value(),
strict_empty_steps_transition: 0,
validate_step_transition: 0x16e360,
validate_score_transition: 0x41a3c4,
two_thirds_majority_transition: u64::max_value(),
min_gas_limit: 0x1388.into(),
max_gas_limit: U256::max_value(),
maximum_extra_data_size: 0x20,
}
}
/// Validators configuration that is used in tests by default.
pub fn test_validators_config() -> ValidatorsConfiguration {
ValidatorsConfiguration::Single(ValidatorsSource::List(validators_addresses(3)))
}
/// Genesis header that is used in tests by default.
pub fn genesis() -> Header {
Header {
seal: vec![vec![GENESIS_STEP as _].into(), vec![].into()],
..Default::default()
}
}
/// Build default i-th block, using data from runtime storage.
pub fn block_i(number: u64, validators: &[KeyPair]) -> Header {
custom_block_i(number, validators, |_| {})
}
/// Build custom i-th block, using data from runtime storage.
pub fn custom_block_i(number: u64, validators: &[KeyPair], customize: impl FnOnce(&mut Header)) -> Header {
let validator_index: u8 = (number % (validators.len() as u64)) as _;
let mut header = Header {
number,
parent_hash: HeadersByNumber::get(number - 1).unwrap()[0].clone(),
gas_limit: 0x2000.into(),
author: validator(validator_index).address(),
seal: vec![vec![(number + GENESIS_STEP) as u8].into(), vec![].into()],
difficulty: number.into(),
..Default::default()
};
customize(&mut header);
signed_header(validators, header, number + GENESIS_STEP)
}
/// Build signed header from given header.
pub fn signed_header(validators: &[KeyPair], mut header: Header, step: u64) -> Header {
let message = header.seal_hash(false).unwrap();
let validator_index = (step % validators.len() as u64) as usize;
let signature = sign(validators[validator_index].secret(), &message.as_fixed_bytes().into()).unwrap();
let signature: [u8; 65] = signature.into();
let signature = H520::from(signature);
header.seal[1] = rlp_encode(&signature);
header
}
/// Return key pair of given test validator.
pub fn validator(index: u8) -> KeyPair {
KeyPair::from_secret(Secret::from([index + 1; 32])).unwrap()
}
/// Return key pairs of all test validators.
pub fn validators(count: u8) -> Vec {
(0..count).map(validator).collect()
}
/// Return addresses of all test validators.
pub fn validators_addresses(count: u8) -> Vec {
(0..count).map(|i| validator(i).address()).collect()
}
/// Prepare externalities to start with custom initial header.
pub fn custom_test_ext(initial_header: Header, initial_validators: Vec) -> sp_io::TestExternalities {
let t = GenesisConfig {
initial_header,
initial_difficulty: 0.into(),
initial_validators,
}
.build_storage::()
.unwrap();
sp_io::TestExternalities::new(t)
}
/// Insert header into storage.
pub fn insert_header(storage: &mut S, header: Header) {
storage.insert_header(HeaderToImport {
context: storage.import_context(None, &header.parent_hash).unwrap(),
is_best: true,
id: header.compute_id(),
header,
total_difficulty: 0.into(),
enacted_change: None,
scheduled_change: None,
finality_votes: FinalityVotes::default(),
});
}
/// Pruning strategy that keeps 10 headers behind best block.
pub struct KeepSomeHeadersBehindBest(pub u64);
impl Default for KeepSomeHeadersBehindBest {
fn default() -> KeepSomeHeadersBehindBest {
KeepSomeHeadersBehindBest(10)
}
}
impl PruningStrategy for KeepSomeHeadersBehindBest {
fn pruning_upper_bound(&mut self, best_number: u64, _: u64) -> u64 {
best_number.checked_sub(self.0).unwrap_or(0)
}
}