Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 72ea91f

Browse files
tomakabkchr
authored andcommitted
Allow remotes to not open a legacy substream (#7075)
* Allow remotes to not open a legacy substream * Misc fixes * Special case first protocol as the one bearing the handshake
1 parent c071d06 commit 72ea91f

File tree

8 files changed

+168
-154
lines changed

8 files changed

+168
-154
lines changed

client/network/src/protocol.rs

Lines changed: 117 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use sp_consensus::{
3636
block_validation::BlockAnnounceValidator,
3737
import_queue::{BlockImportResult, BlockImportError, IncomingBlock, Origin}
3838
};
39-
use codec::{Decode, Encode};
39+
use codec::{Decode, DecodeAll, Encode};
4040
use sp_runtime::{generic::BlockId, ConsensusEngineId, Justification};
4141
use sp_runtime::traits::{
4242
Block as BlockT, Header as HeaderT, NumberFor, Zero, CheckedSub
@@ -53,7 +53,7 @@ use std::borrow::Cow;
5353
use std::collections::{HashMap, HashSet, VecDeque, hash_map::Entry};
5454
use std::sync::Arc;
5555
use std::fmt::Write;
56-
use std::{io, num::NonZeroUsize, pin::Pin, task::Poll, time};
56+
use std::{io, iter, num::NonZeroUsize, pin::Pin, task::Poll, time};
5757
use log::{log, Level, trace, debug, warn, error};
5858
use wasm_timer::Instant;
5959

@@ -275,8 +275,6 @@ struct Peer<B: BlockT, H: ExHashT> {
275275
pub struct PeerInfo<B: BlockT> {
276276
/// Roles
277277
pub roles: Roles,
278-
/// Protocol version
279-
pub protocol_version: u32,
280278
/// Peer best block hash
281279
pub best_hash: B::Hash,
282280
/// Peer best block number
@@ -395,14 +393,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
395393
};
396394

397395
let (peerset, peerset_handle) = sc_peerset::Peerset::from_config(peerset_config);
398-
let versions = &((MIN_VERSION as u8)..=(CURRENT_VERSION as u8)).collect::<Vec<u8>>();
399-
let mut behaviour = GenericProto::new(
400-
local_peer_id,
401-
protocol_id.clone(),
402-
versions,
403-
build_status_message(&config, &chain),
404-
peerset,
405-
);
406396

407397
let mut legacy_equiv_by_name = HashMap::new();
408398

@@ -413,7 +403,6 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
413403
proto.push_str("/transactions/1");
414404
proto
415405
});
416-
behaviour.register_notif_protocol(transactions_protocol.clone(), Vec::new());
417406
legacy_equiv_by_name.insert(transactions_protocol.clone(), Fallback::Transactions);
418407

419408
let block_announces_protocol: Cow<'static, str> = Cow::from({
@@ -423,12 +412,24 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
423412
proto.push_str("/block-announces/1");
424413
proto
425414
});
426-
behaviour.register_notif_protocol(
427-
block_announces_protocol.clone(),
428-
BlockAnnouncesHandshake::build(&config, &chain).encode()
429-
);
430415
legacy_equiv_by_name.insert(block_announces_protocol.clone(), Fallback::BlockAnnounce);
431416

417+
let behaviour = {
418+
let versions = &((MIN_VERSION as u8)..=(CURRENT_VERSION as u8)).collect::<Vec<u8>>();
419+
let block_announces_handshake = BlockAnnouncesHandshake::build(&config, &chain).encode();
420+
GenericProto::new(
421+
local_peer_id,
422+
protocol_id.clone(),
423+
versions,
424+
build_status_message(&config, &chain),
425+
peerset,
426+
// As documented in `GenericProto`, the first protocol in the list is always the
427+
// one carrying the handshake reported in the `CustomProtocolOpen` event.
428+
iter::once((block_announces_protocol.clone(), block_announces_handshake))
429+
.chain(iter::once((transactions_protocol.clone(), vec![]))),
430+
)
431+
};
432+
432433
let protocol = Protocol {
433434
tick_timeout: Box::pin(interval(TICK_TIMEOUT)),
434435
propagate_timeout: Box::pin(interval(PROPAGATE_TIMEOUT)),
@@ -839,99 +840,86 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
839840
}
840841
}
841842

