// 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 std::{collections::btree_map::BTreeMap, sync::Arc};
use futures::channel::{mpsc, oneshot};
use thiserror::Error;
pub use sc_network::IfDisconnected;
use polkadot_node_network_protocol::{
peer_set::PeerSet,
request_response::{request::IncomingRequest, v1 as req_res_v1, Requests},
v1 as protocol_v1, PeerId, UnifiedReputationChange,
};
use polkadot_node_primitives::{
approval::{BlockApprovalMeta, IndirectAssignmentCert, IndirectSignedApprovalVote},
AvailableData, BabeEpoch, CandidateVotes, CollationGenerationConfig, ErasureChunk, PoV,
SignedDisputeStatement, SignedFullStatement, ValidationResult,
};
use polkadot_primitives::v1::{
AuthorityDiscoveryId, BackedCandidate, BlockNumber, CandidateDescriptor, CandidateEvent,
CandidateHash, CandidateIndex, CandidateReceipt, CollatorId, CommittedCandidateReceipt,
CoreState, GroupIndex, GroupRotationInfo, Hash, Header as BlockHeader, Id as ParaId,
InboundDownwardMessage, InboundHrmpMessage, MultiDisputeStatementSet, OccupiedCoreAssumption,
PersistedValidationData, SessionIndex, SessionInfo, SignedAvailabilityBitfield,
SignedAvailabilityBitfields, ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ValidatorSignature,
};
use polkadot_procmacro_subsystem_dispatch_gen::subsystem_dispatch_gen;
use polkadot_statement_table::v1::Misbehavior;
/// Network events as transmitted to other subsystems, wrapped in their message types.
pub mod network_bridge_event;
pub use network_bridge_event::NetworkBridgeEvent;
/// Subsystem messages where each message is always bound to a relay parent.
pub trait BoundToRelayParent {
/// Returns the relay parent this message is bound to.
fn relay_parent(&self) -> Hash;
}
/// 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, Vec, 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 BoundToRelayParent for CandidateBackingMessage {
fn relay_parent(&self) -> Hash {
match self {
Self::GetBackedCandidates(hash, _, _) => *hash,
Self::Second(hash, _, _) => *hash,
Self::Statement(hash, _) => *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, derive_more::From)]
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 with an optional result sender.
///
/// The result sender should be informed when at least one parachain validator seconded the collation. It is also
/// completely okay to just drop the sender.
DistributeCollation(CandidateReceipt, PoV, Option>),
/// Report a collator as having provided an invalid collation. This should lead to disconnect
/// and blacklist of the collator.
ReportCollator(CollatorId),
/// Get a network bridge update.
#[from]
NetworkBridgeUpdateV1(NetworkBridgeEvent),
/// Incoming network request for a collation.
CollationFetchingRequest(IncomingRequest),
/// We recommended a particular candidate to be seconded, but it was invalid; penalize the collator.
///
/// The hash is the relay parent.
Invalid(Hash, CandidateReceipt),
/// The candidate we recommended to be seconded was validated successfully.
///
/// The hash is the relay parent.
Seconded(Hash, SignedFullStatement),
}
impl Default for CollatorProtocolMessage {
fn default() -> Self {
Self::CollateOn(Default::default())
}
}
impl BoundToRelayParent for CollatorProtocolMessage {
fn relay_parent(&self) -> Hash {
Default::default()
}
}
/// Messages received by the dispute coordinator subsystem.
#[derive(Debug)]
pub enum DisputeCoordinatorMessage {
/// Import a statement by a validator about a candidate.
///
/// The subsystem will silently discard ancient statements or sets of only dispute-specific statements for
/// candidates that are previously unknown to the subsystem. The former is simply because ancient
/// data is not relevant and the latter is as a DoS prevention mechanism. Both backing and approval
/// statements already undergo anti-DoS procedures in their respective subsystems, but statements
/// cast specifically for disputes are not necessarily relevant to any candidate the system is
/// already aware of and thus present a DoS vector. Our expectation is that nodes will notify each
/// other of disputes over the network by providing (at least) 2 conflicting statements, of which one is either
/// a backing or validation statement.
///
/// This does not do any checking of the message signature.
ImportStatements {
/// The hash of the candidate.
candidate_hash: CandidateHash,
/// The candidate receipt itself.
candidate_receipt: CandidateReceipt,
/// The session the candidate appears in.
session: SessionIndex,
/// Statements, with signatures checked, by validators participating in disputes.
///
/// The validator index passed alongside each statement should correspond to the index
/// of the validator in the set.
statements: Vec<(SignedDisputeStatement, ValidatorIndex)>,
},
/// Fetch a list of all active disputes that the coordinator is aware of.
ActiveDisputes(oneshot::Sender>),
/// Get candidate votes for a candidate.
QueryCandidateVotes(SessionIndex, CandidateHash, oneshot::Sender