Unverified Commit 9d874fa5 authored by asynchronous rob's avatar asynchronous rob Committed by GitHub
Browse files

Inclusion Module (#1242)

* add availability bitfield types to primitives

* begin inclusion module

* use GitHub issue link for limitation

* fix some compiler errors

* integrate validators into initializer

* add generic signing context

* make signing-context more generic

* fix issues with inclusion module

* add TODO

* guide: add validators and session index to inclusion

* guide: add session index to change notification

* implement session change logic

* add BackedCandidate type

* guide: refine inclusion pipeline

* guide: rename group_on to group_validators

* guide: add check about collator for parathread

* guide: add last_code_upgrade to paras and use in inclusion

* implement Paras::last_code_upgrade

* implement most checks in process_candidates

* make candidate receipt structs more generic

* make BackedCandidate struct more generic

* use hash param, not block number

* check that candidate is in context of the parent block

* include inclusion module in initializer

* implement enact-candidate

* check that only occupied cores have bits set

* finish implementing bitfield processing

* restructure consistency checks on candidates

* make some more primitives generic

* signature checking logic for backed candidates

* finish implementing process_candidates

* implement collect_pending

* add some trait implementations to primitives

* implement InclusionInherent and squash warnings

* test bitfield signing checks

* rename parachain head to para_head

* fix note_new_head bug in paras

* test bitfield enactment in inclusion

* helpers for candidate checks

* add test for most candidate checks

* add test for backing setting storage

* test session change logic

* remove extraneous type parameter

* remove some allow(unused)s

* extract threshold computation to const fn

* remove some more allow(unused)s

* improve doc

* add debug assertion

* fix primitive test compilation

* tag unanimous variant as unused
parent f92be014
Pipeline #97482 failed with stages
in 3 minutes and 23 seconds
......@@ -176,20 +176,20 @@ pub struct DutyRoster {
/// These are global parameters that apply to all parachain candidates in a block.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct GlobalValidationSchedule {
pub struct GlobalValidationSchedule<N = BlockNumber> {
/// The maximum code size permitted, in bytes.
pub max_code_size: u32,
/// The maximum head-data size permitted, in bytes.
pub max_head_data_size: u32,
/// The relay-chain block number this is in the context of.
pub block_number: BlockNumber,
pub block_number: N,
}
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
/// to fully validate the candidate. These fields are parachain-specific.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct LocalValidationData {
pub struct LocalValidationData<N = BlockNumber> {
/// The parent head-data.
pub parent_head: HeadData,
/// The balance of the parachain at the moment of validation.
......@@ -205,28 +205,28 @@ pub struct LocalValidationData {
/// height. This may be equal to the current perceived relay-chain block height, in
/// which case the code upgrade should be applied at the end of the signaling
/// block.
pub code_upgrade_allowed: Option<BlockNumber>,
pub code_upgrade_allowed: Option<N>,
}
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct CandidateCommitments {
pub struct CandidateCommitments<H = Hash> {
/// Fees paid from the chain to the relay chain validators.
pub fees: Balance,
/// Messages destined to be interpreted by the Relay chain itself.
pub upward_messages: Vec<UpwardMessage>,
/// The root of a block's erasure encoding Merkle tree.
pub erasure_root: Hash,
pub erasure_root: H,
/// New validation code.
pub new_validation_code: Option<ValidationCode>,
}
/// Get a collator signature payload on a relay-parent, block-data combo.
pub fn collator_signature_payload(
relay_parent: &Hash,
pub fn collator_signature_payload<H: AsRef<[u8]>>(
relay_parent: &H,
parachain_index: &Id,
pov_block_hash: &Hash,
pov_block_hash: &H,
) -> [u8; 68] {
// 32-byte hash length is protected in a test below.
let mut payload = [0u8; 68];
......@@ -238,10 +238,10 @@ pub fn collator_signature_payload(
payload
}
fn check_collator_signature(
relay_parent: &Hash,
fn check_collator_signature<H: AsRef<[u8]>>(
relay_parent: &H,
parachain_index: &Id,
pov_block_hash: &Hash,
pov_block_hash: &H,
collator: &CollatorId,
signature: &CollatorSignature,
) -> Result<(),()> {
......@@ -258,12 +258,12 @@ fn check_collator_signature(
/// All data pertaining to the execution of a parachain candidate.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct CandidateReceipt {
pub struct CandidateReceipt<H = Hash, N = BlockNumber> {
/// The ID of the parachain this is a candidate for.
pub parachain_index: Id,
/// The hash of the relay-chain block this should be executed in
/// the context of.
pub relay_parent: Hash,
pub relay_parent: H,
/// The head-data
pub head_data: HeadData,
/// The collator's relay-chain account ID
......@@ -271,16 +271,16 @@ pub struct CandidateReceipt {
/// Signature on blake2-256 of the block data by collator.
pub signature: CollatorSignature,
/// The hash of the PoV-block.
pub pov_block_hash: Hash,
pub pov_block_hash: H,
/// The global validation schedule.
pub global_validation: GlobalValidationSchedule,
pub global_validation: GlobalValidationSchedule<N>,
/// The local validation data.
pub local_validation: LocalValidationData,
pub local_validation: LocalValidationData<N>,
/// Commitments made as a result of validation.
pub commitments: CandidateCommitments,
pub commitments: CandidateCommitments<H>,
}
impl CandidateReceipt {
impl<H: AsRef<[u8]>, N> CandidateReceipt<H, N> {
/// Check integrity vs. provided block data.
pub fn check_signature(&self) -> Result<(), ()> {
check_collator_signature(
......@@ -294,7 +294,7 @@ impl CandidateReceipt {
/// Abridge this `CandidateReceipt`, splitting it into an `AbridgedCandidateReceipt`
/// and its omitted component.
pub fn abridge(self) -> (AbridgedCandidateReceipt, OmittedValidationData) {
pub fn abridge(self) -> (AbridgedCandidateReceipt<H>, OmittedValidationData<N>) {
let CandidateReceipt {
parachain_index,
relay_parent,
......@@ -345,11 +345,11 @@ impl Ord for CandidateReceipt {
/// is necessary for validation of the parachain candidate.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct OmittedValidationData {
pub struct OmittedValidationData<N = BlockNumber> {
/// The global validation schedule.
pub global_validation: GlobalValidationSchedule,
pub global_validation: GlobalValidationSchedule<N>,
/// The local validation data.
pub local_validation: LocalValidationData,
pub local_validation: LocalValidationData<N>,
}
/// An abridged candidate-receipt.
......@@ -359,14 +359,14 @@ pub struct OmittedValidationData {
/// be re-generated from relay-chain state.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct AbridgedCandidateReceipt {
pub struct AbridgedCandidateReceipt<H = Hash> {
/// The ID of the parachain this is a candidate for.
pub parachain_index: Id,
/// The hash of the relay-chain block this should be executed in
/// the context of.
// NOTE: the fact that the hash includes this value means that code depends
// on this for deduplication. Removing this field is likely to break things.
pub relay_parent: Hash,
pub relay_parent: H,
/// The head-data
pub head_data: HeadData,
/// The collator's relay-chain account ID
......@@ -374,12 +374,23 @@ pub struct AbridgedCandidateReceipt {
/// Signature on blake2-256 of the block data by collator.
pub signature: CollatorSignature,
/// The hash of the pov-block.
pub pov_block_hash: Hash,
pub pov_block_hash: H,
/// Commitments made as a result of validation.
pub commitments: CandidateCommitments,
pub commitments: CandidateCommitments<H>,
}
impl AbridgedCandidateReceipt {
impl<H: AsRef<[u8]> + Encode> AbridgedCandidateReceipt<H> {
/// Check integrity vs. provided block data.
pub fn check_signature(&self) -> Result<(), ()> {
check_collator_signature(
&self.relay_parent,
&self.parachain_index,
&self.pov_block_hash,
&self.collator,
&self.signature,
)
}
/// Compute the hash of the abridged candidate receipt.
///
/// This is often used as the canonical hash of the receipt, rather than
......@@ -391,7 +402,9 @@ impl AbridgedCandidateReceipt {
use runtime_primitives::traits::{BlakeTwo256, Hash};
BlakeTwo256::hash_of(self)
}
}
impl AbridgedCandidateReceipt {
/// Combine the abridged candidate receipt with the omitted data,
/// forming a full `CandidateReceipt`.
pub fn complete(self, omitted: OmittedValidationData) -> CandidateReceipt {
......@@ -616,13 +629,42 @@ pub enum ValidityAttestation {
Explicit(ValidatorSignature),
}
impl ValidityAttestation {
/// Get a reference to the signature.
pub fn signature(&self) -> &ValidatorSignature {
match *self {
ValidityAttestation::Implicit(ref sig) => sig,
ValidityAttestation::Explicit(ref sig) => sig,
}
}
/// Produce the underlying signed payload of the attestation, given the hash of the candidate,
/// which should be known in context.
pub fn signed_payload<H: Encode>(
&self,
candidate_hash: Hash,
signing_context: &SigningContext<H>,
) -> Vec<u8> {
match *self {
ValidityAttestation::Implicit(_) => (
Statement::Candidate(candidate_hash),
signing_context,
).encode(),
ValidityAttestation::Explicit(_) => (
Statement::Valid(candidate_hash),
signing_context,
).encode(),
}
}
}
/// A type returned by runtime with current session index and a parent hash.
#[derive(Clone, Eq, PartialEq, Default, Decode, Encode, RuntimeDebug)]
pub struct SigningContext {
pub struct SigningContext<H = Hash> {
/// Current session index.
pub session_index: sp_staking::SessionIndex,
/// Hash of the parent.
pub parent_hash: Hash,
pub parent_hash: H,
}
/// An attested candidate. This is submitted to the relay chain by a block author.
......@@ -683,9 +725,9 @@ impl From<BitVec<bitvec::order::Lsb0, u8>> for AvailabilityBitfield {
impl AvailabilityBitfield {
/// Encodes the signing payload into the given buffer.
pub fn encode_signing_payload_into(
pub fn encode_signing_payload_into<H: Encode>(
&self,
signing_context: &SigningContext,
signing_context: &SigningContext<H>,
buf: &mut Vec<u8>,
) {
self.0.encode_to(buf);
......@@ -693,10 +735,9 @@ impl AvailabilityBitfield {
}
/// Encodes the signing payload into a fresh byte-vector.
pub fn encode_signing_payload(
pub fn encode_signing_payload<H: Encode>(
&self,
signing_context:
&SigningContext,
signing_context: &SigningContext<H>,
) -> Vec<u8> {
let mut v = Vec::new();
self.encode_signing_payload_into(signing_context, &mut v);
......@@ -724,7 +765,7 @@ pub fn check_availability_bitfield_signature<H: Encode>(
bitfield: &AvailabilityBitfield,
validator: &ValidatorId,
signature: &ValidatorSignature,
signing_context: &SigningContext,
signing_context: &SigningContext<H>,
payload_encode_buf: Option<&mut Vec<u8>>,
) -> Result<(),()> {
use runtime_primitives::traits::AppVerify;
......@@ -750,15 +791,67 @@ pub struct SignedAvailabilityBitfields(pub Vec<SignedAvailabilityBitfield>);
// After https://github.com/paritytech/polkadot/issues/1250
// they should be unified to this type.
#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
pub struct BackedCandidate {
pub struct BackedCandidate<H = Hash> {
/// The candidate referred to.
pub candidate: AbridgedCandidateReceipt,
pub candidate: AbridgedCandidateReceipt<H>,
/// The validity votes themselves, expressed as signatures.
pub validity_votes: Vec<ValidityAttestation>,
/// The indices of the validators within the group, expressed as a bitfield.
pub validator_indices: BitVec<bitvec::order::Lsb0, u8>,
}
/// Verify the backing of the given candidate.
///
/// Provide a lookup from the index of a validator within the group assigned to this para,
/// as opposed to the index of the validator within the overall validator set, as well as
/// the number of validators in the group.
///
/// Also provide the signing context.
///
/// Returns either an error, indicating that one of the signatures was invalid or that the index
/// was out-of-bounds, or the number of signatures checked.
pub fn check_candidate_backing<H: AsRef<[u8]> + Encode>(
backed: &BackedCandidate<H>,
signing_context: &SigningContext<H>,
group_len: usize,
validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
) -> Result<usize, ()> {
use runtime_primitives::traits::AppVerify;
if backed.validator_indices.len() != group_len {
return Err(())
}
if backed.validity_votes.len() > group_len {
return Err(())
}
// this is known, even in runtime, to be blake2-256.
let hash: Hash = backed.candidate.hash();
let mut signed = 0;
for ((val_in_group_idx, _), attestation) in backed.validator_indices.iter().enumerate()
.filter(|(_, signed)| **signed)
.zip(backed.validity_votes.iter())
{
let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
let payload = attestation.signed_payload(hash.clone(), signing_context);
let sig = attestation.signature();
if sig.verify(&payload[..], &validator_id) {
signed += 1;
} else {
return Err(())
}
}
if signed != backed.validity_votes.len() {
return Err(())
}
Ok(signed)
}
sp_api::decl_runtime_apis! {
/// The API for querying the state of parachains on-chain.
#[api_version(3)]
......@@ -811,9 +904,9 @@ mod tests {
assert_eq!(h.as_ref().len(), 32);
let _payload = collator_signature_payload(
&[1; 32].into(),
&Hash::from([1; 32]),
&5u32.into(),
&[2; 32].into(),
&Hash::from([2; 32]),
);
}
}
......@@ -48,6 +48,8 @@ struct SessionChangeNotification {
new_config: HostConfiguration,
// A secure randomn seed for the session, gathered from BABE.
random_seed: [u8; 32],
// The session index of the beginning session.
session_index: SessionIndex,
}
```
......
......@@ -28,6 +28,12 @@ Storage Layout:
bitfields: map ValidatorIndex => AvailabilityBitfield;
/// Candidates pending availability.
PendingAvailability: map ParaId => CandidatePendingAvailability;
/// The current validators, by their parachain session keys.
Validators: Vec<ValidatorId>;
/// The current session index.
CurrentSessionIndex: SessionIndex;
```
> TODO: `CandidateReceipt` and `AbridgedCandidateReceipt` can contain code upgrades which make them very large. the code entries should be split into a different storage map with infrequent access patterns
......@@ -36,6 +42,8 @@ PendingAvailability: map ParaId => CandidatePendingAvailability;
1. Clear out all candidates pending availability.
1. Clear out all validator bitfields.
1. Update `Validators` with the validators from the session change notification.
1. Update `CurrentSessionIndex` with the session index from the session change notification.
## Routines
......@@ -50,11 +58,15 @@ All failed checks should lead to an unrecoverable error making the block invalid
1. For all now-available candidates, invoke the `enact_candidate` routine with the candidate and relay-parent number.
1. > TODO: pass it onwards to `Validity` module.
1. Return a list of freed cores consisting of the cores where candidates have become available.
* `process_candidates(BackedCandidates, scheduled: Vec<CoreAssignment>)`:
1. check that each candidate corresponds to a scheduled core and that they are ordered in ascending order by `ParaId`.
1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_frequency` of the currently scheduled upgrade, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID.
1. check the backing of the candidate using the signatures and the bitfields.
1. check that the upward messages are not exceeding `config.max_upward_queue_count` and `config.watermark_upward_queue_size` parameters.
* `process_candidates(BackedCandidates, scheduled: Vec<CoreAssignment>, group_validators: Fn(GroupIndex) -> Option<Vec<ValidatorIndex>>)`:
1. check that each candidate corresponds to a scheduled core and that they are ordered in the same order the cores appear in assignments in `scheduled`.
1. check that `scheduled` is sorted ascending by `CoreIndex`, without duplicates.
1. check that there is no candidate pending availability for any scheduled `ParaId`.
1. If the core assignment includes a specific collator, ensure the backed candidate is issued by that collator.
1. Ensure that any code upgrade scheduled by the candidate does not happen within `config.validation_upgrade_frequency` of `Paras::last_code_upgrade(para_id, true)`, if any, comparing against the value of `Paras::FutureCodeUpgrades` for the given para ID.
1. Check the collator's signature on the pov block.
1. check the backing of the candidate using the signatures and the bitfields, comparing against the validators assigned to the groups, fetched with the `group_validators` lookup.
1. check that the upward messages, when combined with the existing queue size, are not exceeding `config.max_upward_queue_count` and `config.watermark_upward_queue_size` parameters.
1. create an entry in the `PendingAvailability` map for each backed candidate with a blank `availability_votes` bitfield.
1. Return a `Vec<CoreIndex>` of all scheduled cores of the list of passed assignments that a candidate was successfully backed for, sorted ascending by CoreIndex.
* `enact_candidate(relay_parent_number: BlockNumber, AbridgedCandidateReceipt)`:
......
......@@ -16,9 +16,10 @@ Included: Option<()>,
## Entry Points
* `inclusion`: This entry-point accepts two parameters: [`Bitfields`](../types/availability.html#signed-availability-bitfield) and [`BackedCandidates`](../types/backing.html#backed-candidate).
1. The `Bitfields` are first forwarded to the `process_bitfields` routine, returning a set of freed cores. Provide a `Scheduler::core_para` as a core-lookup to the `process_bitfields` routine. Annotate each of these freed cores with `FreedReason::Concluded`.
* `inclusion`: This entry-point accepts two parameters: [`Bitfields`](../types/availability.html#signed-availability-bitfield) and [`BackedCandidates`](../type-definitions.html#backed-candidate).
1. The `Bitfields` are first forwarded to the `Inclusion::process_bitfields` routine, returning a set of freed cores. Provide a `Scheduler::core_para` as a core-lookup to the `process_bitfields` routine. Annotate each of these freed cores with `FreedReason::Concluded`.
1. If `Scheduler::availability_timeout_predicate` is `Some`, invoke `Inclusion::collect_pending` using it, and add timed-out cores to the free cores, annotated with `FreedReason::TimedOut`.
1. Invoke `Scheduler::schedule(freed)`
1. Call `Scheduler::occupied` for all scheduled cores where a backed candidate was submitted.
1. Invoke the `Inclusion::process_candidates` routine with the parameters `(backed_candidates, Scheduler::scheduled(), Scheduler::group_validators)`.
1. Call `Scheduler::occupied` using the return value of the `Inclusion::process_candidates` call above, first sorting the list of assigned core indices.
1. If all of the above succeeds, set `Included` to `Some(())`.
......@@ -111,6 +111,8 @@ OutgoingParas: Vec<ParaId>;
* `validation_code_at(ParaId, at: BlockNumber, assume_intermediate: Option<BlockNumber>)`: Fetches the validation code to be used when validating a block in the context of the given relay-chain height. A second block number parameter may be used to tell the lookup to proceed as if an intermediate parablock has been included at the given relay-chain height. This may return past, current, or (with certain choices of `assume_intermediate`) future code. `assume_intermediate`, if provided, must be before `at`. If the validation code has been pruned, this will return `None`.
* `is_parathread(ParaId) -> bool`: Returns true if the para ID references any live parathread.
* `last_code_upgrade(id: ParaId, include_future: bool) -> Option<BlockNumber>`: The block number of the last scheduled upgrade of the requested para. Includes future upgrades if the flag is set. This is the `expected_at` number, not the `activated_at` number.
## Finalization
No finalization routine runs for this module.
This diff is collapsed.
// Copyright 2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot 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.
// Polkadot 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 Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Provides glue code over the scheduler and inclusion modules, and accepting
//! one inherent per block that can include new para candidates and bitfields.
//!
//! Unlike other modules in this crate, it does not need to be initialized by the initializer,
//! as it has no initialization logic and its finalization logic depends only on the details of
//! this module.
use sp_std::prelude::*;
use primitives::{
parachain::{BackedCandidate, SignedAvailabilityBitfields},
};
use frame_support::{
decl_storage, decl_module, decl_error, ensure,
dispatch::DispatchResult,
weights::{DispatchClass, Weight},
traits::Get,
};
use system::ensure_none;
use crate::{inclusion, scheduler::{self, FreedReason}};
pub trait Trait: inclusion::Trait + scheduler::Trait { }
decl_storage! {
trait Store for Module<T: Trait> as ParaInclusionInherent {
/// Whether the inclusion inherent was included within this block.
///
/// The `Option<()>` is effectively a bool, but it never hits storage in the `None` variant
/// due to the guarantees of FRAME's storage APIs.
///
/// If this is `None` at the end of the block, we panic and render the block invalid.
Included: Option<()>;
}
}
decl_error! {
pub enum Error for Module<T: Trait> {
/// Inclusion inherent called more than once per block.
TooManyInclusionInherents,
}
}
decl_module! {
/// The inclusion inherent module.
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
type Error = Error<T>;
fn on_initialize() -> Weight {
T::DbWeight::get().reads_writes(1, 1) // in on_finalize.
}
fn on_finalize() {
if Included::take().is_none() {
panic!("Bitfields and heads must be included every block");
}
}
/// Include backed candidates and bitfields.
#[weight = (1_000_000_000, DispatchClass::Mandatory)]
pub fn inclusion(
origin,
signed_bitfields: SignedAvailabilityBitfields,
backed_candidates: Vec<BackedCandidate<T::Hash>>,
) -> DispatchResult {
ensure_none(origin)?;
ensure!(!<Included>::exists(), Error::<T>::TooManyInclusionInherents);
// Process new availability bitfields, yielding any availability cores whose
// work has now concluded.
let freed_concluded = <inclusion::Module<T>>::process_bitfields(
signed_bitfields,
<scheduler::Module<T>>::core_para,
)?;
// Handle timeouts for any availability core work.
let availability_pred = <scheduler::Module<T>>::availability_timeout_predicate();
let freed_timeout = if let Some(pred) = availability_pred {
<inclusion::Module<T>>::collect_pending(pred)
} else {
Vec::new()
};
// Schedule paras again, given freed cores, and reasons for freeing.
let freed = freed_concluded.into_iter().map(|c| (c, FreedReason::Concluded))
.chain(freed_timeout.into_iter().map(|c| (c, FreedReason::TimedOut)));
<scheduler::Module<T>>::schedule(freed.collect());
// Process backed candidates according to scheduled cores.
let occupied = <inclusion::Module<T>>::process_candidates(
backed_candidates,
<scheduler::Module<T>>::scheduled(),
<scheduler::Module<T>>::group_validators,
)?;
// Note which of the scheduled cores were actually occupied by a backed candidate.
<scheduler::Module<T>>::occupied(&occupied);
// And track that we've finished processing the inherent for this block.
Included::set(Some(()));
Ok(())
}
}
}
......@@ -27,7 +27,7 @@ use primitives::{
use frame_support::{
decl_storage, decl_module, decl_error, traits::Randomness,
};
use crate::{configuration::{self, HostConfiguration}, paras, scheduler};
use crate::{configuration::{self, HostConfiguration}, paras, scheduler, inclusion};
/// Information about a session change that has just occurred.
#[derive(Default, Clone)]
......@@ -42,9 +42,13 @@ pub struct SessionChangeNotification<BlockNumber> {
pub new_config: HostConfiguration<BlockNumber>,
/// A secure random seed for the session, gathered from BABE.
pub random_seed: [u8; 32],
/// New session index.
pub session_index: sp_staking::SessionIndex,
}
pub trait Trait: system::Trait + configuration::Trait + paras::Trait + scheduler::Trait {
pub trait Trait:
system::Trait + configuration::Trait + paras::Trait + scheduler::Trait + inclusion::Trait
{
/// A randomness beacon.
type Randomness: Randomness<Self::Hash>;
}
......@@ -81,7 +85,8 @@ decl_module! {
// - Validity
let total_weight = configuration::Module::<T>::initializer_initialize(now) +
paras::Module::<T>::initializer_initialize(now) +
scheduler::Module::<T>::initializer_initialize(now);
scheduler::Module::<T>::initializer_initialize(now) +
inclusion::Module::<T>::initializer_initialize(now);
HasInitialized::set(Some(()));
......@@ -91,6 +96,7 @@ decl_module! {
fn on_finalize() {
// reverse initialization order.
inclusion::Module::<T>::initializer_finalize();
scheduler::Module::<T>::initializer_finalize();
paras::Module::<T>::initializer_finalize();
configuration::Module::<T>::initializer_finalize();
......@@ -101,16 +107,25 @@ decl_module! {
impl<T: Trait> Module<T> {
/// Should be called when a new session occurs. Forwards the session notification to all
/// wrapped modules.
/// wrapped modules. If `queued` is `None`, the `validators` are considered queued.
///
/// Panics if the modules have already been initialized.
fn on_new_session<'a, I: 'a>(_changed: bool, validators: I, queued: I)
fn on_new_session<'a, I: 'a>(
_changed: bool,
session_index: sp_staking::SessionIndex,
validators: I,
queued: Option<I>,
)
where I: Iterator<Item=(&'a T::AccountId, ValidatorId)>
{
assert!(HasInitialized::get().is_none());
let validators: Vec<_> = validators.map(|(_, v)| v).collect();
let queued: Vec<_> = queued.map(|(_, v)| v).collect();
let queued: Vec<_> = if let Some(<