// 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 .
#![cfg_attr(not(feature = "std"), no_std)]
// Runtime-generated enums
#![allow(clippy::large_enum_variant)]
use crate::finality::{CachedFinalityVotes, FinalityVotes};
use bp_eth_poa::{Address, Header, HeaderId, RawTransaction, RawTransactionReceipt, Receipt, H256, U256};
use codec::{Decode, Encode};
use frame_support::{decl_module, decl_storage, traits::Get};
use sp_runtime::{
transaction_validity::{
InvalidTransaction, TransactionLongevity, TransactionPriority, TransactionSource, TransactionValidity,
UnknownTransaction, ValidTransaction,
},
RuntimeDebug,
};
use sp_std::{cmp::Ord, collections::btree_map::BTreeMap, prelude::*};
pub use validators::{ValidatorsConfiguration, ValidatorsSource};
mod error;
mod finality;
mod import;
mod validators;
mod verification;
#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
#[cfg(test)]
mod mock;
#[cfg(any(feature = "runtime-benchmarks", test))]
pub mod test_utils;
/// Maximal number of blocks we're pruning in single import call.
const MAX_BLOCKS_TO_PRUNE_IN_SINGLE_IMPORT: u64 = 8;
/// Authority round engine configuration parameters.
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug)]
pub struct AuraConfiguration {
/// Empty step messages transition block.
pub empty_steps_transition: u64,
/// Transition block to strict empty steps validation.
pub strict_empty_steps_transition: u64,
/// Monotonic step validation transition block.
pub validate_step_transition: u64,
/// Chain score validation transition block.
pub validate_score_transition: u64,
/// First block for which a 2/3 quorum (instead of 1/2) is required.
pub two_thirds_majority_transition: u64,
/// Minimum gas limit.
pub min_gas_limit: U256,
/// Maximum gas limit.
pub max_gas_limit: U256,
/// Maximum size of extra data.
pub maximum_extra_data_size: u64,
}
/// Transaction pool configuration.
///
/// This is used to limit number of unsigned headers transactions in
/// the pool. We never use it to verify signed transactions.
pub struct PoolConfiguration {
/// Maximal difference between number of header from unsigned transaction
/// and current best block. This must be selected with caution - the more
/// is the difference, the more (potentially invalid) transactions could be
/// accepted to the pool and mined later (filling blocks with spam).
pub max_future_number_difference: u64,
}
/// Block header as it is stored in the runtime storage.
#[derive(Clone, Encode, Decode, PartialEq, RuntimeDebug)]
pub struct StoredHeader {
/// Submitter of this header. May be `None` if header has been submitted
/// using unsigned transaction.
pub submitter: Option,
/// The block header itself.
pub header: Header,
/// Total difficulty of the chain.
pub total_difficulty: U256,
/// The ID of set of validators that is expected to produce direct descendants of
/// this block. If header enacts new set, this would be the new set. Otherwise
/// this is the set that has produced the block itself.
/// The hash is the hash of block where validators set has been enacted.
pub next_validators_set_id: u64,
/// Hash of the last block which has **SCHEDULED** validators set change.
/// Note that signal doesn't mean that the set has been (or ever will be) enacted.
/// Note that the header may already be pruned.
pub last_signal_block: Option,
}
/// Validators set as it is stored in the runtime storage.
#[derive(Encode, Decode, PartialEq, RuntimeDebug)]
#[cfg_attr(test, derive(Clone))]
pub struct ValidatorsSet {
/// Validators of this set.
pub validators: Vec,
/// Hash of the block where this set has been signalled. None if this is the first set.
pub signal_block: Option,
/// Hash of the block where this set has been enacted.
pub enact_block: HeaderId,
}
/// Validators set change as it is stored in the runtime storage.
#[derive(Encode, Decode, PartialEq, RuntimeDebug)]
#[cfg_attr(test, derive(Clone))]
pub struct ScheduledChange {
/// Validators of this set.
pub validators: Vec,
/// Hash of the block which has emitted previous validators change signal.
pub prev_signal_block: Option,
}
/// Header that we're importing.
#[derive(RuntimeDebug)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub struct HeaderToImport {
/// Header import context,
pub context: ImportContext,
/// Should we consider this header as best?
pub is_best: bool,
/// The id of the header.
pub id: HeaderId,
/// The header itself.
pub header: Header,
/// Total chain difficulty at the header.
pub total_difficulty: U256,
/// New validators set and the hash of block where it has been scheduled (if applicable).
/// Some if set is is enacted by this header.
pub enacted_change: Option,
/// Validators set scheduled change, if happened at the header.
pub scheduled_change: Option>,
/// Finality votes at this header.
pub finality_votes: FinalityVotes,
}
/// Header that we're importing.
#[derive(RuntimeDebug)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub struct ChangeToEnact {
/// The id of the header where change has been scheduled.
/// None if it is a first set within current `ValidatorsSource`.
pub signal_block: Option,
/// Validators set that is enacted.
pub validators: Vec,
}
/// Blocks range that we want to prune.
#[derive(Encode, Decode, Default, RuntimeDebug, Clone, PartialEq)]
struct PruningRange {
/// Number of the oldest unpruned block(s). This might be the block that we do not
/// want to prune now (then it is equal to `oldest_block_to_keep`), or block that we
/// were unable to prune for whatever reason (i.e. if it isn't finalized yet and has
/// scheduled validators set change).
pub oldest_unpruned_block: u64,
/// Number of oldest block(s) that we want to keep. We want to prune blocks in range
/// [`oldest_unpruned_block`; `oldest_block_to_keep`).
pub oldest_block_to_keep: u64,
}
/// Header import context.
///
/// The import context contains information needed by the header verification
/// pipeline which is not directly part of the header being imported. This includes
/// information relating to its parent, and the current validator set (which
/// provide _context_ for the current header).
#[derive(RuntimeDebug)]
#[cfg_attr(test, derive(Clone, PartialEq))]
pub struct ImportContext {
submitter: Option,
parent_hash: H256,
parent_header: Header,
parent_total_difficulty: U256,
parent_scheduled_change: Option,
validators_set_id: u64,
validators_set: ValidatorsSet,
last_signal_block: Option,
}
impl ImportContext {
/// Returns reference to header submitter (if known).
pub fn submitter(&self) -> Option<&Submitter> {
self.submitter.as_ref()
}
/// Returns reference to parent header.
pub fn parent_header(&self) -> &Header {
&self.parent_header
}
/// Returns total chain difficulty at parent block.
pub fn total_difficulty(&self) -> &U256 {
&self.parent_total_difficulty
}
/// Returns the validator set change if the parent header has signaled a change.
pub fn parent_scheduled_change(&self) -> Option<&ScheduledChange> {
self.parent_scheduled_change.as_ref()
}
/// Returns id of the set of validators.
pub fn validators_set_id(&self) -> u64 {
self.validators_set_id
}
/// Returns reference to validators set for the block we're going to import.
pub fn validators_set(&self) -> &ValidatorsSet {
&self.validators_set
}
/// Returns reference to the latest block which has signalled change of validators set.
/// This may point to parent if parent has signalled change.
pub fn last_signal_block(&self) -> Option {
match self.parent_scheduled_change {
Some(_) => Some(HeaderId {
number: self.parent_header.number,
hash: self.parent_hash,
}),
None => self.last_signal_block,
}
}
/// Converts import context into header we're going to import.
#[allow(clippy::too_many_arguments)]
pub fn into_import_header(
self,
is_best: bool,
id: HeaderId,
header: Header,
total_difficulty: U256,
enacted_change: Option,
scheduled_change: Option>,
finality_votes: FinalityVotes,
) -> HeaderToImport {
HeaderToImport {
context: self,
is_best,
id,
header,
total_difficulty,
enacted_change,
scheduled_change,
finality_votes,
}
}
}
/// The storage that is used by the client.
///
/// Storage modification must be discarded if block import has failed.
pub trait Storage {
/// Header submitter identifier.
type Submitter: Clone + Ord;
/// Get best known block and total chain difficulty.
fn best_block(&self) -> (HeaderId, U256);
/// Get last finalized block.
fn finalized_block(&self) -> HeaderId;
/// Get imported header by its hash.
///
/// Returns header and its submitter (if known).
fn header(&self, hash: &H256) -> Option<(Header, Option)>;
/// Returns latest cached finality votes (if any) for block ancestors, starting
/// from `parent_hash` block and stopping at genesis block, best finalized block
/// or block where `stop_at` returns true.
fn cached_finality_votes(
&self,
parent: &HeaderId,
best_finalized: &HeaderId,
stop_at: impl Fn(&H256) -> bool,
) -> CachedFinalityVotes;
/// Get header import context by parent header hash.
fn import_context(
&self,
submitter: Option,
parent_hash: &H256,
) -> Option>;
/// Get new validators that are scheduled by given header and hash of the previous
/// block that has scheduled change.
fn scheduled_change(&self, hash: &H256) -> Option;
/// Insert imported header.
fn insert_header(&mut self, header: HeaderToImport);
/// Finalize given block and schedules pruning of all headers
/// with number < prune_end.
///
/// The headers in the pruning range could be either finalized, or not.
/// It is the storage duty to ensure that unfinalized headers that have
/// scheduled changes won't be pruned until they or their competitors
/// are finalized.
fn finalize_and_prune_headers(&mut self, finalized: Option, prune_end: u64);
}
/// Headers pruning strategy.
pub trait PruningStrategy: Default {
/// Return upper bound (exclusive) of headers pruning range.
///
/// Every value that is returned from this function, must be greater or equal to the
/// previous value. Otherwise it will be ignored (we can't revert pruning).
///
/// Module may prune both finalized and unfinalized blocks. But it can't give any
/// guarantees on when it will happen. Example: if some unfinalized block at height N
/// has scheduled validators set change, then the module won't prune any blocks with
/// number >= N even if strategy allows that.
///
/// If your strategy allows pruning unfinalized blocks, this could lead to switch
/// between finalized forks (only if authorities are misbehaving). But since 50%+1 (or 2/3)
/// authorities are able to do whatever they want with the chain, this isn't considered
/// fatal. If your strategy only prunes finalized blocks, we'll never be able to finalize
/// header that isn't descendant of current best finalized block.
fn pruning_upper_bound(&mut self, best_number: u64, best_finalized_number: u64) -> u64;
}
/// Callbacks for header submission rewards/penalties.
pub trait OnHeadersSubmitted {
/// Called when valid headers have been submitted.
///
/// The submitter **must not** be rewarded for submitting valid headers, because greedy authority
/// could produce and submit multiple valid headers (without relaying them to other peers) and
/// get rewarded. Instead, the provider could track submitters and stop rewarding if too many
/// headers have been submitted without finalization.
fn on_valid_headers_submitted(submitter: AccountId, useful: u64, useless: u64);
/// Called when invalid headers have been submitted.
fn on_invalid_headers_submitted(submitter: AccountId);
/// Called when earlier submitted headers have been finalized.
///
/// finalized is the number of headers that submitter has submitted and which
/// have been finalized.
fn on_valid_headers_finalized(submitter: AccountId, finalized: u64);
}
impl OnHeadersSubmitted for () {
fn on_valid_headers_submitted(_submitter: AccountId, _useful: u64, _useless: u64) {}
fn on_invalid_headers_submitted(_submitter: AccountId) {}
fn on_valid_headers_finalized(_submitter: AccountId, _finalized: u64) {}
}
/// The module configuration trait.
pub trait Trait: frame_system::Trait {
/// Aura configuration.
type AuraConfiguration: Get;
/// Validators configuration.
type ValidatorsConfiguration: Get;
/// Interval (in blocks) for for finality votes caching.
/// If None, cache is disabled.
///
/// Ideally, this should either be None (when we are sure that there won't
/// be any significant finalization delays), or something that is bit larger
/// than average finalization delay.
type FinalityVotesCachingInterval: Get