Network bridge refactoring impl (#1537)

* update networking types

* port over overseer-protocol message types

* Add the collation protocol to network bridge

* message sending

* stub for ConnectToValidators

* add some helper traits and methods to protocol types

* add collator protocol message

* leaves-updating

* peer connection and disconnection

* add utilities for dispatching multiple events

* implement message handling

* add an observedrole enum with equality and no sentry nodes

* derive partial-eq on network bridge event

* add PartialEq impls for network message types

* add Into implementation for observedrole

* port over existing network bridge tests

* add some more tests

* port bitfield distribution

* port over bitfield distribution tests

* add codec indices

* port PoV distribution

* port over PoV distribution tests

* port over statement distribution

* port over statement distribution tests

* update overseer and service-new

* address review comments

* port availability distribution

* port over availability distribution tests
This commit is contained in:
Robert Habermeier
2020-08-12 13:16:28 +02:00
committed by GitHub
parent 8e60a5197f
commit a6b1d91d6e
21 changed files with 1557 additions and 815 deletions
+19 -7
View File
@@ -4423,8 +4423,8 @@ dependencies = [
"maplit",
"parity-scale-codec",
"parking_lot 0.11.0",
"polkadot-network",
"polkadot-network-bridge",
"polkadot-node-network-protocol",
"polkadot-node-primitives",
"polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers",
@@ -4450,19 +4450,16 @@ dependencies = [
"parity-scale-codec",
"parking_lot 0.11.0",
"polkadot-erasure-coding",
"polkadot-network",
"polkadot-network-bridge",
"polkadot-node-primitives",
"polkadot-node-network-protocol",
"polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers",
"polkadot-primitives",
"sc-keystore",
"sc-network",
"smallvec 1.4.1",
"smol-timeout",
"sp-core",
"sp-keyring",
"sp-staking",
"streamunordered",
]
@@ -4608,12 +4605,13 @@ dependencies = [
"log 0.4.11",
"parity-scale-codec",
"parking_lot 0.10.2",
"polkadot-node-primitives",
"polkadot-node-network-protocol",
"polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers",
"polkadot-primitives",
"sc-network",
"sp-core",
"sp-keyring",
"sp-runtime",
"streamunordered",
]
@@ -4786,6 +4784,18 @@ dependencies = [
"sp-core",
]
[[package]]
name = "polkadot-node-network-protocol"
version = "0.1.0"
dependencies = [
"parity-scale-codec",
"polkadot-node-primitives",
"polkadot-primitives",
"sc-network",
"sp-core",
"sp-runtime",
]
[[package]]
name = "polkadot-node-primitives"
version = "0.1.0"
@@ -4810,6 +4820,7 @@ dependencies = [
"parity-scale-codec",
"parking_lot 0.10.2",
"pin-project",
"polkadot-node-network-protocol",
"polkadot-node-primitives",
"polkadot-node-subsystem-test-helpers",
"polkadot-primitives",
@@ -4913,11 +4924,11 @@ dependencies = [
"log 0.4.11",
"parity-scale-codec",
"parking_lot 0.10.2",
"polkadot-node-network-protocol",
"polkadot-node-primitives",
"polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers",
"polkadot-primitives",
"sc-network",
"sp-core",
"sp-runtime",
"streamunordered",
@@ -5271,6 +5282,7 @@ dependencies = [
"log 0.4.11",
"parity-scale-codec",
"parking_lot 0.10.2",
"polkadot-node-network-protocol",
"polkadot-node-primitives",
"polkadot-node-subsystem",
"polkadot-node-subsystem-test-helpers",
+1
View File
@@ -55,6 +55,7 @@ members = [
"node/core/runtime-api",
"node/network/bridge",
"node/network/pov-distribution",
"node/network/protocol",
"node/network/statement-distribution",
"node/network/bitfield-distribution",
"node/network/availability-distribution",
@@ -9,16 +9,13 @@ futures = "0.3.5"
log = "0.4.11"
streamunordered = "0.5.1"
codec = { package="parity-scale-codec", version = "1.3.4", features = ["std"] }
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
polkadot-primitives = { path = "../../../primitives" }
polkadot-erasure-coding = { path = "../../../erasure-coding" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-network-bridge = { path = "../../network/bridge" }
polkadot-network = { path = "../../../network" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-node-network-protocol = { path = "../../network/protocol" }
sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
derive_more = "0.99.9"
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master", features = ["std"] }
[dev-dependencies]
@@ -31,4 +28,4 @@ futures-timer = "3.0.2"
smol-timeout = "0.1.0"
env_logger = "0.7.1"
assert_matches = "1.3.0"
smallvec = "1"
smallvec = "1"
@@ -32,24 +32,27 @@ use sp_core::{
};
use sc_keystore as keystore;
use node_primitives::{ProtocolId, View};
use log::{trace, warn};
use polkadot_erasure_coding::branch_hash;
use polkadot_primitives::v1::{
PARACHAIN_KEY_TYPE_ID,
BlakeTwo256, CommittedCandidateReceipt, CoreState, ErasureChunk,
Hash as Hash, HashT, Id as ParaId,
ValidatorId, ValidatorIndex,
ValidatorId, ValidatorIndex, SessionIndex,
};
use polkadot_subsystem::messages::{
AllMessages, AvailabilityDistributionMessage, NetworkBridgeMessage, RuntimeApiMessage,
RuntimeApiRequest, AvailabilityStoreMessage, ChainApiMessage,
};
use polkadot_subsystem::messages::*;
use polkadot_subsystem::{
errors::{ChainApiError, RuntimeApiError},
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem,
SubsystemContext, SubsystemError,
};
use sc_network::ReputationChange as Rep;
use sp_staking::SessionIndex;
use polkadot_node_network_protocol::{
v1 as protocol_v1, View, ReputationChange as Rep, PeerId,
NetworkBridgeEvent,
};
use std::collections::{HashMap, HashSet};
use std::io;
use std::iter;
@@ -76,7 +79,6 @@ type Result<T> = std::result::Result<T, Error>;
const COST_MERKLE_PROOF_INVALID: Rep = Rep::new(-100, "Merkle proof was invalid");
const COST_NOT_A_LIVE_CANDIDATE: Rep = Rep::new(-51, "Candidate is not live");
const COST_MESSAGE_NOT_DECODABLE: Rep = Rep::new(-100, "Message is not decodable");
const COST_PEER_DUPLICATE_MESSAGE: Rep = Rep::new(-500, "Peer sent identical messages");
const BENEFIT_VALID_MESSAGE_FIRST: Rep = Rep::new(15, "Valid message with new information");
const BENEFIT_VALID_MESSAGE: Rep = Rep::new(10, "Valid message");
@@ -284,17 +286,13 @@ impl ProtocolState {
}
}
fn network_update_message(n: NetworkBridgeEvent) -> AllMessages {
AllMessages::AvailabilityDistribution(AvailabilityDistributionMessage::NetworkBridgeUpdate(n))
}
/// Deal with network bridge updates and track what needs to be tracked
/// which depends on the message type received.
async fn handle_network_msg<Context>(
ctx: &mut Context,
keystore: KeyStorePtr,
state: &mut ProtocolState,
bridge_message: NetworkBridgeEvent,
bridge_message: NetworkBridgeEvent<protocol_v1::AvailabilityDistributionMessage>,
) -> Result<()>
where
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
@@ -314,19 +312,13 @@ where
NetworkBridgeEvent::OurViewChange(view) => {
handle_our_view_change(ctx, keystore, state, view).await?;
}
NetworkBridgeEvent::PeerMessage(remote, bytes) => {
if let Ok(gossiped_availability) =
AvailabilityGossipMessage::decode(&mut (bytes.as_slice()))
{
trace!(
target: TARGET,
"Received availability gossip from peer {:?}",
&remote
);
process_incoming_peer_message(ctx, state, remote, gossiped_availability).await?;
} else {
modify_reputation(ctx, remote, COST_MESSAGE_NOT_DECODABLE).await?;
}
NetworkBridgeEvent::PeerMessage(remote, msg) => {
let gossiped_availability = match msg {
protocol_v1::AvailabilityDistributionMessage::Chunk(candidate_hash, chunk) =>
AvailabilityGossipMessage { candidate_hash, erasure_chunk: chunk }
};
process_incoming_peer_message(ctx, state, remote, gossiped_availability).await?;
}
}
Ok(())
@@ -494,16 +486,19 @@ where
.insert(message_id);
}
let encoded = message.encode();
per_candidate
.message_vault
.insert(message.erasure_chunk.index, message);
.insert(message.erasure_chunk.index, message.clone());
let wire_message = protocol_v1::AvailabilityDistributionMessage::Chunk(
message.candidate_hash,
message.erasure_chunk,
);
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(
NetworkBridgeMessage::SendValidationMessage(
peers.clone(),
AvailabilityDistributionSubsystem::PROTOCOL_ID,
encoded,
protocol_v1::ValidationProtocol::AvailabilityDistribution(wire_message),
),
))
.await
@@ -709,9 +704,6 @@ pub struct AvailabilityDistributionSubsystem {
}
impl AvailabilityDistributionSubsystem {
/// The protocol identifier for bitfield distribution.
const PROTOCOL_ID: ProtocolId = *b"avad";
/// Number of ancestors to keep around for the relay-chain heads.
const K: usize = 3;
@@ -725,20 +717,13 @@ impl AvailabilityDistributionSubsystem {
where
Context: SubsystemContext<Message = AvailabilityDistributionMessage>,
{
// startup: register the network protocol with the bridge.
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::RegisterEventProducer(Self::PROTOCOL_ID, network_update_message),
))
.await
.map_err::<Error, _>(Into::into)?;
// work: process incoming messages from the overseer.
let mut state = ProtocolState::default();
loop {
let message = ctx.recv().await.map_err::<Error, _>(Into::into)?;
match message {
FromOverseer::Communication {
msg: AvailabilityDistributionMessage::NetworkBridgeUpdate(event),
msg: AvailabilityDistributionMessage::NetworkBridgeUpdateV1(event),
} => {
if let Err(e) = handle_network_msg(
&mut ctx,
@@ -1,3 +1,19 @@
// 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/>.
use super::*;
use assert_matches::assert_matches;
use polkadot_erasure_coding::{branches, obtain_chunks_v1 as obtain_chunks};
@@ -7,6 +23,7 @@ use polkadot_primitives::v1::{
OmittedValidationData, PoV, ScheduledCore, ValidatorPair,
};
use polkadot_subsystem_testhelpers as test_helpers;
use polkadot_node_network_protocol::ObservedRole;
use futures::{executor, future, Future};
use futures_timer::Delay;
@@ -26,6 +43,15 @@ macro_rules! delay {
};
}
fn chunk_protocol_message(message: AvailabilityGossipMessage)
-> protocol_v1::AvailabilityDistributionMessage
{
protocol_v1::AvailabilityDistributionMessage::Chunk(
message.candidate_hash,
message.erasure_chunk,
)
}
struct TestHarness {
virtual_overseer: test_helpers::TestSubsystemContextHandle<AvailabilityDistributionMessage>,
}
@@ -437,12 +463,9 @@ fn reputation_verification() {
)
.await;
// ignore event producer registration
let _ = overseer_recv(&mut virtual_overseer).await;
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::OurViewChange(view![current,]),
),
)
@@ -668,7 +691,7 @@ fn reputation_verification() {
// setup peer a with interest in current
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerConnected(peer_a.clone(), ObservedRole::Full),
),
)
@@ -676,7 +699,7 @@ fn reputation_verification() {
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![current]),
),
)
@@ -685,7 +708,7 @@ fn reputation_verification() {
// setup peer b with interest in ancestor
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerConnected(peer_b.clone(), ObservedRole::Full),
),
)
@@ -693,7 +716,7 @@ fn reputation_verification() {
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerViewChange(peer_b.clone(), view![ancestors[0]]),
),
)
@@ -701,35 +724,6 @@ fn reputation_verification() {
delay!(100);
/////////////////////////////////////////////////////////
// ready for action
// check if garbage messages are detected and peer rep is changed as expected
let garbage = b"I am garbage";
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
// AvailabilityDistributionSubsystem::PROTOCOL_ID,
garbage.to_vec(),
)),
)
.await;
assert_matches!(
overseer_recv(&mut virtual_overseer).await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::ReportPeer(
peer,
rep
)
) => {
assert_eq!(peer, peer_b);
assert_eq!(rep, COST_MESSAGE_NOT_DECODABLE);
}
);
let valid: AvailabilityGossipMessage = make_valid_availability_gossip(
&test_state,
candidates[0].hash(),
@@ -741,8 +735,11 @@ fn reputation_verification() {
// valid (first, from b)
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
NetworkBridgeEvent::PeerMessage(peer_b.clone(), valid.encode()),
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
chunk_protocol_message(valid.clone()),
),
),
)
.await;
@@ -765,8 +762,11 @@ fn reputation_verification() {
// valid (duplicate, from b)
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
NetworkBridgeEvent::PeerMessage(peer_b.clone(), valid.encode()),
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
chunk_protocol_message(valid.clone()),
),
),
)
.await;
@@ -789,8 +789,11 @@ fn reputation_verification() {
// valid (second, from a)
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
NetworkBridgeEvent::PeerMessage(peer_a.clone(), valid.encode()),
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
chunk_protocol_message(valid.clone()),
),
),
)
.await;
@@ -812,7 +815,7 @@ fn reputation_verification() {
// peer a is not interested in anything anymore
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![]),
),
)
@@ -822,8 +825,11 @@ fn reputation_verification() {
// send the a message again, so we should detect the duplicate
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
NetworkBridgeEvent::PeerMessage(peer_a.clone(), valid.encode()),
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
chunk_protocol_message(valid.clone()),
),
),
)
.await;
@@ -846,7 +852,7 @@ fn reputation_verification() {
// setup peer a with interest in parent x
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerDisconnected(peer_b.clone()),
),
)
@@ -856,7 +862,7 @@ fn reputation_verification() {
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerConnected(peer_b.clone(), ObservedRole::Full),
),
)
@@ -874,8 +880,11 @@ fn reputation_verification() {
// send the a message before we send a view update
overseer_send(
&mut virtual_overseer,
AvailabilityDistributionMessage::NetworkBridgeUpdate(
NetworkBridgeEvent::PeerMessage(peer_a.clone(), valid2.encode()),
AvailabilityDistributionMessage::NetworkBridgeUpdateV1(
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
chunk_protocol_message(valid2),
),
),
)
.await;
@@ -14,7 +14,7 @@ node-primitives = { package = "polkadot-node-primitives", path = "../../primitiv
polkadot-primitives = { path = "../../../primitives" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-network-bridge = { path = "../../network/bridge" }
polkadot-network = { path = "../../../network" }
polkadot-node-network-protocol = { path = "../../network/protocol" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
[dev-dependencies]
@@ -23,15 +23,13 @@
use codec::{Decode, Encode};
use futures::{channel::oneshot, FutureExt};
use node_primitives::{ProtocolId, View};
use log::{trace, warn};
use polkadot_subsystem::messages::*;
use polkadot_subsystem::{
ActiveLeavesUpdate, FromOverseer, OverseerSignal, SpawnedSubsystem, Subsystem, SubsystemContext, SubsystemResult,
};
use polkadot_primitives::v1::{Hash, SignedAvailabilityBitfield, SigningContext, ValidatorId};
use sc_network::ReputationChange;
use polkadot_node_network_protocol::{v1 as protocol_v1, PeerId, NetworkBridgeEvent, View, ReputationChange};
use std::collections::{HashMap, HashSet};
const COST_SIGNATURE_INVALID: ReputationChange =
@@ -42,8 +40,6 @@ const COST_MISSING_PEER_SESSION_KEY: ReputationChange =
ReputationChange::new(-133, "Missing peer session key");
const COST_NOT_IN_VIEW: ReputationChange =
ReputationChange::new(-51, "Not interested in that parent hash");
const COST_MESSAGE_NOT_DECODABLE: ReputationChange =
ReputationChange::new(-100, "Not interested in that parent hash");
const COST_PEER_DUPLICATE_MESSAGE: ReputationChange =
ReputationChange::new(-500, "Peer sent the same message multiple times");
const BENEFIT_VALID_MESSAGE_FIRST: ReputationChange =
@@ -54,11 +50,28 @@ const BENEFIT_VALID_MESSAGE: ReputationChange =
/// Checked signed availability bitfield that is distributed
/// to other peers.
#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq)]
pub struct BitfieldGossipMessage {
struct BitfieldGossipMessage {
/// The relay parent this message is relative to.
pub relay_parent: Hash,
relay_parent: Hash,
/// The actual signed availability bitfield.
pub signed_availability: SignedAvailabilityBitfield,
signed_availability: SignedAvailabilityBitfield,
}
impl BitfieldGossipMessage {
fn into_validation_protocol(self) -> protocol_v1::ValidationProtocol {
protocol_v1::ValidationProtocol::BitfieldDistribution(
self.into_network_message()
)
}
fn into_network_message(self)
-> protocol_v1::BitfieldDistributionMessage
{
protocol_v1::BitfieldDistributionMessage::Bitfield(
self.relay_parent,
self.signed_availability,
)
}
}
/// Data used to track information of peers and relay parents the
@@ -114,28 +127,15 @@ impl PerRelayParentData {
}
}
fn network_update_message(n: NetworkBridgeEvent) -> AllMessages {
AllMessages::BitfieldDistribution(BitfieldDistributionMessage::NetworkBridgeUpdate(n))
}
/// The bitfield distribution subsystem.
pub struct BitfieldDistribution;
impl BitfieldDistribution {
/// The protocol identifier for bitfield distribution.
const PROTOCOL_ID: ProtocolId = *b"bitd";
/// Start processing work as passed on from the Overseer.
async fn run<Context>(mut ctx: Context) -> SubsystemResult<()>
where
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
{
// startup: register the network protocol with the bridge.
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::RegisterEventProducer(Self::PROTOCOL_ID, network_update_message),
))
.await?;
// work: process incoming messages from the overseer and process accordingly.
let mut state = ProtocolState::default();
loop {
@@ -149,7 +149,7 @@ impl BitfieldDistribution {
.await?;
}
FromOverseer::Communication {
msg: BitfieldDistributionMessage::NetworkBridgeUpdate(event),
msg: BitfieldDistributionMessage::NetworkBridgeUpdateV1(event),
} => {
trace!(target: "bitd", "Processing NetworkMessage");
// a network message was received
@@ -314,10 +314,9 @@ where
);
} else {
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(
NetworkBridgeMessage::SendValidationMessage(
interested_peers,
BitfieldDistribution::PROTOCOL_ID,
message.encode(),
message.into_validation_protocol(),
),
))
.await?;
@@ -413,7 +412,7 @@ where
async fn handle_network_msg<Context>(
ctx: &mut Context,
state: &mut ProtocolState,
bridge_message: NetworkBridgeEvent,
bridge_message: NetworkBridgeEvent<protocol_v1::BitfieldDistributionMessage>,
) -> SubsystemResult<()>
where
Context: SubsystemContext<Message = BitfieldDistributionMessage>,
@@ -433,12 +432,16 @@ where
NetworkBridgeEvent::OurViewChange(view) => {
handle_our_view_change(state, view)?;
}
NetworkBridgeEvent::PeerMessage(remote, bytes) => {
if let Ok(gossiped_bitfield) = BitfieldGossipMessage::decode(&mut (bytes.as_slice())) {
trace!(target: "bitd", "Received bitfield gossip from peer {:?}", &remote);
process_incoming_peer_message(ctx, state, remote, gossiped_bitfield).await?;
} else {
modify_reputation(ctx, remote, COST_MESSAGE_NOT_DECODABLE).await?;
NetworkBridgeEvent::PeerMessage(remote, message) => {
match message {
protocol_v1::BitfieldDistributionMessage::Bitfield(relay_parent, bitfield) => {
trace!(target: "bitd", "Received bitfield gossip from peer {:?}", &remote);
let gossiped_bitfield = BitfieldGossipMessage {
relay_parent,
signed_availability: bitfield,
};
process_incoming_peer_message(ctx, state, remote, gossiped_bitfield).await?;
}
}
}
}
@@ -541,10 +544,9 @@ where
.insert(validator.clone());
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(
NetworkBridgeMessage::SendValidationMessage(
vec![dest],
BitfieldDistribution::PROTOCOL_ID,
message.encode(),
message.into_validation_protocol(),
),
))
.await?;
@@ -612,6 +614,7 @@ mod test {
use sp_core::crypto::Pair;
use std::time::Duration;
use assert_matches::assert_matches;
use polkadot_node_network_protocol::ObservedRole;
macro_rules! view {
( $( $hash:expr ),* $(,)? ) => [
@@ -742,7 +745,7 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.into_network_message()),
));
// reputation change due to invalid validator index
@@ -795,7 +798,7 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.into_network_message()),
));
// reputation change due to invalid validator index
@@ -848,7 +851,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
msg.clone().into_network_message(),
),
));
// none of our peers has any interest in any messages
@@ -878,7 +884,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_a.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
msg.clone().into_network_message(),
),
));
assert_matches!(
@@ -895,7 +904,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
msg.clone().into_network_message(),
),
));
assert_matches!(
@@ -909,6 +921,7 @@ mod test {
);
});
}
#[test]
fn changing_view() {
let _ = env_logger::builder()
@@ -960,7 +973,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
msg.clone().into_network_message(),
),
));
// gossip to the overseer
@@ -977,12 +993,11 @@ mod test {
// gossip to the network
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage (
peers, proto, bytes
AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage (
peers, out_msg,
)) => {
assert_eq!(peers, peers![peer_b]);
assert_eq!(proto, BitfieldDistribution::PROTOCOL_ID);
assert_eq!(bytes, msg.encode());
assert_eq!(out_msg, msg.clone().into_validation_protocol());
}
);
@@ -1014,7 +1029,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_b.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
msg.clone().into_network_message(),
),
));
// reputation change for peer B
@@ -1042,7 +1060,10 @@ mod test {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_a.clone(), msg.encode()),
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
msg.clone().into_network_message(),
),
));
// reputation change for peer B
@@ -1058,59 +1079,4 @@ mod test {
});
}
#[test]
fn invalid_peer_message() {
let _ = env_logger::builder()
.filter(None, log::LevelFilter::Trace)
.is_test(true)
.try_init();
let hash_a: Hash = [0; 32].into();
let peer_a = PeerId::random();
// validator 0 key pair
let (mut state, _signing_context, _validator_pair) = state_with_view(view![], hash_a.clone());
let pool = sp_core::testing::TaskExecutor::new();
let (mut ctx, mut handle) =
make_subsystem_context::<BitfieldDistributionMessage, _>(pool);
executor::block_on(async move {
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerConnected(peer_a.clone(), ObservedRole::Full),
));
// make peer b interested
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerViewChange(peer_a.clone(), view![hash_a]),
));
assert!(state.peer_views.contains_key(&peer_a));
// recv a first message from the network
launch!(handle_network_msg(
&mut ctx,
&mut state,
NetworkBridgeEvent::PeerMessage(peer_a.clone(), b"00AaBbCcDdEeFf".to_vec()),
));
// reputation change for peer A
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::ReportPeer(peer, rep)
) => {
assert_eq!(peer, peer_a);
assert_eq!(rep, COST_MESSAGE_NOT_DECODABLE);
}
);
});
}
}
+2 -1
View File
@@ -10,14 +10,15 @@ log = "0.4.8"
futures-timer = "3.0.2"
streamunordered = "0.5.1"
polkadot-primitives = { path = "../../../primitives" }
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
parity-scale-codec = "1.3.4"
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-network-protocol = { path = "../protocol" }
[dev-dependencies]
assert_matches = "1.3.0"
parking_lot = "0.10.0"
polkadot-node-subsystem-test-helpers = { path = "../../subsystem-test-helpers" }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/substrate", branch = "master" }
File diff suppressed because it is too large Load Diff
@@ -12,9 +12,9 @@ streamunordered = "0.5.1"
polkadot-primitives = { path = "../../../primitives" }
node-primitives = { package = "polkadot-node-primitives", path = "../../primitives" }
parity-scale-codec = "1.3.4"
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-network-protocol = { path = "../../network/protocol" }
[dev-dependencies]
parking_lot = "0.10.0"
@@ -24,21 +24,20 @@ use polkadot_subsystem::{
ActiveLeavesUpdate, OverseerSignal, SubsystemContext, Subsystem, SubsystemResult, FromOverseer, SpawnedSubsystem,
};
use polkadot_subsystem::messages::{
PoVDistributionMessage, NetworkBridgeEvent, ReputationChange as Rep, PeerId,
RuntimeApiMessage, RuntimeApiRequest, AllMessages, NetworkBridgeMessage,
PoVDistributionMessage, RuntimeApiMessage, RuntimeApiRequest, AllMessages, NetworkBridgeMessage,
};
use polkadot_node_network_protocol::{
v1 as protocol_v1, ReputationChange as Rep, NetworkBridgeEvent, PeerId, View,
};
use node_primitives::{View, ProtocolId};
use futures::prelude::*;
use futures::channel::oneshot;
use parity_scale_codec::{Encode, Decode};
use std::collections::{hash_map::{Entry, HashMap}, HashSet};
use std::sync::Arc;
const COST_APPARENT_FLOOD: Rep = Rep::new(-500, "Peer appears to be flooding us with PoV requests");
const COST_UNEXPECTED_POV: Rep = Rep::new(-500, "Peer sent us an unexpected PoV");
const COST_MALFORMED_MESSAGE: Rep = Rep::new(-500, "Peer sent us a malformed message");
const COST_AWAITED_NOT_IN_VIEW: Rep
= Rep::new(-100, "Peer claims to be awaiting something outside of its view");
@@ -46,20 +45,6 @@ const BENEFIT_FRESH_POV: Rep = Rep::new(25, "Peer supplied us with an awaited Po
const BENEFIT_LATE_POV: Rep = Rep::new(10, "Peer supplied us with an awaited PoV, \
but was not the first to do so");
const PROTOCOL_V1: ProtocolId = *b"pvd1";
#[derive(Encode, Decode)]
enum WireMessage {
/// Notification that we are awaiting the given PoVs (by hash) against a
/// specific relay-parent hash.
#[codec(index = "0")]
Awaiting(Hash, Vec<Hash>),
/// Notification of an awaited PoV, in a given relay-parent context.
/// (relay_parent, pov_hash, pov)
#[codec(index = "1")]
SendPoV(Hash, Hash, PoV),
}
/// The PoV Distribution Subsystem.
pub struct PoVDistribution;
@@ -98,6 +83,22 @@ struct PeerState {
awaited: HashMap<Hash, HashSet<Hash>>,
}
fn awaiting_message(relay_parent: Hash, awaiting: Vec<Hash>)
-> protocol_v1::ValidationProtocol
{
protocol_v1::ValidationProtocol::PoVDistribution(
protocol_v1::PoVDistributionMessage::Awaiting(relay_parent, awaiting)
)
}
fn send_pov_message(relay_parent: Hash, pov_hash: Hash, pov: PoV)
-> protocol_v1::ValidationProtocol
{
protocol_v1::ValidationProtocol::PoVDistribution(
protocol_v1::PoVDistributionMessage::SendPoV(relay_parent, pov_hash, pov)
)
}
/// Handles the signal. If successful, returns `true` if the subsystem should conclude,
/// `false` otherwise.
async fn handle_signal(
@@ -169,11 +170,10 @@ async fn notify_all_we_are_awaiting(
if peers_to_send.is_empty() { return Ok(()) }
let payload = WireMessage::Awaiting(relay_parent, vec![pov_hash]).encode();
let payload = awaiting_message(relay_parent, vec![pov_hash]);
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
peers_to_send,
PROTOCOL_V1,
payload,
))).await
}
@@ -194,11 +194,10 @@ async fn notify_one_we_are_awaiting_many(
if awaiting_hashes.is_empty() { return Ok(()) }
let payload = WireMessage::Awaiting(relay_parent, awaiting_hashes).encode();
let payload = awaiting_message(relay_parent, awaiting_hashes);
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
vec![peer.clone()],
PROTOCOL_V1,
payload,
))).await
}
@@ -226,11 +225,10 @@ async fn distribute_to_awaiting(
if peers_to_send.is_empty() { return Ok(()) }
let payload = WireMessage::SendPoV(relay_parent, pov_hash, pov.clone()).encode();
let payload = send_pov_message(relay_parent, pov_hash, pov.clone());
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
peers_to_send,
PROTOCOL_V1,
payload,
))).await
}
@@ -361,11 +359,10 @@ async fn handle_awaiting(
// For all requested PoV hashes, if we have it, we complete the request immediately.
// Otherwise, we note that the peer is awaiting the PoV.
if let Some(pov) = relay_parent_state.known.get(&pov_hash) {
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
vec![peer.clone()],
PROTOCOL_V1,
WireMessage::SendPoV(relay_parent, pov_hash, (&**pov).clone()).encode(),
))).await?;
let payload = send_pov_message(relay_parent, pov_hash, (&**pov).clone());
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendValidationMessage(vec![peer.clone()], payload)
)).await?;
} else {
peer_awaiting.insert(pov_hash);
}
@@ -449,7 +446,7 @@ async fn handle_incoming_pov(
async fn handle_network_update(
state: &mut State,
ctx: &mut impl SubsystemContext<Message = PoVDistributionMessage>,
update: NetworkBridgeEvent,
update: NetworkBridgeEvent<protocol_v1::PoVDistributionMessage>,
) -> SubsystemResult<()> {
match update {
NetworkBridgeEvent::PeerConnected(peer, _observed_role) => {
@@ -483,17 +480,18 @@ async fn handle_network_update(
Ok(())
}
NetworkBridgeEvent::PeerMessage(peer, bytes) => {
match WireMessage::decode(&mut &bytes[..]) {
Ok(msg) => match msg {
WireMessage::Awaiting(relay_parent, pov_hashes) => handle_awaiting(
NetworkBridgeEvent::PeerMessage(peer, message) => {
match message {
protocol_v1::PoVDistributionMessage::Awaiting(relay_parent, pov_hashes)
=> handle_awaiting(
state,
ctx,
peer,
relay_parent,
pov_hashes,
).await,
WireMessage::SendPoV(relay_parent, pov_hash, pov) => handle_incoming_pov(
protocol_v1::PoVDistributionMessage::SendPoV(relay_parent, pov_hash, pov)
=> handle_incoming_pov(
state,
ctx,
peer,
@@ -501,11 +499,6 @@ async fn handle_network_update(
pov_hash,
pov,
).await,
},
Err(_) => {
report_peer(ctx, peer, COST_MALFORMED_MESSAGE).await?;
Ok(())
}
}
}
NetworkBridgeEvent::OurViewChange(view) => {
@@ -515,19 +508,9 @@ async fn handle_network_update(
}
}
fn network_update_message(update: NetworkBridgeEvent) -> AllMessages {
AllMessages::PoVDistribution(PoVDistributionMessage::NetworkBridgeUpdate(update))
}
async fn run(
mut ctx: impl SubsystemContext<Message = PoVDistributionMessage>,
) -> SubsystemResult<()> {
// startup: register the network protocol with the bridge.
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::RegisterEventProducer(
PROTOCOL_V1,
network_update_message,
))).await?;
let mut state = State {
relay_parent_state: HashMap::new(),
peer_state: HashMap::new(),
@@ -556,7 +539,7 @@ async fn run(
descriptor,
pov,
).await?,
PoVDistributionMessage::NetworkBridgeUpdate(event) =>
PoVDistributionMessage::NetworkBridgeUpdateV1(event) =>
handle_network_update(
&mut state,
&mut ctx,
@@ -661,13 +644,12 @@ mod tests {
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(peers, protocol, message)
NetworkBridgeMessage::SendValidationMessage(peers, message)
) => {
assert_eq!(peers, vec![peer_a.clone()]);
assert_eq!(protocol, PROTOCOL_V1);
assert_eq!(
message,
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
send_pov_message(hash_a, pov_hash, pov.clone()),
);
}
)
@@ -737,13 +719,12 @@ mod tests {
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(peers, protocol, message)
NetworkBridgeMessage::SendValidationMessage(peers, message)
) => {
assert_eq!(peers, vec![peer_a.clone()]);
assert_eq!(protocol, PROTOCOL_V1);
assert_eq!(
message,
WireMessage::Awaiting(hash_a, vec![pov_hash]).encode(),
awaiting_message(hash_a, vec![pov_hash]),
);
}
)
@@ -809,13 +790,12 @@ mod tests {
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(peers, protocol, message)
NetworkBridgeMessage::SendValidationMessage(peers, message)
) => {
assert_eq!(peers, vec![peer_a.clone()]);
assert_eq!(protocol, PROTOCOL_V1);
assert_eq!(
message,
WireMessage::Awaiting(hash_a, vec![pov_a_hash]).encode(),
awaiting_message(hash_a, vec![pov_a_hash]),
);
}
)
@@ -878,8 +858,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
handle_network_update(
@@ -887,8 +867,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_b.clone(),
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
assert_eq!(&*pov_recv.await.unwrap(), &pov);
@@ -966,8 +946,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_a, pov_hash, bad_pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, bad_pov.clone()),
).focus().unwrap(),
).await.unwrap();
// didn't complete our sender.
@@ -1029,8 +1009,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
assert_matches!(
@@ -1090,8 +1070,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_b, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_b, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
assert_matches!(
@@ -1152,8 +1132,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::Awaiting(hash_a, vec![pov_hash]).encode(),
),
awaiting_message(hash_a, vec![pov_hash]),
).focus().unwrap(),
).await.unwrap();
}
@@ -1166,8 +1146,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::Awaiting(hash_a, vec![last_pov_hash]).encode(),
),
awaiting_message(hash_a, vec![last_pov_hash]),
).focus().unwrap(),
).await.unwrap();
// No more bookkeeping for you!
@@ -1235,8 +1215,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::Awaiting(hash_b, vec![pov_hash]).encode(),
),
awaiting_message(hash_b, vec![pov_hash]),
).focus().unwrap(),
).await.unwrap();
assert!(state.peer_state[&peer_a].awaited.get(&hash_b).is_none());
@@ -1297,8 +1277,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::Awaiting(hash_b, vec![pov_hash]).encode(),
),
awaiting_message(hash_b, vec![pov_hash]),
).focus().unwrap(),
).await.unwrap();
// Illegal `awaited` is ignored.
@@ -1371,8 +1351,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
assert_eq!(&*pov_recv.await.unwrap(), &pov);
@@ -1390,13 +1370,12 @@ mod tests {
assert_matches!(
handle.recv().await,
AllMessages::NetworkBridge(
NetworkBridgeMessage::SendMessage(peers, protocol, message)
NetworkBridgeMessage::SendValidationMessage(peers, message)
) => {
assert_eq!(peers, vec![peer_b.clone()]);
assert_eq!(protocol, PROTOCOL_V1);
assert_eq!(
message,
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
send_pov_message(hash_a, pov_hash, pov.clone()),
);
}
);
@@ -1454,8 +1433,8 @@ mod tests {
&mut ctx,
NetworkBridgeEvent::PeerMessage(
peer_a.clone(),
WireMessage::SendPoV(hash_a, pov_hash, pov.clone()).encode(),
),
send_pov_message(hash_a, pov_hash, pov.clone()),
).focus().unwrap(),
).await.unwrap();
assert_eq!(&*pov_recv.await.unwrap(), &pov);
+14
View File
@@ -0,0 +1,14 @@
[package]
name = "polkadot-node-network-protocol"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
description = "Primitives types for the Node-side"
[dependencies]
polkadot-primitives = { path = "../../../primitives" }
polkadot-node-primitives = { path = "../../primitives" }
parity-scale-codec = { version = "1.3.4", default-features = false, features = ["derive"] }
runtime_primitives = { package = "sp-runtime", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
+269
View File
@@ -0,0 +1,269 @@
// 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/>.
//! Network protocol types for parachains.
use polkadot_primitives::v1::Hash;
use parity_scale_codec::{Encode, Decode};
use std::convert::TryFrom;
pub use sc_network::{ReputationChange, PeerId};
/// A unique identifier of a request.
pub type RequestId = u64;
/// A version of the protocol.
pub type ProtocolVersion = u32;
/// An error indicating that this the over-arching message type had the wrong variant
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct WrongVariant;
/// The peer-sets that the network manages. Different subsystems will use different peer-sets.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum PeerSet {
/// The validation peer-set is responsible for all messages related to candidate validation and communication among validators.
Validation,
/// The collation peer-set is used for validator<>collator communication.
Collation,
}
/// The advertised role of a node.
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ObservedRole {
/// A light node.
Light,
/// A full node.
Full,
/// A node claiming to be an authority (unauthenticated)
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
| sc_network::ObservedRole::OurSentry
| sc_network::ObservedRole::OurGuardedAuthority
=> 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,
}
}
}
/// Events from network.
#[derive(Debug, Clone, PartialEq)]
pub enum NetworkBridgeEvent<M> {
/// A peer has connected.
PeerConnected(PeerId, ObservedRole),
/// A peer has disconnected.
PeerDisconnected(PeerId),
/// Peer has sent a message.
PeerMessage(PeerId, M),
/// Peer's `View` has changed.
PeerViewChange(PeerId, View),
/// Our `View` has changed.
OurViewChange(View),
}
macro_rules! impl_try_from {
($m_ty:ident, $variant:ident, $out:ty) => {
impl TryFrom<$m_ty> for $out {
type Error = crate::WrongVariant;
#[allow(unreachable_patterns)] // when there is only one variant
fn try_from(x: $m_ty) -> Result<$out, Self::Error> {
match x {
$m_ty::$variant(y) => Ok(y),
_ => Err(crate::WrongVariant),
}
}
}
impl<'a> TryFrom<&'a $m_ty> for &'a $out {
type Error = crate::WrongVariant;
fn try_from(x: &'a $m_ty) -> Result<&'a $out, Self::Error> {
#[allow(unreachable_patterns)] // when there is only one variant
match *x {
$m_ty::$variant(ref y) => Ok(y),
_ => Err(crate::WrongVariant),
}
}
}
}
}
impl<M> NetworkBridgeEvent<M> {
/// Focus an overarching network-bridge event into some more specific variant.
///
/// This acts as a call to `clone`, except in the case where the event is a message event,
/// in which case the clone can be expensive and it only clones if the message type can
/// be focused.
pub fn focus<'a, T>(&'a self) -> Result<NetworkBridgeEvent<T>, WrongVariant>
where T: 'a + Clone, &'a T: TryFrom<&'a M, Error = WrongVariant>
{
Ok(match *self {
NetworkBridgeEvent::PeerConnected(ref peer, ref role)
=> NetworkBridgeEvent::PeerConnected(peer.clone(), role.clone()),
NetworkBridgeEvent::PeerDisconnected(ref peer)
=> NetworkBridgeEvent::PeerDisconnected(peer.clone()),
NetworkBridgeEvent::PeerMessage(ref peer, ref msg)
=> NetworkBridgeEvent::PeerMessage(peer.clone(), <&'a T>::try_from(msg)?.clone()),
NetworkBridgeEvent::PeerViewChange(ref peer, ref view)
=> NetworkBridgeEvent::PeerViewChange(peer.clone(), view.clone()),
NetworkBridgeEvent::OurViewChange(ref view)
=> NetworkBridgeEvent::OurViewChange(view.clone()),
})
}
}
/// A succinct representation of a peer's view. This consists of a bounded amount of chain heads.
///
/// Up to `N` (5?) chain heads.
#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
pub struct View(pub Vec<Hash>);
impl View {
/// Returns an iterator of the hashes present in `Self` but not in `other`.
pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.0.iter().filter(move |h| !other.contains(h))
}
/// An iterator containing hashes present in both `Self` and in `other`.
pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.0.iter().filter(move |h| other.contains(h))
}
/// Whether the view contains a given hash.
pub fn contains(&self, hash: &Hash) -> bool {
self.0.contains(hash)
}
}
/// v1 protocol types.
pub mod v1 {
use polkadot_primitives::v1::{
Hash, CollatorId, Id as ParaId, ErasureChunk, CandidateReceipt,
SignedAvailabilityBitfield, PoV,
};
use polkadot_node_primitives::SignedFullStatement;
use parity_scale_codec::{Encode, Decode};
use std::convert::TryFrom;
use super::RequestId;
/// Network messages used by the availability distribution subsystem
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum AvailabilityDistributionMessage {
/// An erasure chunk for a given candidate hash.
#[codec(index = "0")]
Chunk(Hash, ErasureChunk),
}
/// Network messages used by the bitfield distribution subsystem.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum BitfieldDistributionMessage {
/// A signed availability bitfield for a given relay-parent hash.
#[codec(index = "0")]
Bitfield(Hash, SignedAvailabilityBitfield),
}
/// Network messages used by the PoV distribution subsystem.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum PoVDistributionMessage {
/// Notification that we are awaiting the given PoVs (by hash) against a
/// specific relay-parent hash.
#[codec(index = "0")]
Awaiting(Hash, Vec<Hash>),
/// Notification of an awaited PoV, in a given relay-parent context.
/// (relay_parent, pov_hash, pov)
#[codec(index = "1")]
SendPoV(Hash, Hash, PoV),
}
/// Network messages used by the statement distribution subsystem.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum StatementDistributionMessage {
/// A signed full statement under a given relay-parent.
#[codec(index = "0")]
Statement(Hash, SignedFullStatement)
}
/// Network messages used by the collator protocol subsystem
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum CollatorProtocolMessage {
/// Declare the intent to advertise collations under a collator ID.
#[codec(index = "0")]
Declare(CollatorId),
/// Advertise a collation to a validator. Can only be sent once the peer has declared
/// that they are a collator with given ID.
#[codec(index = "1")]
AdvertiseCollation(Hash, ParaId),
/// Request the advertised collation at that relay-parent.
#[codec(index = "2")]
RequestCollation(RequestId, Hash, ParaId),
/// A requested collation.
#[codec(index = "3")]
Collation(RequestId, CandidateReceipt, PoV),
}
/// All network messages on the validation peer-set.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum ValidationProtocol {
/// Availability distribution messages
#[codec(index = "0")]
AvailabilityDistribution(AvailabilityDistributionMessage),
/// Bitfield distribution messages
#[codec(index = "1")]
BitfieldDistribution(BitfieldDistributionMessage),
/// PoV Distribution messages
#[codec(index = "2")]
PoVDistribution(PoVDistributionMessage),
/// Statement distribution messages
#[codec(index = "3")]
StatementDistribution(StatementDistributionMessage),
}
impl_try_from!(ValidationProtocol, AvailabilityDistribution, AvailabilityDistributionMessage);
impl_try_from!(ValidationProtocol, BitfieldDistribution, BitfieldDistributionMessage);
impl_try_from!(ValidationProtocol, PoVDistribution, PoVDistributionMessage);
impl_try_from!(ValidationProtocol, StatementDistribution, StatementDistributionMessage);
/// All network messages on the collation peer-set.
#[derive(Debug, Clone, Encode, Decode, PartialEq)]
pub enum CollationProtocol {
/// Collator protocol messages
#[codec(index = "0")]
CollatorProtocol(CollatorProtocolMessage),
}
impl_try_from!(CollationProtocol, CollatorProtocol, CollatorProtocolMessage);
}
@@ -16,6 +16,7 @@ parity-scale-codec = "1.3.4"
sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
sp-staking = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
polkadot-subsystem = { package = "polkadot-node-subsystem", path = "../../subsystem" }
polkadot-node-network-protocol = { path = "../../network/protocol" }
arrayvec = "0.5.1"
indexmap = "1.4.0"
@@ -24,15 +24,16 @@ use polkadot_subsystem::{
ActiveLeavesUpdate, FromOverseer, OverseerSignal,
};
use polkadot_subsystem::messages::{
AllMessages, NetworkBridgeMessage, NetworkBridgeEvent, StatementDistributionMessage,
PeerId, ReputationChange as Rep, CandidateBackingMessage, RuntimeApiMessage,
RuntimeApiRequest,
AllMessages, NetworkBridgeMessage, StatementDistributionMessage, CandidateBackingMessage,
RuntimeApiMessage, RuntimeApiRequest,
};
use node_primitives::{ProtocolId, View, SignedFullStatement};
use node_primitives::SignedFullStatement;
use polkadot_primitives::v1::{
Hash, CompactStatement, ValidatorIndex, ValidatorId, SigningContext, ValidatorSignature,
};
use parity_scale_codec::{Encode, Decode};
use polkadot_node_network_protocol::{
v1 as protocol_v1, View, PeerId, ReputationChange as Rep, NetworkBridgeEvent,
};
use futures::prelude::*;
use futures::channel::oneshot;
@@ -40,11 +41,8 @@ use indexmap::IndexSet;
use std::collections::{HashMap, HashSet};
const PROTOCOL_V1: ProtocolId = *b"sdn1";
const COST_UNEXPECTED_STATEMENT: Rep = Rep::new(-100, "Unexpected Statement");
const COST_INVALID_SIGNATURE: Rep = Rep::new(-500, "Invalid Statement Signature");
const COST_INVALID_MESSAGE: Rep = Rep::new(-500, "Invalid message");
const COST_DUPLICATE_STATEMENT: Rep = Rep::new(-250, "Statement sent more than once by peer");
const COST_APPARENT_FLOOD: Rep = Rep::new(-1000, "Peer appears to be flooding us with statements");
@@ -77,10 +75,6 @@ impl<C> Subsystem<C> for StatementDistribution
}
}
fn network_update_message(n: NetworkBridgeEvent) -> AllMessages {
AllMessages::StatementDistribution(StatementDistributionMessage::NetworkBridgeUpdate(n))
}
/// Tracks our impression of a single peer's view of the candidates a validator has seconded
/// for a given relay-parent.
///
@@ -480,13 +474,6 @@ fn check_statement_signature(
.and_then(|v| statement.check_signature(&signing_context, v))
}
#[derive(Encode, Decode)]
enum WireMessage {
/// relay-parent, full statement.
#[codec(index = "0")]
Statement(Hash, SignedFullStatement),
}
/// Places the statement in storage if it is new, and then
/// circulates the statement to all peers who have not seen it yet, and
/// sends all statements dependent on that statement to peers who could previously not receive
@@ -534,6 +521,14 @@ async fn circulate_statement_and_dependents(
Ok(())
}
fn statement_message(relay_parent: Hash, statement: SignedFullStatement)
-> protocol_v1::ValidationProtocol
{
protocol_v1::ValidationProtocol::StatementDistribution(
protocol_v1::StatementDistributionMessage::Statement(relay_parent, statement)
)
}
/// Circulates a statement to all peers who have not seen it yet, and returns
/// an iterator over peers who need to have dependent statements sent.
async fn circulate_statement(
@@ -554,10 +549,9 @@ async fn circulate_statement(
// Send all these peers the initial statement.
if !peers_to_send.is_empty() {
let payload = WireMessage::Statement(relay_parent, stored.statement.clone()).encode();
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
let payload = statement_message(relay_parent, stored.statement.clone());
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
peers_to_send.keys().cloned().collect(),
PROTOCOL_V1,
payload,
))).await?;
}
@@ -580,16 +574,14 @@ async fn send_statements_about(
) -> SubsystemResult<()> {
for statement in active_head.statements_about(candidate_hash) {
if peer_data.send(&relay_parent, &statement.fingerprint()).is_some() {
let payload = WireMessage::Statement(
let payload = statement_message(
relay_parent,
statement.statement.clone(),
).encode();
);
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
vec![peer.clone()],
PROTOCOL_V1,
payload,
))).await?;
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendValidationMessage(vec![peer.clone()], payload)
)).await?;
}
}
@@ -606,16 +598,14 @@ async fn send_statements(
) -> SubsystemResult<()> {
for statement in active_head.statements() {
if peer_data.send(&relay_parent, &statement.fingerprint()).is_some() {
let payload = WireMessage::Statement(
let payload = statement_message(
relay_parent,
statement.statement.clone(),
).encode();
);
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
vec![peer.clone()],
PROTOCOL_V1,
payload,
))).await?;
ctx.send_message(AllMessages::NetworkBridge(
NetworkBridgeMessage::SendValidationMessage(vec![peer.clone()], payload)
)).await?;
}
}
@@ -643,11 +633,10 @@ async fn handle_incoming_message<'a>(
our_view: &View,
active_heads: &'a mut HashMap<Hash, ActiveHeadData>,
ctx: &mut impl SubsystemContext<Message = StatementDistributionMessage>,
message: Vec<u8>,
message: protocol_v1::StatementDistributionMessage,
) -> SubsystemResult<Option<(Hash, &'a StoredStatement)>> {
let (relay_parent, statement) = match WireMessage::decode(&mut &message[..]) {
Err(_) => return report_peer(ctx, peer, COST_INVALID_MESSAGE).await.map(|_| None),
Ok(WireMessage::Statement(r, s)) => (r, s),
let (relay_parent, statement) = match message {
protocol_v1::StatementDistributionMessage::Statement(r, s) => (r, s),
};
if !our_view.contains(&relay_parent) {
@@ -750,7 +739,7 @@ async fn handle_network_update(
active_heads: &mut HashMap<Hash, ActiveHeadData>,
ctx: &mut impl SubsystemContext<Message = StatementDistributionMessage>,
our_view: &mut View,
update: NetworkBridgeEvent,
update: NetworkBridgeEvent<protocol_v1::StatementDistributionMessage>,
) -> SubsystemResult<()> {
match update {
NetworkBridgeEvent::PeerConnected(peer, _role) => {
@@ -827,12 +816,6 @@ async fn handle_network_update(
async fn run(
mut ctx: impl SubsystemContext<Message = StatementDistributionMessage>,
) -> SubsystemResult<()> {
// startup: register the network protocol with the bridge.
ctx.send_message(AllMessages::NetworkBridge(NetworkBridgeMessage::RegisterEventProducer(
PROTOCOL_V1,
network_update_message,
))).await?;
let mut peers: HashMap<PeerId, PeerData> = HashMap::new();
let mut our_view = View::default();
let mut active_heads: HashMap<Hash, ActiveHeadData> = HashMap::new();
@@ -897,13 +880,14 @@ async fn run(
relay_parent,
statement,
).await?,
StatementDistributionMessage::NetworkBridgeUpdate(event) => handle_network_update(
&mut peers,
&mut active_heads,
&mut ctx,
&mut our_view,
event,
).await?,
StatementDistributionMessage::NetworkBridgeUpdateV1(event) =>
handle_network_update(
&mut peers,
&mut active_heads,
&mut ctx,
&mut our_view,
event,
).await?,
}
}
}
@@ -1272,19 +1256,16 @@ mod tests {
for statement in active_head.statements_about(candidate_hash) {
let message = handle.recv().await;
let expected_to = vec![peer.clone()];
let expected_protocol = PROTOCOL_V1;
let expected_payload
= WireMessage::Statement(hash_c, statement.statement.clone()).encode();
= statement_message(hash_c, statement.statement.clone());
assert_matches!(
message,
AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
to,
protocol,
payload,
)) => {
assert_eq!(to, expected_to);
assert_eq!(protocol, expected_protocol);
assert_eq!(payload, expected_payload)
}
)
@@ -1383,19 +1364,17 @@ mod tests {
let message = handle.recv().await;
assert_matches!(
message,
AllMessages::NetworkBridge(NetworkBridgeMessage::SendMessage(
AllMessages::NetworkBridge(NetworkBridgeMessage::SendValidationMessage(
to,
protocol,
payload,
)) => {
assert_eq!(to.len(), 2);
assert!(to.contains(&peer_b));
assert!(to.contains(&peer_c));
assert_eq!(protocol, PROTOCOL_V1);
assert_eq!(
payload,
WireMessage::Statement(hash_b, statement.statement.clone()).encode(),
statement_message(hash_b, statement.statement.clone()),
);
}
)
@@ -145,6 +145,7 @@ fn main() {
candidate_validation: Subsystem2,
candidate_backing: Subsystem1,
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
+36 -4
View File
@@ -78,7 +78,7 @@ use polkadot_subsystem::messages::{
CandidateValidationMessage, CandidateBackingMessage,
CandidateSelectionMessage, ChainApiMessage, StatementDistributionMessage,
AvailabilityDistributionMessage, BitfieldSigningMessage, BitfieldDistributionMessage,
ProvisionerMessage, PoVDistributionMessage, RuntimeApiMessage,
ProvisionerMessage, PoVDistributionMessage, RuntimeApiMessage, CollatorProtocolMessage,
AvailabilityStoreMessage, NetworkBridgeMessage, AllMessages,
};
pub use polkadot_subsystem::{
@@ -333,6 +333,9 @@ pub struct Overseer<S: SpawnNamed> {
/// A candidate selection subsystem.
candidate_selection_subsystem: OverseenSubsystem<CandidateSelectionMessage>,
/// A collator protocol subsystem
collator_protocol_subsystem: OverseenSubsystem<CollatorProtocolMessage>,
/// A statement distribution subsystem.
statement_distribution_subsystem: OverseenSubsystem<StatementDistributionMessage>,
@@ -395,13 +398,15 @@ pub struct Overseer<S: SpawnNamed> {
///
/// [`Subsystem`]: trait.Subsystem.html
/// [`DummySubsystem`]: struct.DummySubsystem.html
pub struct AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA> {
pub struct AllSubsystems<CV, CB, CS, CP, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA> {
/// A candidate validation subsystem.
pub candidate_validation: CV,
/// A candidate backing subsystem.
pub candidate_backing: CB,
/// A candidate selection subsystem.
pub candidate_selection: CS,
/// A collator protocol subsystem.
pub collator_protocol: CP,
/// A statement distribution subsystem.
pub statement_distribution: SD,
/// An availability distribution subsystem.
@@ -494,6 +499,7 @@ where
/// candidate_validation: ValidationSubsystem,
/// candidate_backing: DummySubsystem,
/// candidate_selection: DummySubsystem,
/// collator_protocol: DummySubsystem,
/// statement_distribution: DummySubsystem,
/// availability_distribution: DummySubsystem,
/// bitfield_signing: DummySubsystem,
@@ -524,15 +530,16 @@ where
/// #
/// # }); }
/// ```
pub fn new<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA>(
pub fn new<CV, CB, CS, CP, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA>(
leaves: impl IntoIterator<Item = BlockInfo>,
all_subsystems: AllSubsystems<CV, CB, CS, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA>,
all_subsystems: AllSubsystems<CV, CB, CS, CP, SD, AD, BS, BD, P, PoVD, RA, AS, NB, CA>,
mut s: S,
) -> SubsystemResult<(Self, OverseerHandler)>
where
CV: Subsystem<OverseerSubsystemContext<CandidateValidationMessage>> + Send,
CB: Subsystem<OverseerSubsystemContext<CandidateBackingMessage>> + Send,
CS: Subsystem<OverseerSubsystemContext<CandidateSelectionMessage>> + Send,
CP: Subsystem<OverseerSubsystemContext<CollatorProtocolMessage>> + Send,
SD: Subsystem<OverseerSubsystemContext<StatementDistributionMessage>> + Send,
AD: Subsystem<OverseerSubsystemContext<AvailabilityDistributionMessage>> + Send,
BS: Subsystem<OverseerSubsystemContext<BitfieldSigningMessage>> + Send,
@@ -574,6 +581,13 @@ where
all_subsystems.candidate_selection,
)?;
let collator_protocol_subsystem = spawn(
&mut s,
&mut running_subsystems,
&mut running_subsystems_rx,
all_subsystems.collator_protocol,
)?;
let statement_distribution_subsystem = spawn(
&mut s,
&mut running_subsystems,
@@ -655,6 +669,7 @@ where
candidate_validation_subsystem,
candidate_backing_subsystem,
candidate_selection_subsystem,
collator_protocol_subsystem,
statement_distribution_subsystem,
availability_distribution_subsystem,
bitfield_signing_subsystem,
@@ -690,6 +705,10 @@ where
let _ = s.tx.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}
if let Some(ref mut s) = self.collator_protocol_subsystem.instance {
let _ = s.tx.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}
if let Some(ref mut s) = self.statement_distribution_subsystem.instance {
let _ = s.tx.send(FromOverseer::Signal(OverseerSignal::Conclude)).await;
}
@@ -844,6 +863,10 @@ where
s.tx.send(FromOverseer::Signal(signal.clone())).await?;
}
if let Some(ref mut s) = self.collator_protocol_subsystem.instance {
s.tx.send(FromOverseer::Signal(signal.clone())).await?;
}
if let Some(ref mut s) = self.statement_distribution_subsystem.instance {
s.tx.send(FromOverseer::Signal(signal.clone())).await?;
}
@@ -900,6 +923,11 @@ where
let _ = s.tx.send(FromOverseer::Communication { msg }).await;
}
}
AllMessages::CollatorProtocol(msg) => {
if let Some(ref mut s) = self.collator_protocol_subsystem.instance {
let _ = s.tx.send(FromOverseer::Communication { msg }).await;
}
}
AllMessages::StatementDistribution(msg) => {
if let Some(ref mut s) = self.statement_distribution_subsystem.instance {
let _ = s.tx.send(FromOverseer::Communication { msg }).await;
@@ -1102,6 +1130,7 @@ mod tests {
candidate_validation: TestSubsystem1(s1_tx),
candidate_backing: TestSubsystem2(s2_tx),
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
@@ -1166,6 +1195,7 @@ mod tests {
candidate_validation: TestSubsystem1(s1_tx),
candidate_backing: TestSubsystem4,
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
@@ -1283,6 +1313,7 @@ mod tests {
candidate_validation: TestSubsystem5(tx_5),
candidate_backing: TestSubsystem6(tx_6),
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
@@ -1385,6 +1416,7 @@ mod tests {
candidate_validation: TestSubsystem5(tx_5),
candidate_backing: TestSubsystem6(tx_6),
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
-26
View File
@@ -258,29 +258,3 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
}
}
}
/// A unique identifier for a network protocol.
pub type ProtocolId = [u8; 4];
/// A succinct representation of a peer's view. This consists of a bounded amount of chain heads.
///
/// Up to `N` (5?) chain heads.
#[derive(Default, Debug, Clone, PartialEq, Eq, Encode, Decode)]
pub struct View(pub Vec<Hash>);
impl View {
/// Returns an iterator of the hashes present in `Self` but not in `other`.
pub fn difference<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.0.iter().filter(move |h| !other.contains(h))
}
/// An iterator containing hashes present in both `Self` and in `other`.
pub fn intersection<'a>(&'a self, other: &'a View) -> impl Iterator<Item = &'a Hash> + 'a {
self.0.iter().filter(move |h| other.contains(h))
}
/// Whether the view contains a given hash.
pub fn contains(&self, hash: &Hash) -> bool {
self.0.contains(hash)
}
}
+1
View File
@@ -281,6 +281,7 @@ fn real_overseer<S: SpawnNamed>(
candidate_validation: DummySubsystem,
candidate_backing: DummySubsystem,
candidate_selection: DummySubsystem,
collator_protocol: DummySubsystem,
statement_distribution: DummySubsystem,
availability_distribution: DummySubsystem,
bitfield_signing: DummySubsystem,
+1
View File
@@ -15,6 +15,7 @@ parity-scale-codec = "1.3.4"
parking_lot = { version = "0.10.0", optional = true }
pin-project = "0.4.22"
polkadot-node-primitives = { path = "../primitives" }
polkadot-node-network-protocol = { path = "../network/protocol" }
polkadot-primitives = { path = "../../primitives" }
polkadot-statement-table = { path = "../../statement-table" }
sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
+65 -36
View File
@@ -25,7 +25,7 @@
use futures::channel::{mpsc, oneshot};
use polkadot_primitives::v1::{
Hash, CommittedCandidateReceipt,
Hash, CommittedCandidateReceipt, CollatorId,
CandidateReceipt, PoV, ErasureChunk, BackedCandidate, Id as ParaId,
SignedAvailabilityBitfield, ValidatorId, ValidationCode, ValidatorIndex,
CoreAssignment, CoreOccupied, CandidateDescriptor,
@@ -34,12 +34,13 @@ use polkadot_primitives::v1::{
CandidateEvent, SessionIndex, BlockNumber,
};
use polkadot_node_primitives::{
MisbehaviorReport, SignedFullStatement, View, ProtocolId, ValidationResult,
MisbehaviorReport, SignedFullStatement, ValidationResult,
};
use polkadot_node_network_protocol::{
v1 as protocol_v1, NetworkBridgeEvent, ReputationChange, PeerId, PeerSet,
};
use std::sync::Arc;
pub use sc_network::{ObservedRole, ReputationChange, PeerId};
/// A notification of a new backed candidate.
#[derive(Debug)]
pub struct NewBackedCandidate(pub BackedCandidate);
@@ -142,45 +143,71 @@ impl CandidateValidationMessage {
}
}
/// Events from network.
#[derive(Debug, Clone)]
pub enum NetworkBridgeEvent {
/// A peer has connected.
PeerConnected(PeerId, ObservedRole),
/// A peer has disconnected.
PeerDisconnected(PeerId),
/// 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, 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<protocol_v1::CollatorProtocolMessage>),
}
/// Peer has sent a message.
PeerMessage(PeerId, Vec<u8>),
/// Peer's `View` has changed.
PeerViewChange(PeerId, View),
/// Our `View` has changed.
OurViewChange(View),
impl CollatorProtocolMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option<Hash> {
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 {
/// Register an event producer on startup.
RegisterEventProducer(ProtocolId, fn(NetworkBridgeEvent) -> AllMessages),
/// Report a peer for their actions.
ReportPeer(PeerId, ReputationChange),
/// Send a message to multiple peers.
SendMessage(Vec<PeerId>, ProtocolId, Vec<u8>),
/// Send a message to one or more peers on the validation peer-set.
SendValidationMessage(Vec<PeerId>, protocol_v1::ValidationProtocol),
/// Send a message to one or more peers on the collation peer-set.
SendCollationMessage(Vec<PeerId>, protocol_v1::CollationProtocol),
/// Connect to peers who represent the given `ValidatorId`s at the given relay-parent.
///
/// Also accepts a response channel by which the issuer can learn the `PeerId`s of those
/// validators.
ConnectToValidators(PeerSet, Vec<ValidatorId>, oneshot::Sender<Vec<(ValidatorId, PeerId)>>),
}
impl NetworkBridgeMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option<Hash> {
match self {
Self::RegisterEventProducer(_, _) => None,
Self::ReportPeer(_, _) => None,
Self::SendMessage(_, _, _) => None,
Self::SendValidationMessage(_, _) => None,
Self::SendCollationMessage(_, _) => None,
Self::ConnectToValidators(_, _, _) => None,
}
}
}
@@ -189,14 +216,14 @@ impl NetworkBridgeMessage {
#[derive(Debug)]
pub enum AvailabilityDistributionMessage {
/// Event from the network bridge.
NetworkBridgeUpdate(NetworkBridgeEvent),
NetworkBridgeUpdateV1(NetworkBridgeEvent<protocol_v1::AvailabilityDistributionMessage>),
}
impl AvailabilityDistributionMessage {
/// If the current variant contains the relay parent hash, return it.
pub fn relay_parent(&self) -> Option<Hash> {
match self {
Self::NetworkBridgeUpdate(_) => None,
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
@@ -208,7 +235,7 @@ pub enum BitfieldDistributionMessage {
DistributeBitfield(Hash, SignedAvailabilityBitfield),
/// Event from the network bridge.
NetworkBridgeUpdate(NetworkBridgeEvent),
NetworkBridgeUpdateV1(NetworkBridgeEvent<protocol_v1::BitfieldDistributionMessage>),
}
impl BitfieldDistributionMessage {
@@ -216,7 +243,7 @@ impl BitfieldDistributionMessage {
pub fn relay_parent(&self) -> Option<Hash> {
match self {
Self::DistributeBitfield(hash, _) => Some(*hash),
Self::NetworkBridgeUpdate(_) => None,
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
@@ -391,7 +418,7 @@ pub enum StatementDistributionMessage {
/// given relay-parent hash and it should be distributed to other validators.
Share(Hash, SignedFullStatement),
/// Event from the network bridge.
NetworkBridgeUpdate(NetworkBridgeEvent),
NetworkBridgeUpdateV1(NetworkBridgeEvent<protocol_v1::StatementDistributionMessage>),
}
impl StatementDistributionMessage {
@@ -399,7 +426,7 @@ impl StatementDistributionMessage {
pub fn relay_parent(&self) -> Option<Hash> {
match self {
Self::Share(hash, _) => Some(*hash),
Self::NetworkBridgeUpdate(_) => None,
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
@@ -464,7 +491,7 @@ pub enum PoVDistributionMessage {
/// The PoV should correctly hash to the PoV hash mentioned in the CandidateDescriptor
DistributePoV(Hash, CandidateDescriptor, Arc<PoV>),
/// An update from the network bridge.
NetworkBridgeUpdate(NetworkBridgeEvent),
NetworkBridgeUpdateV1(NetworkBridgeEvent<protocol_v1::PoVDistributionMessage>),
}
impl PoVDistributionMessage {
@@ -473,7 +500,7 @@ impl PoVDistributionMessage {
match self {
Self::FetchPoV(hash, _, _) => Some(*hash),
Self::DistributePoV(hash, _, _) => Some(*hash),
Self::NetworkBridgeUpdate(_) => None,
Self::NetworkBridgeUpdateV1(_) => None,
}
}
}
@@ -487,6 +514,10 @@ pub enum AllMessages {
CandidateBacking(CandidateBackingMessage),
/// Message for the candidate selection subsystem.
CandidateSelection(CandidateSelectionMessage),
/// Message for the Chain API subsystem.
ChainApi(ChainApiMessage),
/// Message for the Collator Protocol subsystem.
CollatorProtocol(CollatorProtocolMessage),
/// Message for the statement distribution subsystem.
StatementDistribution(StatementDistributionMessage),
/// Message for the availability distribution subsystem.
@@ -505,6 +536,4 @@ pub enum AllMessages {
AvailabilityStore(AvailabilityStoreMessage),
/// Message for the network bridge subsystem.
NetworkBridge(NetworkBridgeMessage),
/// Message for the Chain API subsystem.
ChainApi(ChainApiMessage),
}