Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix starting requests on shutting down connections #2847

Merged
merged 6 commits into from
Oct 11, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bin/full-node/src/run/network_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,7 +555,7 @@ impl NetworkService {

// The call to `send_block_announce` below panics if we have no active connection.
// TODO: not the correct check; must make sure that we have a substream open
if !guarded.network.has_established_connection(target) {
if !guarded.network.can_send_requests(target) {
return Err(QueueNotificationError::NoConnection);
}

Expand Down Expand Up @@ -624,7 +624,7 @@ impl NetworkService {
let mut guarded = self.inner.guarded.lock().await;

// The call to `start_blocks_request` below panics if we have no active connection.
if !guarded.network.has_established_connection(&target) {
if !guarded.network.can_send_requests(&target) {
return Err(BlocksRequestError::NoConnection);
}

Expand Down
10 changes: 5 additions & 5 deletions bin/light-base/src/network_service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ impl<TPlat: Platform> NetworkService<TPlat> {
let mut guarded = self.shared.guarded.lock().await;

// The call to `start_blocks_request` below panics if we have no active connection.
if !guarded.network.has_established_connection(&target) {
if !guarded.network.can_send_requests(&target) {
return Err(BlocksRequestError::NoConnection);
}

Expand Down Expand Up @@ -490,7 +490,7 @@ impl<TPlat: Platform> NetworkService<TPlat> {

// The call to `start_grandpa_warp_sync_request` below panics if we have no
// active connection.
if !guarded.network.has_established_connection(&target) {
if !guarded.network.can_send_requests(&target) {
return Err(GrandpaWarpSyncRequestError::NoConnection);
}

Expand Down Expand Up @@ -593,7 +593,7 @@ impl<TPlat: Platform> NetworkService<TPlat> {

// The call to `start_storage_proof_request` below panics if we have no active
// connection.
if !guarded.network.has_established_connection(&target) {
if !guarded.network.can_send_requests(&target) {
return Err(StorageProofRequestError::NoConnection);
}

Expand Down Expand Up @@ -663,7 +663,7 @@ impl<TPlat: Platform> NetworkService<TPlat> {
let mut guarded = self.shared.guarded.lock().await;

// The call to `start_call_proof_request` below panics if we have no active connection.
if !guarded.network.has_established_connection(&target) {
if !guarded.network.can_send_requests(&target) {
return Err(CallProofRequestError::NoConnection);
}

Expand Down Expand Up @@ -772,7 +772,7 @@ impl<TPlat: Platform> NetworkService<TPlat> {

// The call to `send_block_announce` below panics if we have no active connection.
// TODO: not the correct check; must make sure that we have a substream open
if !guarded.network.has_established_connection(target) {
if !guarded.network.can_send_requests(target) {
return Err(QueueNotificationError::NoConnection);
}

Expand Down
1 change: 1 addition & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

### Fixed

- Fix smoldot trying to send requests to peers whose connection is shutting down, leading to a panic. ([#2847](https://github.com/paritytech/smoldot/pull/2847))
- Fix the responses to libp2p identify requests being wrongly empty. ([#2840](https://github.com/paritytech/smoldot/pull/2840))
- Fix some Merkle proofs and SCALE-encoded structures being accepted as correct when they are actually invalid. This is a very minor fix that can presumably not be used as an attack vector. ([#2819](https://github.com/paritytech/smoldot/pull/2819))

Expand Down
17 changes: 16 additions & 1 deletion src/libp2p/peers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1386,7 +1386,8 @@ where
/// # Panic
///
/// Panics if `protocol_index` isn't a valid index in [`Config::request_response_protocols`].
/// Panics if there is no open connection with the target.
/// Panics if there is no open connection with the target or if all connections are shutting
/// down. Use [`Peers::can_send_requests`] to check if this is the case.
///
#[track_caller]
pub fn start_request(
Expand All @@ -1409,6 +1410,20 @@ where
))
}

/// Returns `true` if if it possible to send requests (i.e. through [`Peers::start_request`])
/// to the given peer.
///
/// If `false` is returned, then starting a request will panic.
///
/// In other words, returns `true` if there exists an established connection non-shutting-down
/// connection with the given peer.
pub fn can_send_requests(&self, peer_id: &PeerId) -> bool {
self.established_peer_connections(peer_id)
.filter(|c| !self.connection_state(*c).shutting_down)
.count()
!= 0
}

/// Responds to a previously-emitted [`Event::RequestIn`].
///
/// # Panic
Expand Down
14 changes: 10 additions & 4 deletions src/network/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2298,10 +2298,16 @@ where
None
}

/// Returns `true` if there exists an established connection with the given peer.
// TODO: revisit this API w.r.t. shutdowns
pub fn has_established_connection(&self, peer_id: &PeerId) -> bool {
self.inner.established_peer_connections(peer_id).count() != 0
/// Returns `true` if if it possible to send requests (i.e. through
/// [`ChainNetwork::start_grandpa_warp_sync_request`],
/// [`ChainNetwork::start_blocks_request`], etc.) to the given peer.
///
/// If `false` is returned, starting a request will panic.
///
/// In other words, returns `true` if there exists an established connection non-shutting-down
/// connection with the given peer.
pub fn can_send_requests(&self, peer_id: &PeerId) -> bool {
self.inner.can_send_requests(peer_id)
}

/// Returns an iterator to the list of [`PeerId`]s that we have an established connection
Expand Down