mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-09 20:11:09 +00:00
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:
committed by
GitHub
parent
8e60a5197f
commit
a6b1d91d6e
Generated
+19
-7
@@ -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",
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
);
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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" }
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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" }
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user