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
@@ -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);
}
);
});
}
}