842-
/// Called on receipt of a status message via the legacy protocol on the first connection between two peers.
843-
pub fn on_peer_connected(
843+
/// Called on the first connection between two peers, after their exchange of handshake.
844+
fn on_peer_connected(
844845
&mut self,
845846
who: PeerId,
846-
status: message::Status<B>,
847+
status: BlockAnnouncesHandshake<B>,
847848
notifications_sink: NotificationsSink,
848849
) -> CustomMessageOutcome<B> {
849850
trace!(target: "sync", "New peer {} {:?}", who, status);
850-
let _protocol_version = {
851-
if self.context_data.peers.contains_key(&who) {
852-
debug!(target: "sync", "Ignoring duplicate status packet from {}", who);
853-
return CustomMessageOutcome::None;
854-
}
855-
if status.genesis_hash != self.genesis_hash {
856-
log!(
857-
target: "sync",
858-
if self.important_peers.contains(&who) { Level::Warn } else { Level::Trace },
859-
"Peer is on different chain (our genesis: {} theirs: {})",
860-
self.genesis_hash, status.genesis_hash
861-
);
862-
self.peerset_handle.report_peer(who.clone(), rep::GENESIS_MISMATCH);
863-
self.behaviour.disconnect_peer(&who);
864851

865-
if self.boot_node_ids.contains(&who) {
866-
error!(
867-
target: "sync",
868-
"Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})",
869-
who,
870-
self.genesis_hash,
871-
status.genesis_hash,
872-
);
873-
}
852+
if self.context_data.peers.contains_key(&who) {
853+
debug!(target: "sync", "Ignoring duplicate status packet from {}", who);
854+
return CustomMessageOutcome::None;
855+
}
856+
if status.genesis_hash != self.genesis_hash {
857+
log!(
858+
target: "sync",
859+
if self.important_peers.contains(&who) { Level::Warn } else { Level::Trace },
860+
"Peer is on different chain (our genesis: {} theirs: {})",
861+
self.genesis_hash, status.genesis_hash
862+
);
863+
self.peerset_handle.report_peer(who.clone(), rep::GENESIS_MISMATCH);
864+
self.behaviour.disconnect_peer(&who);
874865

875-
return CustomMessageOutcome::None;
876-
}
877-
if status.version < MIN_VERSION && CURRENT_VERSION < status.min_supported_version {
878-
log!(
866+
if self.boot_node_ids.contains(&who) {
867+
error!(
879868
target: "sync",
880-
if self.important_peers.contains(&who) { Level::Warn } else { Level::Trace },
881-
"Peer {:?} using unsupported protocol version {}", who, status.version
869+
"Bootnode with peer id `{}` is on a different chain (our genesis: {} theirs: {})",
870+
who,
871+
self.genesis_hash,
872+
status.genesis_hash,
882873
);
883-
self.peerset_handle.report_peer(who.clone(), rep::BAD_PROTOCOL);
884-
self.behaviour.disconnect_peer(&who);
885-
return CustomMessageOutcome::None;
886874
}
887875

888-
if self.config.roles.is_light() {
889-
// we're not interested in light peers
890-
if status.roles.is_light() {
891-
debug!(target: "sync", "Peer {} is unable to serve light requests", who);
892-
self.peerset_handle.report_peer(who.clone(), rep::BAD_ROLE);
893-
self.behaviour.disconnect_peer(&who);
894-
return CustomMessageOutcome::None;
895-
}
876+
return CustomMessageOutcome::None;
877+
}
896878

897-
// we don't interested in peers that are far behind us
898-
let self_best_block = self
899-
.context_data
900-
.chain
901-
.info()
902-
.best_number;
903-
let blocks_difference = self_best_block
904-
.checked_sub(&status.best_number)
905-
.unwrap_or_else(Zero::zero)
906-
.saturated_into::<u64>();
907-
if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE {
908-
debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who);
909-
self.peerset_handle.report_peer(who.clone(), rep::PEER_BEHIND_US_LIGHT);
910-
self.behaviour.disconnect_peer(&who);
911-
return CustomMessageOutcome::None;
912-
}
879+
if self.config.roles.is_light() {
880+
// we're not interested in light peers
881+
if status.roles.is_light() {
882+
debug!(target: "sync", "Peer {} is unable to serve light requests", who);
883+
self.peerset_handle.report_peer(who.clone(), rep::BAD_ROLE);
884+
self.behaviour.disconnect_peer(&who);
885+
return CustomMessageOutcome::None;
913886
}
914887

915-
let peer = Peer {
916-
info: PeerInfo {
917-
protocol_version: status.version,
918-
roles: status.roles,
919-
best_hash: status.best_hash,
920-
best_number: status.best_number
921-
},
922-
block_request: None,
923-
known_transactions: LruHashSet::new(NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS)
924-
.expect("Constant is nonzero")),
925-
known_blocks: LruHashSet::new(NonZeroUsize::new(MAX_KNOWN_BLOCKS)
926-
.expect("Constant is nonzero")),
927-
next_request_id: 0,
928-
obsolete_requests: HashMap::new(),
929-
};
930-
self.context_data.peers.insert(who.clone(), peer);
888+
// we don't interested in peers that are far behind us
889+
let self_best_block = self
890+
.context_data
891+
.chain
892+
.info()
893+
.best_number;
894+
let blocks_difference = self_best_block
895+
.checked_sub(&status.best_number)
896+
.unwrap_or_else(Zero::zero)
897+
.saturated_into::<u64>();
898+
if blocks_difference > LIGHT_MAXIMAL_BLOCKS_DIFFERENCE {
899+
debug!(target: "sync", "Peer {} is far behind us and will unable to serve light requests", who);
900+
self.peerset_handle.report_peer(who.clone(), rep::PEER_BEHIND_US_LIGHT);
901+
self.behaviour.disconnect_peer(&who);
902+
return CustomMessageOutcome::None;
903+
}
904+
}
931905

932-
debug!(target: "sync", "Connected {}", who);
933-
status.version
906+
let peer = Peer {
907+
info: PeerInfo {
908+
roles: status.roles,
909+
best_hash: status.best_hash,
910+
best_number: status.best_number
911+
},
912+
block_request: None,
913+
known_transactions: LruHashSet::new(NonZeroUsize::new(MAX_KNOWN_TRANSACTIONS)
914+
.expect("Constant is nonzero")),
915+
known_blocks: LruHashSet::new(NonZeroUsize::new(MAX_KNOWN_BLOCKS)
916+
.expect("Constant is nonzero")),
917+
next_request_id: 0,
918+
obsolete_requests: HashMap::new(),
934919
};
920+
self.context_data.peers.insert(who.clone(), peer);
921+
922+
debug!(target: "sync", "Connected {}", who);
935923

936924
let info = self.context_data.peers.get(&who).expect("We just inserted above; QED").info.clone();
937925
self.pending_messages.push_back(CustomMessageOutcome::PeerNewBest(who.clone(), status.best_number));
@@ -1161,20 +1149,12 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
11611149
if inserted || force {
11621150
let message = message::BlockAnnounce {
11631151
header: header.clone(),
1164-
state: if peer.info.protocol_version >= 4 {
1165-
if is_best {
1166-
Some(message::BlockState::Best)
1167-
} else {
1168-
Some(message::BlockState::Normal)
1169-
}
1170-
} else {
1171-
None
1172-
},
1173-
data: if peer.info.protocol_version >= 4 {
1174-
Some(data.clone())
1152+
state: if is_best {
1153+
Some(message::BlockState::Best)
11751154
} else {
1176-
None
1155+
Some(message::BlockState::Normal)
11771156
},
1157+
data: Some(data.clone()),
11781158
};
11791159

11801160
self.behaviour.write_notification(
@@ -1620,9 +1600,20 @@ impl<B: BlockT, H: ExHashT> NetworkBehaviour for Protocol<B, H> {
16201600

16211601
let outcome = match event {
16221602
GenericProtoOut::CustomProtocolOpen { peer_id, received_handshake, notifications_sink, .. } => {
1623-
match <Message<B> as Decode>::decode(&mut &received_handshake[..]) {
1624-
Ok(GenericMessage::Status(handshake)) =>
1625-
self.on_peer_connected(peer_id, handshake, notifications_sink),
1603+
// `received_handshake` can be either a `Status` message if received from the
1604+
// legacy substream ,or a `BlockAnnouncesHandshake` if received from the block
1605+
// announces substream.
1606+
match <Message<B> as DecodeAll>::decode_all(&mut &received_handshake[..]) {
1607+
Ok(GenericMessage::Status(handshake)) => {
1608+
let handshake = BlockAnnouncesHandshake {
1609+
roles: handshake.roles,
1610+
best_number: handshake.best_number,
1611+
best_hash: handshake.best_hash,
1612+
genesis_hash: handshake.genesis_hash,
1613+
};
1614+
1615+
self.on_peer_connected(peer_id, handshake, notifications_sink)
1616+
},
16261617
Ok(msg) => {
16271618
debug!(
16281619
target: "sync",
@@ -1634,15 +1625,23 @@ impl<B: BlockT, H: ExHashT> NetworkBehaviour for Protocol<B, H> {
16341625
CustomMessageOutcome::None
16351626
}
16361627
Err(err) => {
1637-
debug!(
1638-
target: "sync",
1639-
"Couldn't decode handshake sent by {}: {:?}: {}",
1640-
peer_id,
1641-
received_handshake,
1642-
err.what()
1643-
);
1644-
self.peerset_handle.report_peer(peer_id, rep::BAD_MESSAGE);
1645-
CustomMessageOutcome::None
1628+
match <BlockAnnouncesHandshake<B> as DecodeAll>::decode_all(&mut &received_handshake[..]) {
1629+
Ok(handshake) => {
1630+
self.on_peer_connected(peer_id, handshake, notifications_sink)
1631+
}
1632+
Err(err2) => {
1633+
debug!(
1634+
target: "sync",
1635+
"Couldn't decode handshake sent by {}: {:?}: {} & {}",
1636+
peer_id,
1637+
received_handshake,
1638+
err.what(),
1639+
err2,
1640+
);
1641+
self.peerset_handle.report_peer(peer_id, rep::BAD_MESSAGE);
1642+
CustomMessageOutcome::None
1643+
}
1644+
}
16461645
}
16471646
}
16481647
}

client/network/src/protocol/generic_proto/behaviour.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,14 +336,21 @@ impl GenericProto {
336336
versions: &[u8],
337337
handshake_message: Vec<u8>,
338338
peerset: sc_peerset::Peerset,
339+
notif_protocols: impl Iterator<Item = (Cow<'static, str>, Vec<u8>)>,
339340
) -> Self {
341+
let notif_protocols = notif_protocols
342+
.map(|(n, hs)| (n, Arc::new(RwLock::new(hs))))
343+
.collect::<Vec<_>>();
344+
345+
assert!(!notif_protocols.is_empty());
346+
340347
let legacy_handshake_message = Arc::new(RwLock::new(handshake_message));
341348
let legacy_protocol = RegisteredProtocol::new(protocol, versions, legacy_handshake_message);
342349

343350
GenericProto {
344351
local_peer_id,
345352
legacy_protocol,
346-
notif_protocols: Vec::new(),
353+
notif_protocols,
347354
peerset,
348355
peers: FnvHashMap::default(),
349356
delays: Default::default(),

0 commit comments

Comments
 (0)