// Copyright 2017-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 .
//! Message types for the overseer and subsystems.
//!
//! These messages are intended to define the protocol by which different subsystems communicate with each
//! other and signals that they receive from an overseer to coordinate their work.
//! This is intended for use with the `polkadot-overseer` crate.
//!
//! Subsystems' APIs are defined separately from their implementation, leading to easier mocking.
use futures::channel::{mpsc, oneshot};
use thiserror::Error;
use polkadot_node_network_protocol::{
v1 as protocol_v1, NetworkBridgeEvent, ReputationChange, PeerId,
};
use polkadot_node_primitives::{
CollationGenerationConfig, MisbehaviorReport, SignedFullStatement, ValidationResult,
};
use polkadot_primitives::v1::{
AuthorityDiscoveryId, AvailableData, BackedCandidate, BlockNumber,
Header as BlockHeader, CandidateDescriptor, CandidateEvent, CandidateReceipt,
CollatorId, CommittedCandidateReceipt, CoreState, ErasureChunk,
GroupRotationInfo, Hash, Id as ParaId, OccupiedCoreAssumption,
PersistedValidationData, PoV, SessionIndex, SignedAvailabilityBitfield,
ValidationCode, ValidatorId, ValidationData,
ValidatorIndex, ValidatorSignature, InboundDownwardMessage,
};
use std::sync::Arc;
/// A notification of a new backed candidate.
#[derive(Debug)]
pub struct NewBackedCandidate(pub BackedCandidate);
/// Messages received by the Candidate Selection subsystem.
#[derive(Debug)]
pub enum CandidateSelectionMessage {
/// A candidate collation can be fetched from a collator and should be considered for seconding.
Collation(Hash, ParaId, CollatorId),
/// We recommended a particular candidate to be seconded, but it was invalid; penalize the collator.
/// The hash is the relay parent.
Invalid(Hash, CandidateReceipt),
}
impl CandidateSelectionMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::Collation(hash, ..) => Some(*hash),
Self::Invalid(hash, _) => Some(*hash),
}
}
}
impl Default for CandidateSelectionMessage {
fn default() -> Self {
CandidateSelectionMessage::Invalid(Default::default(), Default::default())
}
}
/// Messages received by the Candidate Backing subsystem.
#[derive(Debug)]
pub enum CandidateBackingMessage {
/// Requests a set of backable candidates that could be backed in a child of the given
/// relay-parent, referenced by its hash.
GetBackedCandidates(Hash, oneshot::Sender>),
/// Note that the Candidate Backing subsystem should second the given candidate in the context of the
/// given relay-parent (ref. by hash). This candidate must be validated.
Second(Hash, CandidateReceipt, PoV),
/// Note a validator's statement about a particular candidate. Disagreements about validity must be escalated
/// to a broader check by Misbehavior Arbitration. Agreements are simply tallied until a quorum is reached.
Statement(Hash, SignedFullStatement),
}
impl CandidateBackingMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::GetBackedCandidates(hash, _) => Some(*hash),
Self::Second(hash, _, _) => Some(*hash),
Self::Statement(hash, _) => Some(*hash),
}
}
}
/// Blanket error for validation failing for internal reasons.
#[derive(Debug, Error)]
#[error("Validation failed with {0:?}")]
pub struct ValidationFailed(pub String);
/// Messages received by the Validation subsystem.
///
/// ## Validation Requests
///
/// Validation requests made to the subsystem should return an error only on internal error.
/// Otherwise, they should return either `Ok(ValidationResult::Valid(_))`
/// or `Ok(ValidationResult::Invalid)`.
#[derive(Debug)]
pub enum CandidateValidationMessage {
/// Validate a candidate with provided parameters using relay-chain state.
///
/// This will implicitly attempt to gather the `PersistedValidationData` and `ValidationCode`
/// from the runtime API of the chain, based on the `relay_parent`
/// of the `CandidateDescriptor`.
///
/// This will also perform checking of validation outputs against the acceptance criteria.
///
/// If there is no state available which can provide this data or the core for
/// the para is not free at the relay-parent, an error is returned.
ValidateFromChainState(
CandidateDescriptor,
Arc,
oneshot::Sender>,
),
/// Validate a candidate with provided, exhaustive parameters for validation.
///
/// Explicitly provide the `PersistedValidationData` and `ValidationCode` so this can do full
/// validation without needing to access the state of the relay-chain.
///
/// This request doesn't involve acceptance criteria checking, therefore only useful for the
/// cases where the validity of the candidate is established. This is the case for the typical
/// use-case: secondary checkers would use this request relying on the full prior checks
/// performed by the relay-chain.
ValidateFromExhaustive(
PersistedValidationData,
ValidationCode,
CandidateDescriptor,
Arc,
oneshot::Sender>,
),
}
impl CandidateValidationMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::ValidateFromChainState(_, _, _) => None,
Self::ValidateFromExhaustive(_, _, _, _, _) => None,
}
}
}
/// Messages received by the Collator Protocol subsystem.
#[derive(Debug)]
pub enum CollatorProtocolMessage {
/// Signal to the collator protocol that it should connect to validators with the expectation
/// of collating on the given para. This is only expected to be called once, early on, if at all,
/// and only by the Collation Generation subsystem. As such, it will overwrite the value of
/// the previous signal.
///
/// This should be sent before any `DistributeCollation` message.
CollateOn(ParaId),
/// Provide a collation to distribute to validators.
DistributeCollation(CandidateReceipt, PoV),
/// Fetch a collation under the given relay-parent for the given ParaId.
FetchCollation(Hash, CollatorId, ParaId, oneshot::Sender<(CandidateReceipt, PoV)>),
/// Report a collator as having provided an invalid collation. This should lead to disconnect
/// and blacklist of the collator.
ReportCollator(CollatorId),
/// Note a collator as having provided a good collation.
NoteGoodCollation(CollatorId),
/// Get a network bridge update.
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
impl CollatorProtocolMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::CollateOn(_) => None,
Self::DistributeCollation(receipt, _) => Some(receipt.descriptor().relay_parent),
Self::FetchCollation(relay_parent, _, _, _) => Some(*relay_parent),
Self::ReportCollator(_) => None,
Self::NoteGoodCollation(_) => None,
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
/// Messages received by the network bridge subsystem.
#[derive(Debug)]
pub enum NetworkBridgeMessage {
/// Report a peer for their actions.
ReportPeer(PeerId, ReputationChange),
/// Send a message to one or more peers on the validation peer-set.
SendValidationMessage(Vec, protocol_v1::ValidationProtocol),
/// Send a message to one or more peers on the collation peer-set.
SendCollationMessage(Vec, protocol_v1::CollationProtocol),
/// Connect to peers who represent the given `validator_ids`.
///
/// Also ask the network to stay connected to these peers at least
/// until the request is revoked.
ConnectToValidators {
/// Ids of the validators to connect to.
validator_ids: Vec,
/// Response sender by which the issuer can learn the `PeerId`s of
/// the validators as they are connected.
/// The response is sent immediately for already connected peers.
connected: mpsc::Sender<(AuthorityDiscoveryId, PeerId)>,
/// By revoking the request the caller allows the network to
/// free some peer slots thus freeing the resources.
/// It doesn't necessarily lead to peers disconnection though.
/// The revokation is enacted on in the next connection request.
///
/// This can be done by sending to the channel or dropping the sender.
revoke: oneshot::Receiver<()>,
},
}
impl NetworkBridgeMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::ReportPeer(_, _) => None,
Self::SendValidationMessage(_, _) => None,
Self::SendCollationMessage(_, _) => None,
Self::ConnectToValidators { .. } => None,
}
}
}
/// Availability Distribution Message.
#[derive(Debug)]
pub enum AvailabilityDistributionMessage {
/// Event from the network bridge.
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
impl AvailabilityDistributionMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
/// Bitfield distribution message.
#[derive(Debug)]
pub enum BitfieldDistributionMessage {
/// Distribute a bitfield via gossip to other validators.
DistributeBitfield(Hash, SignedAvailabilityBitfield),
/// Event from the network bridge.
NetworkBridgeUpdateV1(NetworkBridgeEvent),
}
impl BitfieldDistributionMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
match self {
Self::DistributeBitfield(hash, _) => Some(*hash),
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
/// Bitfield signing message.
///
/// Currently non-instantiable.
#[derive(Debug)]
pub enum BitfieldSigningMessage {}
impl BitfieldSigningMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option {
None
}
}
/// Availability store subsystem message.
#[derive(Debug)]
pub enum AvailabilityStoreMessage {
/// Query a `AvailableData` from the AV store.
QueryAvailableData(Hash, oneshot::Sender