#![deny(unused_crate_dependencies)]
#![warn(missing_docs)]
use codec::{Decode, Encode};
use polkadot_primitives::{BlockNumber, Hash};
use std::fmt;
#[doc(hidden)]
pub use sc_network::IfDisconnected;
pub use sc_network_types::PeerId;
#[doc(hidden)]
pub use std::sync::Arc;
mod reputation;
pub use self::reputation::{ReputationChange, UnifiedReputationChange};
pub mod peer_set;
pub mod request_response;
pub mod authority_discovery;
pub mod grid_topology;
pub const MIN_GOSSIP_PEERS: usize = 25;
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct WrongVariant;
impl fmt::Display for WrongVariant {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "Wrong message variant")
}
}
impl std::error::Error for WrongVariant {}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ObservedRole {
Light,
Full,
Authority,
}
impl From<sc_network::ObservedRole> for ObservedRole {
fn from(role: sc_network::ObservedRole) -> ObservedRole {
match role {
sc_network::ObservedRole::Light => ObservedRole::Light,
sc_network::ObservedRole::Authority => ObservedRole::Authority,
sc_network::ObservedRole::Full => ObservedRole::Full,
}
}
}
impl Into<sc_network::ObservedRole> for ObservedRole {
fn into(self) -> sc_network::ObservedRole {
match self {
ObservedRole::Light => sc_network::ObservedRole::Light,
ObservedRole::Full => sc_network::ObservedRole::Full,
ObservedRole::Authority => sc_network::ObservedRole::Authority,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct OurView {
view: View,
}
impl OurView {
pub fn new(heads: impl IntoIterator<Item = Hash>, finalized_number: BlockNumber) -> Self {
let view = View::new(heads, finalized_number);
Self { view }
}
}
impl PartialEq for OurView {
fn eq(&self, other: &Self) -> bool {
self.view == other.view
}
}
impl std::ops::Deref for OurView {
type Target = View;
fn deref(&self) -> &View {
&self.view
}
}
#[macro_export]
macro_rules! our_view {
( $( $hash:expr ),* $(,)? ) => {
$crate::OurView::new(
vec![ $( $hash.clone() ),* ].into_iter().map(|h| h),
0,
)
};
}
#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
pub struct View {
heads: Vec<Hash>,
pub finalized_number: BlockNumber,
}
#[macro_export]
macro_rules! view {
( $( $hash:expr ),* $(,)? ) => {
$crate::View::new(vec![ $( $hash.clone() ),* ], 0)
};
}
impl View {
pub fn new(heads: impl IntoIterator<Item = Hash>, finalized_number: BlockNumber) -> Self {
let mut heads = heads.into_iter().collect::<Vec<Hash>>();
heads.sort();
Self { heads, finalized_number }
}
pub fn with_finalized(finalized_number: BlockNumber) -> Self {
Self { heads: Vec::new(), finalized_number }
}
pub fn len(&self) -> usize {
self.heads.len()
}
pub fn is_empty(&self) -> bool {
self.heads.is_empty()
}
pub fn iter(&self) -> impl Iterator<Item = &Hash> {
self.heads.iter()
}
pub fn into_iter(self) -> impl Iterator<Item = Hash> {
self.heads.into_iter()
}
pub fn replace_difference(&mut self, new: View) -> impl Iterator<Item = &Hash> {
let old = std::mem::replace(self, new);
self.heads.iter().filter(move |h| !old.contains(h))
}
pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.heads.iter().filter(move |h| !other.contains(h))
}
pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.heads.iter().filter(move |h| other.contains(h))
}
pub fn contains(&self, hash: &Hash) -> bool {
self.heads.contains(hash)
}
pub fn check_heads_eq(&self, other: &Self) -> bool {
self.heads == other.heads
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ValidationProtocols<V3> {
V3(V3),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CollationProtocols<V1, V2> {
V1(V1),
V2(V2),
}
impl<V3: Clone> ValidationProtocols<&'_ V3> {
pub fn clone_inner(&self) -> ValidationProtocols<V3> {
match *self {
ValidationProtocols::V3(inner) => ValidationProtocols::V3(inner.clone()),
}
}
}
impl<V1: Clone, V2: Clone> CollationProtocols<&'_ V1, &'_ V2> {
pub fn clone_inner(&self) -> CollationProtocols<V1, V2> {
match *self {
CollationProtocols::V1(inner) => CollationProtocols::V1(inner.clone()),
CollationProtocols::V2(inner) => CollationProtocols::V2(inner.clone()),
}
}
}
pub type VersionedValidationProtocol = ValidationProtocols<v3::ValidationProtocol>;
impl From<v3::ValidationProtocol> for VersionedValidationProtocol {
fn from(v3: v3::ValidationProtocol) -> Self {
VersionedValidationProtocol::V3(v3)
}
}
pub type VersionedCollationProtocol =
CollationProtocols<v1::CollationProtocol, v2::CollationProtocol>;
impl From<v1::CollationProtocol> for VersionedCollationProtocol {
fn from(v1: v1::CollationProtocol) -> Self {
VersionedCollationProtocol::V1(v1)
}
}
impl From<v2::CollationProtocol> for VersionedCollationProtocol {
fn from(v2: v2::CollationProtocol) -> Self {
VersionedCollationProtocol::V2(v2)
}
}
macro_rules! impl_versioned_validation_full_protocol_from {
($from:ty, $out:ty, $variant:ident) => {
impl From<$from> for $out {
fn from(versioned_from: $from) -> $out {
match versioned_from {
ValidationProtocols::V3(x) => ValidationProtocols::V3(x.into()),
}
}
}
};
}
macro_rules! impl_versioned_collation_full_protocol_from {
($from:ty, $out:ty, $variant:ident) => {
impl From<$from> for $out {
fn from(versioned_from: $from) -> $out {
match versioned_from {
CollationProtocols::V1(x) => CollationProtocols::V1(x.into()),
CollationProtocols::V2(x) => CollationProtocols::V2(x.into()),
}
}
}
};
}
macro_rules! impl_versioned_validation_try_from {
(
$from:ty,
$out:ty,
$v3_pat:pat => $v3_out:expr
) => {
impl TryFrom<$from> for $out {
type Error = crate::WrongVariant;
fn try_from(x: $from) -> Result<$out, Self::Error> {
#[allow(unreachable_patterns)] match x {
ValidationProtocols::V3($v3_pat) => Ok(ValidationProtocols::V3($v3_out)),
_ => Err(crate::WrongVariant),
}
}
}
impl<'a> TryFrom<&'a $from> for $out {
type Error = crate::WrongVariant;
fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
#[allow(unreachable_patterns)] match x {
ValidationProtocols::V3($v3_pat) =>
Ok(ValidationProtocols::V3($v3_out.clone())),
_ => Err(crate::WrongVariant),
}
}
}
};
}
macro_rules! impl_versioned_collation_try_from {
(
$from:ty,
$out:ty,
$v1_pat:pat => $v1_out:expr,
$v2_pat:pat => $v2_out:expr
) => {
impl TryFrom<$from> for $out {
type Error = crate::WrongVariant;
fn try_from(x: $from) -> Result<$out, Self::Error> {
#[allow(unreachable_patterns)] match x {
CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out)),
CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out)),
_ => Err(crate::WrongVariant),
}
}
}
impl<'a> TryFrom<&'a $from> for $out {
type Error = crate::WrongVariant;
fn try_from(x: &'a $from) -> Result<$out, Self::Error> {
#[allow(unreachable_patterns)] match x {
CollationProtocols::V1($v1_pat) => Ok(CollationProtocols::V1($v1_out.clone())),
CollationProtocols::V2($v2_pat) => Ok(CollationProtocols::V2($v2_out.clone())),
_ => Err(crate::WrongVariant),
}
}
}
};
}
pub type BitfieldDistributionMessage = ValidationProtocols<v3::BitfieldDistributionMessage>;
impl_versioned_validation_full_protocol_from!(
BitfieldDistributionMessage,
VersionedValidationProtocol,
BitfieldDistribution
);
impl_versioned_validation_try_from!(
VersionedValidationProtocol,
BitfieldDistributionMessage,
v3::ValidationProtocol::BitfieldDistribution(x) => x
);
pub type StatementDistributionMessage = ValidationProtocols<v3::StatementDistributionMessage>;
impl_versioned_validation_full_protocol_from!(
StatementDistributionMessage,
VersionedValidationProtocol,
StatementDistribution
);
impl_versioned_validation_try_from!(
VersionedValidationProtocol,
StatementDistributionMessage,
v3::ValidationProtocol::StatementDistribution(x) => x
);
pub type ApprovalDistributionMessage = ValidationProtocols<v3::ApprovalDistributionMessage>;
impl_versioned_validation_full_protocol_from!(
ApprovalDistributionMessage,
VersionedValidationProtocol,
ApprovalDistribution
);
impl_versioned_validation_try_from!(
VersionedValidationProtocol,
ApprovalDistributionMessage,
v3::ValidationProtocol::ApprovalDistribution(x) => x
);
pub type GossipSupportNetworkMessage = ValidationProtocols<v3::GossipSupportNetworkMessage>;
impl TryFrom<VersionedValidationProtocol> for GossipSupportNetworkMessage {
type Error = WrongVariant;
fn try_from(_: VersionedValidationProtocol) -> Result<Self, Self::Error> {
Err(WrongVariant)
}
}
impl<'a> TryFrom<&'a VersionedValidationProtocol> for GossipSupportNetworkMessage {
type Error = WrongVariant;
fn try_from(_: &'a VersionedValidationProtocol) -> Result<Self, Self::Error> {
Err(WrongVariant)
}
}
pub type CollatorProtocolMessage =
CollationProtocols<v1::CollatorProtocolMessage, v2::CollatorProtocolMessage>;
impl_versioned_collation_full_protocol_from!(
CollatorProtocolMessage,
VersionedCollationProtocol,
CollatorProtocol
);
impl_versioned_collation_try_from!(
VersionedCollationProtocol,
CollatorProtocolMessage,
v1::CollationProtocol::CollatorProtocol(x) => x,
v2::CollationProtocol::CollatorProtocol(x) => x
);
pub mod v1 {
use codec::{Decode, Encode};
use polkadot_primitives::{CollatorId, CollatorSignature, Hash, Id as ParaId};
use polkadot_node_primitives::UncheckedSignedFullStatement;
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum CollatorProtocolMessage {
#[codec(index = 0)]
Declare(CollatorId, ParaId, CollatorSignature),
#[codec(index = 1)]
AdvertiseCollation(Hash),
#[codec(index = 4)]
CollationSeconded(Hash, UncheckedSignedFullStatement),
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
pub enum CollationProtocol {
#[codec(index = 0)]
#[from]
CollatorProtocol(CollatorProtocolMessage),
}
pub fn declare_signature_payload(peer_id: &sc_network_types::PeerId) -> Vec<u8> {
let mut payload = peer_id.to_bytes();
payload.extend_from_slice(b"COLL");
payload
}
}
pub mod v2 {
use codec::{Decode, Encode};
use polkadot_primitives::{CandidateHash, CollatorId, CollatorSignature, Hash, Id as ParaId};
use polkadot_node_primitives::UncheckedSignedFullStatement;
pub use super::v1::declare_signature_payload;
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum CollatorProtocolMessage {
#[codec(index = 0)]
Declare(CollatorId, ParaId, CollatorSignature),
#[codec(index = 1)]
AdvertiseCollation {
relay_parent: Hash,
candidate_hash: CandidateHash,
parent_head_data_hash: Hash,
},
#[codec(index = 4)]
CollationSeconded(Hash, UncheckedSignedFullStatement),
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
pub enum CollationProtocol {
#[codec(index = 0)]
#[from]
CollatorProtocol(CollatorProtocolMessage),
}
}
pub mod v3 {
use bitvec::{order::Lsb0, slice::BitSlice, vec::BitVec};
use codec::{Decode, Encode};
use polkadot_primitives::{
CandidateHash, GroupIndex, Hash, Id as ParaId, UncheckedSignedAvailabilityBitfield,
UncheckedSignedStatement,
};
use polkadot_node_primitives::approval::v2::{
CandidateBitfield, IndirectAssignmentCertV2, IndirectSignedApprovalVoteV2,
};
pub use super::v2::declare_signature_payload;
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum BitfieldDistributionMessage {
#[codec(index = 0)]
Bitfield(Hash, UncheckedSignedAvailabilityBitfield),
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub struct StatementFilter {
pub seconded_in_group: BitVec<u8, Lsb0>,
pub validated_in_group: BitVec<u8, Lsb0>,
}
impl StatementFilter {
pub fn blank(group_size: usize) -> Self {
StatementFilter {
seconded_in_group: BitVec::repeat(false, group_size),
validated_in_group: BitVec::repeat(false, group_size),
}
}
pub fn full(group_size: usize) -> Self {
StatementFilter {
seconded_in_group: BitVec::repeat(true, group_size),
validated_in_group: BitVec::repeat(true, group_size),
}
}
pub fn has_len(&self, len: usize) -> bool {
self.seconded_in_group.len() == len && self.validated_in_group.len() == len
}
pub fn backing_validators(&self) -> usize {
self.seconded_in_group
.iter()
.by_vals()
.zip(self.validated_in_group.iter().by_vals())
.filter(|&(s, v)| s || v) .count()
}
pub fn has_seconded(&self) -> bool {
self.seconded_in_group.iter().by_vals().any(|x| x)
}
pub fn mask_seconded(&mut self, mask: &BitSlice<u8, Lsb0>) {
for (mut x, mask) in self
.seconded_in_group
.iter_mut()
.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
{
*x = *x && !mask;
}
}
pub fn mask_valid(&mut self, mask: &BitSlice<u8, Lsb0>) {
for (mut x, mask) in self
.validated_in_group
.iter_mut()
.zip(mask.iter().by_vals().chain(std::iter::repeat(false)))
{
*x = *x && !mask;
}
}
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub struct BackedCandidateManifest {
pub relay_parent: Hash,
pub candidate_hash: CandidateHash,
pub group_index: GroupIndex,
pub para_id: ParaId,
pub parent_head_data_hash: Hash,
pub statement_knowledge: StatementFilter,
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub struct BackedCandidateAcknowledgement {
pub candidate_hash: CandidateHash,
pub statement_knowledge: StatementFilter,
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum StatementDistributionMessage {
#[codec(index = 0)]
Statement(Hash, UncheckedSignedStatement),
#[codec(index = 1)]
BackedCandidateManifest(BackedCandidateManifest),
#[codec(index = 2)]
BackedCandidateKnown(BackedCandidateAcknowledgement),
}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq)]
pub enum ApprovalDistributionMessage {
#[codec(index = 0)]
Assignments(Vec<(IndirectAssignmentCertV2, CandidateBitfield)>),
#[codec(index = 1)]
Approvals(Vec<IndirectSignedApprovalVoteV2>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum GossipSupportNetworkMessage {}
#[derive(Debug, Clone, Encode, Decode, PartialEq, Eq, derive_more::From)]
pub enum ValidationProtocol {
#[codec(index = 1)]
#[from]
BitfieldDistribution(BitfieldDistributionMessage),
#[codec(index = 3)]
#[from]
StatementDistribution(StatementDistributionMessage),
#[codec(index = 4)]
#[from]
ApprovalDistribution(ApprovalDistributionMessage),
}
}
pub fn filter_by_peer_version(
peers: &[(PeerId, peer_set::ProtocolVersion)],
version: peer_set::ProtocolVersion,
) -> Vec<PeerId> {
peers.iter().filter(|(_, v)| v == &version).map(|(p, _)| *p).collect::<Vec<_>>()
}