Skip to content

Commit 5666d88

Browse files
committed
Cleanup
1 parent 0141c64 commit 5666d88

11 files changed

Lines changed: 71 additions & 62 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,10 @@ The format is loosely based on [Keep a Changelog](https://keepachangelog.com/en/
6868
- Node bootstrapping:
6969
- The format of the bootstrap file was changed and the legacy format is no longer supported.
7070

71+
- P2p:
72+
- The logic of initiating new outbound connections has been improved to prevent the node from
73+
constantly attempting to re-establish a connection with a peer that has banned it.
74+
7175
### Fixed
7276
- P2p: when a peer sends a message that can't be decoded, it will now be discouraged (which is what
7377
is normally done for misbehaving peers) and the node won't try connecting to it again.\

p2p/src/net/default_backend/peer.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -424,8 +424,6 @@ where
424424
.await?
425425
}
426426
CategorizedMessage::BlockSyncMessage(msg) => {
427-
block_sync_msg_sender.send(msg).await?;
428-
429427
if !self.sync_message_received {
430428
self.peer_event_sender
431429
.send(PeerEvent::MessageReceived(
@@ -434,10 +432,10 @@ where
434432
.await?;
435433
self.sync_message_received = true;
436434
}
435+
436+
block_sync_msg_sender.send(msg).await?;
437437
}
438438
CategorizedMessage::TransactionSyncMessage(msg) => {
439-
transaction_sync_msg_sender.send(msg).await?;
440-
441439
if !self.sync_message_received {
442440
self.peer_event_sender
443441
.send(PeerEvent::MessageReceived(
@@ -446,6 +444,8 @@ where
446444
.await?;
447445
self.sync_message_received = true;
448446
}
447+
448+
transaction_sync_msg_sender.send(msg).await?;
449449
}
450450
}
451451

p2p/src/net/types.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,10 @@ impl PeerRole {
6262
pub fn as_outbound(&self) -> Option<OutboundPeerRole> {
6363
match self {
6464
Self::Inbound => None,
65-
Self::OutboundFullRelay => Some(OutboundPeerRole::OutboundFullRelay),
66-
Self::OutboundBlockRelay => Some(OutboundPeerRole::OutboundBlockRelay),
67-
Self::OutboundReserved => Some(OutboundPeerRole::OutboundReserved),
68-
Self::OutboundManual => Some(OutboundPeerRole::OutboundManual),
65+
Self::OutboundFullRelay => Some(OutboundPeerRole::FullRelay),
66+
Self::OutboundBlockRelay => Some(OutboundPeerRole::BlockRelay),
67+
Self::OutboundReserved => Some(OutboundPeerRole::Reserved),
68+
Self::OutboundManual => Some(OutboundPeerRole::Manual),
6969
Self::Feeler => Some(OutboundPeerRole::Feeler),
7070
}
7171
}
@@ -88,13 +88,35 @@ impl PeerRole {
8888

8989
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, strum::EnumIter)]
9090
pub enum OutboundPeerRole {
91-
OutboundFullRelay,
92-
OutboundBlockRelay,
93-
OutboundReserved,
94-
OutboundManual,
91+
FullRelay,
92+
BlockRelay,
93+
Reserved,
94+
Manual,
9595
Feeler,
9696
}
9797

98+
impl OutboundPeerRole {
99+
/// Return true if for this connection type some message exchange is expected (besides
100+
/// the handshake and WillDisconnect), i.e. the node is supposed to send at least one message
101+
/// and get back a response.
102+
///
103+
/// This is used by peerdb's AddressData to determine whether the "no activity" counter
104+
/// should be increased after a connection with no peer activity.
105+
pub fn is_message_exchange_expected(&self) -> bool {
106+
match self {
107+
Self::FullRelay | Self::BlockRelay | Self::Reserved | Self::Manual => true,
108+
Self::Feeler => false,
109+
}
110+
}
111+
112+
pub fn is_manual(&self) -> bool {
113+
match self {
114+
Self::Manual => true,
115+
| Self::FullRelay | Self::BlockRelay | Self::Reserved | Self::Feeler => false,
116+
}
117+
}
118+
}
119+
98120
/// Peer information learned during handshaking
99121
///
100122
/// When an inbound/outbound connection succeeds, the networking service handshakes with the remote

p2p/src/peer_manager/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,6 +1552,7 @@ where
15521552
);
15531553
if let Some(address) = address_opt {
15541554
log::debug!("Need to establish a feeler connection to address {address}");
1555+
15551556
self.connect(address, OutboundConnectType::Feeler);
15561557
self.next_feeler_connection_time = Self::choose_next_feeler_connection_time(
15571558
&self.p2p_config,
@@ -1581,7 +1582,7 @@ where
15811582
// just in case, so that if things go horribly wrong, only the debug build will panic.
15821583
if let Some(peer) = self.peers.get(&peer_id) {
15831584
if !is_disconnection_message && peer.peer_role.is_outbound() {
1584-
self.peerdb.outbound_peer_has_activity(
1585+
self.peerdb.outbound_peer_had_activity(
15851586
peer.peer_address,
15861587
Self::lock_rng(&self.rng).deref_mut(),
15871588
);

p2p/src/peer_manager/peerdb/address_data/mod.rs

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub enum AddressState {
8181
#[strum_discriminants(name(AddressStateTransitionToTag), derive(strum::EnumIter))]
8282
pub enum AddressStateTransitionTo {
8383
Connected { peer_role: OutboundPeerRole },
84-
HasActivity,
84+
HadActivity,
8585
Disconnected,
8686
ConnectionFailed,
8787
SetReserved,
@@ -239,7 +239,7 @@ impl AddressData {
239239
}
240240
},
241241

242-
AddressStateTransitionTo::HasActivity => match self.state {
242+
AddressStateTransitionTo::HadActivity => match self.state {
243243
AddressState::Connected {
244244
had_activity: _,
245245
peer_role,
@@ -253,13 +253,13 @@ impl AddressData {
253253
was_reachable: _,
254254
} => {
255255
debug_panic_or_log!(
256-
"Unexpected address state transition: Disconnected -> HasActivity"
256+
"Unexpected address state transition: Disconnected -> HadActivity"
257257
);
258258
self.state.clone()
259259
}
260260
AddressState::Unreachable { erase_after: _ } => {
261261
debug_panic_or_log!(
262-
"Unexpected address state transition: Unreachable -> HasActivity"
262+
"Unexpected address state transition: Unreachable -> HadActivity"
263263
);
264264
self.state.clone()
265265
}
@@ -273,19 +273,20 @@ impl AddressData {
273273
if had_activity {
274274
self.connections_without_activity_count = 0;
275275
} else {
276-
// We don't increase the counter for:
277-
// 1) feeler connections (because it gets disconnected immediately, so the peer may
278-
// not have the chance to send us anything);
279-
// 2) manual connections;
280-
let is_regular_auto_connection = match peer_role {
281-
OutboundPeerRole::OutboundFullRelay
282-
| OutboundPeerRole::OutboundBlockRelay
283-
| OutboundPeerRole::OutboundReserved => true,
284-
285-
OutboundPeerRole::Feeler | OutboundPeerRole::OutboundManual => false,
286-
};
287-
288-
if is_regular_auto_connection {
276+
// Note:
277+
// 1) We don't increase the counter for manual connections.
278+
// 2) Since `is_message_exchange_expected` doesn't know the actual services
279+
// that the peer provides, it's technically possible to punish an
280+
// "innocent" peer here, e.g. when the connection type is supposed to involve
281+
// block exchange, but the peer's actual services don't include Blocks.
282+
// However:
283+
// a) The worst punishment it can get is that the next connection will be
284+
// postponed for (roughly) MAX_DELAY_REACHABLE, which is currently 1 hour.
285+
// b) Such a peer will be rather useless anyway.
286+
// c) The connection has to be short enough, so that even a single PingRequest message
287+
// (which requires a response) could not be sent.
288+
// So it's not a big deal.
289+
if peer_role.is_message_exchange_expected() && !peer_role.is_manual() {
289290
self.connections_without_activity_count += 1;
290291
}
291292
}

p2p/src/peer_manager/peerdb/address_data/tests.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ fn randomized(#[case] seed: Seed) {
5353
AddressStateTransitionToTag::Connected => AddressStateTransitionTo::Connected {
5454
peer_role: OutboundPeerRole::iter().choose(&mut rng).unwrap(),
5555
},
56-
AddressStateTransitionToTag::HasActivity => AddressStateTransitionTo::HasActivity,
56+
AddressStateTransitionToTag::HadActivity => AddressStateTransitionTo::HadActivity,
5757
AddressStateTransitionToTag::Disconnected => AddressStateTransitionTo::Disconnected,
5858
AddressStateTransitionToTag::ConnectionFailed => {
5959
AddressStateTransitionTo::ConnectionFailed
@@ -68,7 +68,7 @@ fn randomized(#[case] seed: Seed) {
6868
AddressStateTransitionTo::Connected { peer_role: _ } => {
6969
!address_data.is_connected()
7070
}
71-
AddressStateTransitionTo::HasActivity => address_data.is_connected(),
71+
AddressStateTransitionTo::HadActivity => address_data.is_connected(),
7272
AddressStateTransitionTo::Disconnected => address_data.is_connected(),
7373
AddressStateTransitionTo::ConnectionFailed => !address_data.is_connected(),
7474
AddressStateTransitionTo::SetReserved => true,

p2p/src/peer_manager/peerdb/mod.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,8 +425,8 @@ impl<S: PeerDbStorage> PeerDb<S> {
425425
}
426426

427427
/// Report that the peer has sent us a message other than the one indicating an intent to disconnect.
428-
pub fn outbound_peer_has_activity(&mut self, address: SocketAddress, rng: &mut impl Rng) {
429-
self.change_address_state(address, AddressStateTransitionTo::HasActivity, rng);
428+
pub fn outbound_peer_had_activity(&mut self, address: SocketAddress, rng: &mut impl Rng) {
429+
self.change_address_state(address, AddressStateTransitionTo::HadActivity, rng);
430430
}
431431

432432
pub fn remove_address(&mut self, address: &SocketAddress) {

p2p/src/peer_manager/tests/unsuccessful_connection_counter_update.rs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,9 @@ async fn auto_connection_fails_peer_state_becomes_disconnected(
286286
// Keep peer address's `was_reachable` field at false.
287287
// 3) Advance the time so that the corresponding connection would be attempted; make the
288288
// connection fail; check that the peer address state is now `Unreachable`.
289-
// 4) Check that no further connection attempts are made.
289+
// 4) Optionally, accept an inbound connection from the peer address; expect that it doesn't
290+
// affect the current address state.
291+
// 5) Check that no further connection attempts are made.
290292
#[tracing::instrument(skip(seed))]
291293
#[rstest]
292294
#[trace]
@@ -510,7 +512,6 @@ async fn manual_connection_fails(#[case] seed: Seed, #[values(false, true)] make
510512

511513
if make_reachable {
512514
let peer_discovery_time = time_getter.get_time_getter().get_time();
513-
514515
discover_peer(&peer_mgr_event_sender, peer_address, true).await;
515516

516517
let peer_addr_state =
@@ -609,7 +610,7 @@ async fn manual_connection_fails(#[case] seed: Seed, #[values(false, true)] make
609610
// Make the connection succeed and close it immediately; check that `connections_without_activity_count`
610611
// has been incremented.
611612
// 3) Occasionally, make a successful incoming or manual outgoing connection without peer activity, or an unsuccessful
612-
// manual outgoing one. Expect that this doesn't affect `connections_without_activity_count`.
613+
// manual outgoing connection. Expect that this doesn't affect `connections_without_activity_count`.
613614
// 4) On the final iteration make the peer actually send a message. Check that `connections_without_activity_count` has
614615
// been reset to zero.
615616
// Note that feeler connections are not checked in this test because once a feeler connection succeeds, it won't
@@ -765,7 +766,7 @@ async fn auto_connection_without_peer_activity(
765766

766767
// An inbound or manual connection without peer activity shouldn't affect connections_without_activity_count.
767768
// Same for a failed outbound connection.
768-
let extra_outboun_connection_failed = match rng.gen_range(0..4) {
769+
let extra_outbound_connection_failed = match rng.gen_range(0..4) {
769770
0 => {
770771
log::debug!("Accepting an extra inbound connection");
771772

@@ -816,7 +817,7 @@ async fn auto_connection_without_peer_activity(
816817
};
817818

818819
let expected_connections_without_activity_count = if is_last_iteration { 0 } else { i + 1 };
819-
let expected_fail_count = if extra_outboun_connection_failed {
820+
let expected_fail_count = if extra_outbound_connection_failed {
820821
1
821822
} else {
822823
0

p2p/src/peer_manager/tests/utils.rs

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ use crate::{
3434
types::{ConnectivityEvent, PeerInfo},
3535
},
3636
peer_manager::PeerManagerInterface,
37-
peer_manager_event::PeerDisconnectionDbAction,
3837
test_helpers::TEST_PROTOCOL_VERSION,
3938
tests::helpers::PeerManagerNotification,
4039
utils::oneshot_nofail,
@@ -299,25 +298,6 @@ pub fn start_manually_connecting(
299298
result_receiver
300299
}
301300

302-
pub fn disconnect_manually(
303-
peer_mgr_event_sender: &mpsc::UnboundedSender<PeerManagerEvent>,
304-
peer_id: PeerId,
305-
peerdb_action: PeerDisconnectionDbAction,
306-
) -> oneshot_nofail::Receiver<crate::Result<()>> {
307-
let (result_sender, result_receiver) = oneshot_nofail::channel();
308-
309-
peer_mgr_event_sender
310-
.send(PeerManagerEvent::Disconnect(
311-
peer_id,
312-
peerdb_action,
313-
None,
314-
result_sender,
315-
))
316-
.unwrap();
317-
318-
result_receiver
319-
}
320-
321301
pub async fn adjust_peer_score(
322302
peer_mgr_event_sender: &mpsc::UnboundedSender<PeerManagerEvent>,
323303
peer_id: PeerId,

p2p/src/tests/peer_mgr_events.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ enum TestParamForFirstSyncMessageReceivedMustBeSent {
6565
// is sent to the peer manager.
6666
// 1) Send a random message from the peer.
6767
// 2) If the sent message was a sync one, expect that `PeerManagerNotification::MessageReceived` is emitted with
68-
// message equal to `PeerManagerMessageExtTag::FirstSyncMessageReceived`. If the sent message was not a sync one,
68+
// the message equal to `PeerManagerMessageExtTag::FirstSyncMessageReceived`. If the sent message was not a sync one,
6969
// expect that no such notification is emitted.
7070
#[tracing::instrument(skip(seed))]
7171
#[rstest]
@@ -233,7 +233,7 @@ async fn first_sync_message_received_must_be_sent(
233233

234234
// Check that `PeerManagerMessageExt::FirstSyncMessageReceived` will be sent only once even if
235235
// many sync messages are received from the peer.
236-
// 1) Send a few HeaderListRequest and/or NewTransaction (legit messages that a peer can send
236+
// 1) Send a few `HeaderListRequest` and/or `NewTransaction` messages (i.e. some legit messages that a peer can send
237237
// in any number).
238238
// 2) Expect that only one `PeerManagerNotification::MessageReceived` with `PeerManagerMessageExtTag::FirstSyncMessageReceived`
239239
// is produced.

0 commit comments

Comments
 (0)