Unverified Commit 5d7142f1 authored by asynchronous rob's avatar asynchronous rob Committed by GitHub
Browse files

Implement Runtime APIs (#1411)

* create a README on Runtime APIs

* add ParaId type

* write up runtime APIs

* more preamble

* rename

* rejig runtime APIs

* add occupied_since to `BlockNumber`

* skeleton crate for runtime API subsystem

* improve group_for_core

* improve docs on availability cores runtime API

* guide: freed -> free

* add primitives for runtime APIs

* create a v1 ParachainHost API trait

* guide: make validation code return `Option`al.

* skeleton runtime API helpers

* make parachain-host runtime-generic

* skeleton for most runtime API implementation functions

* guide: add runtime API helper methods

* implement new helpers of the inclusion module

* guide: remove retries check, as it is unneeded

* implement helpers for scheduler module for Runtime APIs

* clean up `validator_groups` implementation

* implement next_rotation_at and last_rotation_at

* guide: more helpers on GroupRotationInfo

* almost finish implementing runtime APIs

* add explicit block parameter to runtime API fns

* guide: generalize number parameter

* guide: add group_responsible to occupied-core

* update primitives due to guide changes

* finishing touches on runtime API implementation; squash warnings

* break out runtime API impl to separate file

* add tests for next_up logic

* test group rotation info

* point to filed TODO

* remove unused TODO [now]

* indentation

* guide: para -> para_id

* rename para field to para_id for core meta

* remove reference to outdated AvailabilityCores type

* add an event in `inclusion` for candidates being included or timing out

* guide: candidate events

* guide: adjust language

* Candidate events type from guide and adjust inclusion event

* implement `candidate_events` runtime API

* fix runtime test compilation

* max -> min

* fix typos

* guide: add `RuntimeAPIRequest::CandidateEvents`
parent 220b87a6
Pipeline #100934 passed with stages
in 25 minutes and 29 seconds
......@@ -4633,6 +4633,7 @@ dependencies = [
"serde",
"sp-api",
"sp-application-crypto",
"sp-arithmetic",
"sp-core",
"sp-inherents",
"sp-runtime",
......@@ -4829,6 +4830,7 @@ dependencies = [
"sp-staking",
"sp-std",
"sp-trie",
"sp-version",
]
[[package]]
......
Stub - This folder will hold core subsystem implementations, each with their own crate.
This folder contains core subsystems, each with their own crate.
[package]
name = "polkadot-node-core-runtime-api"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
[dependencies]
futures = "0.3.5"
log = "0.4.8"
sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
primitives = { package = "sp-core", git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-primitives = { path = "../../../primitives" }
polkadot-node-primitives = { path = "../../primitives" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
[dev-dependencies]
futures = { version = "0.3.5", features = ["thread-pool"] }
subsystem-test = { package = "polkadot-subsystem-test-helpers", path = "../../test-helpers/subsystem" }
assert_matches = "1.3.0"
// 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/>.
//! Implements the Runtime API Subsystem
//!
//! This provides a clean, ownerless wrapper around the parachain-related runtime APIs. This crate
//! can also be used to cache responses from heavy runtime APIs.
//!
//! TODO: https://github.com/paritytech/polkadot/issues/1419 implement this.
......@@ -1386,7 +1386,6 @@ mod tests {
});
}
// TODO [now] awaiting peer sending us something is no longer awaiting.
#[test]
fn peer_completing_request_no_longer_awaiting() {
let hash_a: Hash = [0; 32].into();
......
......@@ -14,6 +14,7 @@ sp-api = { git = "https://github.com/paritytech/substrate", branch = "master", d
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-std = { package = "sp-std", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-arithmetic = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
runtime_primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
polkadot-parachain = { path = "../parachain", default-features = false }
polkadot-core-primitives = { path = "../core-primitives", default-features = false }
......@@ -37,6 +38,7 @@ std = [
"sp-std/std",
"sp-version/std",
"sp-staking/std",
"sp-arithmetic/std",
"runtime_primitives/std",
"serde",
"polkadot-parachain/std",
......
......@@ -23,6 +23,7 @@ use bitvec::vec::BitVec;
use primitives::RuntimeDebug;
use runtime_primitives::traits::AppVerify;
use inherents::InherentIdentifier;
use sp_arithmetic::traits::{BaseArithmetic, Saturating, Zero};
use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
......@@ -50,6 +51,8 @@ pub use crate::v0::{
#[cfg(feature = "std")]
pub use crate::v0::{ValidatorPair, CollatorPair};
pub use sp_staking::SessionIndex;
/// Unique identifier for the Inclusion Inherent
pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
......@@ -139,13 +142,13 @@ impl<H> CandidateReceipt<H> {
/// All data pertaining to the execution of a para candidate.
#[derive(PartialEq, Eq, Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(Debug, Default))]
pub struct FullCandidateReceipt<H = Hash> {
pub struct FullCandidateReceipt<H = Hash, N = BlockNumber> {
/// The inner candidate receipt.
pub inner: CandidateReceipt<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>,
}
/// A candidate-receipt with commitments directly included.
......@@ -202,7 +205,7 @@ impl Ord for CommittedCandidateReceipt {
/// 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.
......@@ -220,7 +223,7 @@ 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>,
}
/// Extra data that is needed along with the other fields in a `CandidateReceipt`
......@@ -229,13 +232,13 @@ pub struct LocalValidationData {
/// These are global parameters that apply to all 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,
}
/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
......@@ -476,3 +479,221 @@ pub struct AvailableData {
/// The omitted validation data.
pub omitted_validation: OmittedValidationData,
}
/// A helper data-type for tracking validator-group rotations.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub struct GroupRotationInfo<N = BlockNumber> {
/// The block number where the session started.
pub session_start_block: N,
/// How often groups rotate. 0 means never.
pub group_rotation_frequency: N,
/// The current block number.
pub now: N,
}
impl GroupRotationInfo {
/// Returns the index of the group needed to validate the core at the given index, assuming
/// the given number of cores.
///
/// `core_index` should be less than `cores`, which is capped at u32::max().
pub fn group_for_core(&self, core_index: CoreIndex, cores: usize) -> GroupIndex {
if self.group_rotation_frequency == 0 { return GroupIndex(core_index.0) }
if cores == 0 { return GroupIndex(0) }
let cores = sp_std::cmp::min(cores, u32::max_value() as usize);
let blocks_since_start = self.now.saturating_sub(self.session_start_block);
let rotations = blocks_since_start / self.group_rotation_frequency;
let idx = (core_index.0 as usize + rotations as usize) % cores;
GroupIndex(idx as u32)
}
}
impl<N: Saturating + BaseArithmetic + Copy> GroupRotationInfo<N> {
/// Returns the block number of the next rotation after the current block. If the current block
/// is 10 and the rotation frequency is 5, this should return 15.
///
/// If the group rotation frequency is 0, returns 0.
pub fn next_rotation_at(&self) -> N {
if self.group_rotation_frequency.is_zero() { return Zero::zero() }
let cycle_once = self.now + self.group_rotation_frequency;
cycle_once - (
cycle_once.saturating_sub(self.session_start_block) % self.group_rotation_frequency
)
}
/// Returns the block number of the last rotation before or including the current block. If the
/// current block is 10 and the rotation frequency is 5, this should return 10.
///
/// If the group rotation frequency is 0, returns 0.
pub fn last_rotation_at(&self) -> N {
if self.group_rotation_frequency.is_zero() { return Zero::zero() }
self.now - (
self.now.saturating_sub(self.session_start_block) % self.group_rotation_frequency
)
}
}
/// Information about a core which is currently occupied.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub struct OccupiedCore<N = BlockNumber> {
/// The ID of the para occupying the core.
pub para_id: Id,
/// If this core is freed by availability, this is the assignment that is next up on this
/// core, if any. None if there is nothing queued for this core.
pub next_up_on_available: Option<ScheduledCore>,
/// The relay-chain block number this began occupying the core at.
pub occupied_since: N,
/// The relay-chain block this will time-out at, if any.
pub time_out_at: N,
/// If this core is freed by being timed-out, this is the assignment that is next up on this
/// core. None if there is nothing queued for this core or there is no possibility of timing
/// out.
pub next_up_on_time_out: Option<ScheduledCore>,
/// A bitfield with 1 bit for each validator in the set. `1` bits mean that the corresponding
/// validators has attested to availability on-chain. A 2/3+ majority of `1` bits means that
/// this will be available.
pub availability: BitVec<bitvec::order::Lsb0, u8>,
/// The group assigned to distribute availability pieces of this candidate.
pub group_responsible: GroupIndex,
}
/// Information about a core which is currently occupied.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub struct ScheduledCore {
/// The ID of a para scheduled.
pub para_id: Id,
/// The collator required to author the block, if any.
pub collator: Option<CollatorId>,
}
/// The state of a particular availability core.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub enum CoreState<N = BlockNumber> {
/// The core is currently occupied.
#[codec(index = "0")]
Occupied(OccupiedCore<N>),
/// The core is currently free, with a para scheduled and given the opportunity
/// to occupy.
///
/// If a particular Collator is required to author this block, that is also present in this
/// variant.
#[codec(index = "1")]
Scheduled(ScheduledCore),
/// The core is currently free and there is nothing scheduled. This can be the case for parathread
/// cores when there are no parathread blocks queued. Parachain cores will never be left idle.
#[codec(index = "2")]
Free,
}
/// An assumption being made about the state of an occupied core.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub enum OccupiedCoreAssumption {
/// The candidate occupying the core was made available and included to free the core.
#[codec(index = "0")]
Included,
/// The candidate occupying the core timed out and freed the core without advancing the para.
#[codec(index = "1")]
TimedOut,
/// The core was not occupied to begin with.
#[codec(index = "2")]
Free,
}
/// An even concerning a candidate.
#[derive(Clone, Encode, Decode)]
#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
pub enum CandidateEvent<H = Hash> {
/// This candidate receipt was backed in the most recent block.
#[codec(index = "0")]
CandidateBacked(CandidateReceipt<H>, HeadData),
/// This candidate receipt was included and became a parablock at the most recent block.
#[codec(index = "1")]
CandidateIncluded(CandidateReceipt<H>, HeadData),
/// This candidate receipt was not made available in time and timed out.
#[codec(index = "2")]
CandidateTimedOut(CandidateReceipt<H>, HeadData),
}
sp_api::decl_runtime_apis! {
/// The API for querying the state of parachains on-chain.
pub trait ParachainHost<H: Decode, N: Decode> {
/// Get the current validators.
fn validators() -> Vec<ValidatorId>;
/// Returns the validator groups and rotation info localized based on the block whose state
/// this is invoked on. Note that `now` in the `GroupRotationInfo` should be the successor of
/// the number of the block.
fn validator_groups() -> (Vec<Vec<ValidatorIndex>>, GroupRotationInfo<N>);
/// Yields information on all availability cores. Cores are either free or occupied. Free
/// cores can have paras assigned to them.
fn availability_cores() -> Vec<CoreState<N>>;
/// Yields the GlobalValidationSchedule. This applies to all para candidates with the
/// relay-parent equal to the block in which context this is invoked in.
fn global_validation_schedule() -> GlobalValidationSchedule<N>;
/// Yields the LocalValidationData for the given ParaId along with an assumption that
/// should be used if the para currently occupies a core.
///
/// Returns `None` if either the para is not registered or the assumption is `Freed`
/// and the para already occupies a core.
fn local_validation_data(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<LocalValidationData<N>>;
/// Returns the session index expected at a child of the block.
///
/// This can be used to instantiate a `SigningContext`.
fn session_index_for_child() -> SessionIndex;
/// Fetch the validation code used by a para, making the given `OccupiedCoreAssumption`.
///
/// Returns `None` if either the para is not registered or the assumption is `Freed`
/// and the para already occupies a core.
fn validation_code(para_id: Id, assumption: OccupiedCoreAssumption)
-> Option<ValidationCode>;
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras
/// assigned to occupied cores in `availability_cores` and `None` otherwise.
fn candidate_pending_availability(para_id: Id) -> Option<CommittedCandidateReceipt<H>>;
/// Get a vector of events concerning candidates that occurred within a block.
// NOTE: this needs to skip block initialization as events are wiped within block
// initialization.
#[skip_initialize_block]
fn candidate_events() -> Vec<CandidateEvent<H>>;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn group_rotation_info_calculations() {
let info = GroupRotationInfo {
session_start_block: 10u32,
now: 15,
group_rotation_frequency: 5,
};
assert_eq!(info.next_rotation_at(), 20);
assert_eq!(info.last_rotation_at(), 15);
let info = GroupRotationInfo {
session_start_block: 10u32,
now: 11,
group_rotation_frequency: 0,
};
assert_eq!(info.next_rotation_at(), 0);
assert_eq!(info.last_rotation_at(), 0);
}
}
......@@ -59,7 +59,19 @@ struct GroupRotationInfo {
impl GroupRotationInfo {
/// Returns the index of the group needed to validate the core at the given index,
/// assuming the given amount of cores/groups.
fn group_for_core(core_index: usize, cores: usize) -> usize;
fn group_for_core(&self, core_index, cores) -> GroupIndex;
/// Returns the block number of the next rotation after the current block. If the current block
/// is 10 and the rotation frequency is 5, this should return 15.
///
/// If the group rotation frequency is 0, returns 0.
fn next_rotation_at(&self) -> BlockNumber;
/// Returns the block number of the last rotation before or including the current block. If the
/// current block is 10 and the rotation frequency is 5, this should return 10.
///
/// If the group rotation frequency is 0, returns 0.
fn last_rotation_at(&self) -> BlockNumber;
}
/// Returns the validator groups and rotation info localized based on the block whose state
......@@ -81,7 +93,7 @@ This is all the information that a validator needs about scheduling for the curr
```rust
struct OccupiedCore {
/// The ID of the para occupying the core.
para: ParaId,
para_id: ParaId,
/// If this core is freed by availability, this is the assignment that is next up on this
/// core, if any. None if there is nothing queued for this core.
next_up_on_available: Option<ScheduledCore>,
......@@ -97,11 +109,13 @@ struct OccupiedCore {
/// validators has attested to availability on-chain. A 2/3+ majority of `1` bits means that
/// this will be available.
availability: Bitfield,
/// The group assigned to distribute availability pieces of this candidate.
group_responsible: GroupIndex,
}
struct ScheduledCore {
/// The ID of a para scheduled.
para: ParaId,
para_id: ParaId,
/// The collator required to author the block, if any.
collator: Option<CollatorId>,
}
......@@ -171,7 +185,7 @@ fn session_index_for_child(at: Block) -> SessionIndex;
Fetch the validation code used by a para, making the given `OccupiedCoreAssumption`.
```rust
fn validation_code(at: Block, ParaId, OccupiedCoreAssumption) -> ValidationCode;
fn validation_code(at: Block, ParaId, OccupiedCoreAssumption) -> Option<ValidationCode>;
```
## Candidate Pending Availability
......@@ -181,3 +195,20 @@ Get the receipt of a candidate pending availability. This returns `Some` for any
```rust
fn candidate_pending_availability(at: Block, ParaId) -> Option<CommittedCandidateReceipt>;
```
## Candidate Events
Yields a vector of events concerning candidates that occurred within the given block.
```rust
enum CandidateEvent {
/// This candidate receipt was backed in the most recent block.
CandidateBacked(CandidateReceipt, HeadData),
/// This candidate receipt was included and became a parablock at the most recent block.
CandidateIncluded(CandidateReceipt, HeadData),
/// This candidate receipt was not made available in time and timed out.
CandidateTimedOut(CandidateReceipt, HeadData),
}
fn candidate_events(at: Block) -> Vec<CandidateEvent>;
```
......@@ -84,3 +84,6 @@ All failed checks should lead to an unrecoverable error making the block invalid
// return a vector of cleaned-up core IDs.
}
```
* `force_enact(ParaId)`: Forcibly enact the candidate with the given ID as though it had been deemed available by bitfields. Is a no-op if there is no candidate pending availability for this para-id. This should generally not be used but it is useful during execution of Runtime APIs, where the changes to the state are expected to be discarded directly after.
* `candidate_pending_availability(ParaId) -> Option<CommittedCandidateReceipt>`: returns the `CommittedCandidateReceipt` pending availability for the para provided, if any.
* `pending_availability(ParaId) -> Option<CandidatePendingAvailability>`: returns the metadata around the candidate pending availability for the para, if any.
......@@ -198,3 +198,6 @@ Actions:
- `core_para(CoreIndex) -> ParaId`: return the currently-scheduled or occupied ParaId for the given core.
- `group_validators(GroupIndex) -> Option<Vec<ValidatorIndex>>`: return all validators in a given group, if the group index is valid for this session.
- `availability_timeout_predicate() -> Option<impl Fn(CoreIndex, BlockNumber) -> bool>`: returns an optional predicate that should be used for timing out occupied cores. if `None`, no timing-out should be done. The predicate accepts the index of the core, and the block number since which it has been occupied. The predicate should be implemented based on the time since the last validator group rotation, and the respective parachain and parathread timeouts, i.e. only within `max(config.chain_availability_period, config.thread_availability_period)` of the last rotation would this return `Some`.
- `group_rotation_info() -> GroupRotationInfo`: Returns a helper for determining group rotation.
- `next_up_on_available(CoreIndex) -> Option<ScheduledCore>`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it became available. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that core, and is `None` if there isn't one.
- `next_up_on_time_out(CoreIndex) -> Option<ScheduledCore>`: Return the next thing that will be scheduled on this core assuming it is currently occupied and the candidate occupying it timed out. Returns in `ScheduledCore` format (todo: link to Runtime APIs page; linkcheck doesn't allow this right now). For parachains, this is always the ID of the parachain and no specified collator. For parathreads, this is based on the next item in the `ParathreadQueue` assigned to that core, or if there isn't one, the claim that is currently occupying the core. Otherwise `None`.
......@@ -252,9 +252,11 @@ enum RuntimeApiRequest {
ResponseChannel<Option<LocalValidationData>>,
),
/// Get information about all availability cores.
AvailabilityCores(ResponseChannel<AvailabilityCores>),
AvailabilityCores(ResponseChannel<Vec<CoreState>>),
/// Get a committed candidate receipt for all candidates pending availability.
CandidatePendingAvailability(ParaId, ResponseChannel<Option<CommittedCandidateReceipt>>),
/// Get all events concerning candidates in the last block.
CandidateEvents(ResponseChannel<Vec<CandidateEvent>>),
}
enum RuntimeApiMessage {
......
......@@ -49,6 +49,8 @@ pallet-staking-reward-curve = { git = "https://github.com/paritytech/substrate",
treasury = { package = "pallet-treasury", git = "https://github.com/paritytech/substrate", branch = "master" }
serde_json = "1.0.41"
libsecp256k1 = "0.3.2"
sp-version = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
[features]
default = ["std"]
......
......@@ -25,12 +25,11 @@ use primitives::v1::{
ValidatorId, CandidateCommitments, CandidateDescriptor, ValidatorIndex, Id as ParaId,
AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
BackedCandidate, CoreIndex, GroupIndex, CoreAssignment, CommittedCandidateReceipt,
CandidateReceipt, HeadData,
};
use frame_support::{
decl_storage, decl_module, decl_error, ensure, dispatch::DispatchResult, IterableStorageMap,
weights::Weight,
traits::Get,
debug,
decl_storage, decl_module, decl_error, decl_event, ensure, debug,
dispatch::DispatchResult, IterableStorageMap, weights::Weight, traits::Get,
};
use codec::{Encode, Decode};
use bitvec::{order::Lsb0 as BitOrderLsb0, vec::BitVec};
......@@ -69,7 +68,28 @@ pub struct CandidatePendingAvailability<H, N> {
backed_in_number: N,
}
pub trait Trait: system::Trait + paras::Trait + configuration::Trait { }
impl<H, N> CandidatePendingAvailability<H, N> {
/// Get the availability votes on the candidate.
pub(crate) fn availability_votes(&self) -> &BitVec<BitOrderLsb0, u8> {
&self.availability_votes
}
/// Get the relay-chain block number this was backed in.
pub(crate) fn backed_in_number(&self) -> &N {
&self.backed_in_number
}
/// Get the core index.
pub(crate) fn core_occupied(&self)-> CoreIndex {
self.core.clone()
}
}
pub trait Trait:
system::Trait + paras::Trait + configuration::Trait
{
type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
}
decl_storage! {
trait Store for Module<T: Trait> as ParaInclusion {
......@@ -89,7 +109,7 @@ decl_storage! {
Validators get(fn validators) config(validators): Vec<ValidatorId>;
/// The current session index.
CurrentSessionIndex: SessionIndex;
CurrentSessionIndex get(fn session_index): SessionIndex;
}
}
......@@ -130,10 +150,25 @@ decl_error! {
}
}
decl_event! {
pub enum Event<T> where <T as system::Trait>::Hash {
/// A candidate was backed.
CandidateBacked(CandidateReceipt<Hash>, HeadData),
/// A candidate was included.
CandidateIncluded(CandidateReceipt<Hash>, HeadData),
/// A candidate timed out.
CandidateTimedOut(CandidateReceipt<Hash>, HeadData),
}
}
decl_module! {
/// The parachain-candidate inclusion module.
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin, system = system {
pub struct Module<T: Trait>
for enum Call where origin: <T as system::Trait>::Origin, system = system
{
type Error = Error<T>;
fn deposit_event() = default;
}
}
......@@ -450,7 +485,17 @@ impl<T: Trait> Module<T> {
// initialize all availability votes to 0.
let availability_votes: BitVec<BitOrderLsb0, u8>
= bitvec::bitvec![BitOrderLsb0, u8; 0; validators.len()];
let (descriptor, commitments) = (candidate.candidate.descriptor, candidate.candidate.commitments);
Self::deposit_event(Event::<T>::CandidateBacked(
candidate.candidate.to_plain(),
candidate.candidate.commitments.head_data.clone(),
));
let (descriptor, commitments) = (
candidate.candidate.descriptor,
candidate.candidate.commitments,
);
<PendingAvailability<T>>::insert(&para_id, CandidatePendingAvailability {
core,
descriptor,
......@@ -468,6 +513,7 @@ impl<T: Trait> Module<T> {
relay_parent_number: T::BlockNumber,
receipt: CommittedCandidateReceipt<T::Hash>,
) -> Weight {
let plain = receipt.to_plain();
let commitments = receipt.commitments;
let config = <configuration::Module<T>>::config();
......@@ -481,6 +527,10 @@ impl<T: Trait> Module<T> {
);
}
Self::deposit_event(
Event::<T>::CandidateIncluded(plain, commitments.head_data.clone())
);
weight + <paras::Module<T>>::note_new_head(