-
Notifications
You must be signed in to change notification settings - Fork 214
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
[Merged by Bors] - Fix libp2p identify race #6573
Conversation
c72d92c
to
119c374
Compare
Codecov ReportAttention: Patch coverage is
✅ All tests successful. No failed tests found.
Additional details and impacted files@@ Coverage Diff @@
## develop #6573 +/- ##
=========================================
- Coverage 79.9% 79.9% -0.1%
=========================================
Files 356 356
Lines 47357 47399 +42
=========================================
+ Hits 37879 37880 +1
- Misses 7342 7369 +27
- Partials 2136 2150 +14 ☔ View full report in Codecov by Sentry. |
When a P2P test is set up using `mocknet.FullMeshConnected(...)` and then calls `p2p/server.New(...)`, there's a possible race due to how `libp2p` `identify` service works. Namely, when a new peer connects, an active `identify` request is initiated towards it asking in particular what protocols does the peer support, to which the peer must reply with an identify response message. Also, when `SetStreamHandler` is called, an identify response message is pushed towards the currently connected peers. In some cases, the following race is possible: 1. Peer `A` connects to peer `B`. 2. Peer `B` sends identify request to peer `A`. 3. Peer `A` sends response to the identify request from peer `A`. This response contains the list of protocols, but that list misses the protocol which is used for `Server` in p.4, b/c `Server` is not set up yet. 4. Peer `A` sets up a `Server` which uses `SetStreamHandler`, and at this point peer `A` sends pushes an identify response message to peer `B`, _without_ corresponding identify request. 5. Peer `B` receives pushed identify response from `A` which is sent in p.4, despite it being sent after the response in p.3. This may happen due to how `libp2p` handles incoming requests. Peer `B` sets the supported protocols in its `ProtoBook` for peer `A`, the list of protocols now contains the protocol specfied for the `Server` in p.4. 6. Peer `B` receives identify response from `A` which was sent in p.3, despite it being sent before p.4, due to possible reordering. This response also has a list of protocols, but it misses the protocol specified for the `Server` in p.4. Peer `B` again sets the supported protocols in its `ProtoBook` for peer `A`, but now that list misses the necessary protocol. 7. Peer `B` tries to find peers which support the protocol used for the `Server` in p.4, or connect to peer `B` using that protocol. This fails b/c `ProtoBook` entry for peer `A` contains wrong protocol list. In addition to this, there's an issue with protocol support checks which `Fetcher` does to check which peers it can retrieve data from. When a peer is freshly connected, the active identify request towards it may not be finished yet when the fetcher tries to check that peer. Although unlikely, in some cases this may cause valid peers to get ignored. This change removes the instances of use of `mocknet.FullMeshConnected(...)` where it may cause identify race, replacing it with `mocknet.FullMeshLinked(...)` followed by `mesh.ConnectAllButSelf()` after the `Server`s are set up. It also fixes fetcher peer selection mechanism so it waits for any pending identification request to finish, similar how to `Host.NewStream` does that.
119c374
to
54840f8
Compare
bors merge |
## Motivation This supersedes #6570 When a P2P test is set up using `mocknet.FullMeshConnected(...)` and then calls `p2p/server.New(...)`, there's a possible race due to how `libp2p` `identify` service works. Namely, when a new peer connects, an active `identify` request is initiated towards it asking in particular what protocols does the peer support, to which the peer must reply with an identify response message. Also, when `SetStreamHandler` is called, an identify response message is pushed towards the currently connected peers. In some cases, the following race is possible: 1. Peer `A` connects to peer `B`. 2. Peer `B` sends identify request to peer `A`. 3. Peer `A` sends response to the identify request from peer `A`. This response contains the list of protocols, but that list misses the protocol which is used for `Server` in p.4, b/c `Server` is not set up yet. 4. Peer `A` sets up a `Server` which uses `SetStreamHandler`, and at this point peer `A` sends pushes an identify response message to peer `B`, _without_ corresponding identify request. 5. Peer `B` receives pushed identify response from `A` which is sent in p.4, despite it being sent after the response in p.3. This may happen due to how `libp2p` handles incoming requests. Peer `B` sets the supported protocols in its `ProtoBook` for peer `A`, the list of protocols now contains the protocol specfied for the `Server` in p.4. 6. Peer `B` receives identify response from `A` which was sent in p.3, despite it being sent before p.4, due to possible reordering. This response also has a list of protocols, but it misses the protocol specified for the `Server` in p.4. Peer `B` again sets the supported protocols in its `ProtoBook` for peer `A`, but now that list misses the necessary protocol. 7. Peer `B` tries to find peers which support the protocol used for the `Server` in p.4, or connect to peer `B` using that protocol. This fails b/c `ProtoBook` entry for peer `A` contains wrong protocol list. In addition to this, there's an issue with protocol support checks which `Fetcher` does to check which peers it can retrieve data from. When a peer is freshly connected, the active identify request towards it may not be finished yet when the fetcher tries to check that peer. Although unlikely, in some cases this may cause valid peers to get ignored.
Build failed: |
|
bors merge |
## Motivation This supersedes #6570 When a P2P test is set up using `mocknet.FullMeshConnected(...)` and then calls `p2p/server.New(...)`, there's a possible race due to how `libp2p` `identify` service works. Namely, when a new peer connects, an active `identify` request is initiated towards it asking in particular what protocols does the peer support, to which the peer must reply with an identify response message. Also, when `SetStreamHandler` is called, an identify response message is pushed towards the currently connected peers. In some cases, the following race is possible: 1. Peer `A` connects to peer `B`. 2. Peer `B` sends identify request to peer `A`. 3. Peer `A` sends response to the identify request from peer `A`. This response contains the list of protocols, but that list misses the protocol which is used for `Server` in p.4, b/c `Server` is not set up yet. 4. Peer `A` sets up a `Server` which uses `SetStreamHandler`, and at this point peer `A` sends pushes an identify response message to peer `B`, _without_ corresponding identify request. 5. Peer `B` receives pushed identify response from `A` which is sent in p.4, despite it being sent after the response in p.3. This may happen due to how `libp2p` handles incoming requests. Peer `B` sets the supported protocols in its `ProtoBook` for peer `A`, the list of protocols now contains the protocol specfied for the `Server` in p.4. 6. Peer `B` receives identify response from `A` which was sent in p.3, despite it being sent before p.4, due to possible reordering. This response also has a list of protocols, but it misses the protocol specified for the `Server` in p.4. Peer `B` again sets the supported protocols in its `ProtoBook` for peer `A`, but now that list misses the necessary protocol. 7. Peer `B` tries to find peers which support the protocol used for the `Server` in p.4, or connect to peer `B` using that protocol. This fails b/c `ProtoBook` entry for peer `A` contains wrong protocol list. In addition to this, there's an issue with protocol support checks which `Fetcher` does to check which peers it can retrieve data from. When a peer is freshly connected, the active identify request towards it may not be finished yet when the fetcher tries to check that peer. Although unlikely, in some cases this may cause valid peers to get ignored.
Pull request successfully merged into develop. Build succeeded: |
Motivation
This supersedes #6570
When a P2P test is set up using
mocknet.FullMeshConnected(...)
and then callsp2p/server.New(...)
, there's a possible race due to howlibp2p
identify
service works. Namely, when a new peer connects, an activeidentify
request is initiated towards it asking in particular what protocols does the peer support, to which the peer must reply with an identify response message. Also, whenSetStreamHandler
is called, an identify response message is pushed towards the currently connected peers. In some cases, the following race is possible:A
connects to peerB
.B
sends identify request to peerA
.A
sends response to the identify request from peerA
. This response contains the list of protocols, but that list misses the protocol which is used forServer
in p.4, b/cServer
is not set up yet.A
sets up aServer
which usesSetStreamHandler
, and at this point peerA
sends pushes an identify response message to peerB
, without corresponding identify request.B
receives pushed identify response fromA
which is sent in p.4, despite it being sent after the response in p.3. This may happen due to howlibp2p
handles incoming requests. PeerB
sets the supported protocols in itsProtoBook
for peerA
, the list of protocols now contains the protocol specfied for theServer
in p.4.B
receives identify response fromA
which was sent in p.3, despite it being sent before p.4, due to possible reordering. This response also has a list of protocols, but it misses the protocol specified for theServer
in p.4. PeerB
again sets the supported protocols in itsProtoBook
for peerA
, but now that list misses the necessary protocol.B
tries to find peers which support the protocol used for theServer
in p.4, or connect to peerB
using that protocol. This fails b/cProtoBook
entry for peerA
contains wrong protocol list.In addition to this, there's an issue with protocol support checks which
Fetcher
does to check which peers it can retrieve data from. When a peer is freshly connected, the active identify request towards it may not be finished yet when the fetcher tries to check that peer. Although unlikely, in some cases this may cause valid peers to get ignored.Description
This change removes the instances of use of
mocknet.FullMeshConnected(...)
where it may cause identify race, replacing it withmocknet.FullMeshLinked(...)
followed bymesh.ConnectAllButSelf()
after theServer
s are set up. It also fixes fetcher peer selection mechanism so it waits for any pending identification request to finish, similar how toHost.NewStream
does that.Previously, in some tests there was a check for protocol list contents in some tests, but it worked mostly by chance, and now is replaced with delayed mesh connection.
Test Plan
Make sure the tests pass.