-
Notifications
You must be signed in to change notification settings - Fork 215
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 libp2p identify race #6573
base: develop
Are you sure you want to change the base?
Fix libp2p identify race #6573
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -44,7 +44,30 @@ func wrapHost(tb testing.TB, h host.Host) Host { | |||||
func TestServer(t *testing.T) { | ||||||
const limit = 1024 | ||||||
|
||||||
mesh, err := mocknet.FullMeshConnected(5) | ||||||
// Don't establish peer connections immediately. | ||||||
// If we make the nodes connect to each other right away, there | ||||||
// may be a problem with libp2p identify service. Namely, when a | ||||||
// connection to a peer is established, identify request is sent | ||||||
// to that peer, to which the peer sends identify response. Also, | ||||||
// when a new handler is added to the host via SetStreamHandler, | ||||||
// as it's done in p2p/server.Server, the identify response | ||||||
// message is pushed to the peers currently connected to this | ||||||
// node. | ||||||
// When a server is created immediately following a connection | ||||||
// from a peer, that peer may receive 2 identify response messages | ||||||
// in quick succession: one which is indeed the response to | ||||||
// initial identify request, and one which is push message | ||||||
// generated by creation of the server. In some cases, the initial | ||||||
// response may not contain the protocol of the freshly added | ||||||
// server (hashProtocol="hs/1" in this case). | ||||||
// The identify response message sent when SetStreamHandler is | ||||||
// called will always contain the protocol being added, but due to | ||||||
// how libp2p works, the responses may be processed in reverse | ||||||
// order, and the set of protocols from the initial message will | ||||||
// override the set of protocols in the second mesage (from | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NIT: typo
Suggested change
|
||||||
// SetStreamHandler). In this case, the peer will have a wrong | ||||||
// idea about this node's protocols, and the test may fail. | ||||||
mesh, err := mocknet.FullMeshLinked(5) | ||||||
Comment on lines
+47
to
+70
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about putting these comments as a doc on the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||||||
require.NoError(t, err) | ||||||
proto := "test" | ||||||
request := []byte("test request") | ||||||
|
@@ -121,6 +144,10 @@ func TestServer(t *testing.T) { | |||||
eg.Wait() | ||||||
}) | ||||||
|
||||||
// Connect the P2P mesh only after the servers are configured. | ||||||
// This way, we avoid the race causing bad protocol identification. | ||||||
require.NoError(t, mesh.ConnectAllButSelf()) | ||||||
|
||||||
t.Run("ReceiveMessage", func(t *testing.T) { | ||||||
n := srvs[0].NumAcceptedRequests() | ||||||
srvID := mesh.Hosts()[1].ID() | ||||||
|
@@ -212,7 +239,7 @@ func TestServer(t *testing.T) { | |||||
} | ||||||
|
||||||
func Test_Queued(t *testing.T) { | ||||||
mesh, err := mocknet.FullMeshConnected(2) | ||||||
mesh, err := mocknet.FullMeshLinked(2) | ||||||
require.NoError(t, err) | ||||||
|
||||||
var ( | ||||||
|
@@ -245,6 +272,8 @@ func Test_Queued(t *testing.T) { | |||||
t.Cleanup(func() { | ||||||
assert.NoError(t, eg.Wait()) | ||||||
}) | ||||||
require.NoError(t, mesh.ConnectAllButSelf()) | ||||||
|
||||||
var reqEq errgroup.Group | ||||||
for i := 0; i < queueSize; i++ { // fill the queue with requests | ||||||
reqEq.Go(func() error { | ||||||
|
@@ -266,7 +295,7 @@ func Test_Queued(t *testing.T) { | |||||
} | ||||||
|
||||||
func Test_RequestInterval(t *testing.T) { | ||||||
mesh, err := mocknet.FullMeshConnected(2) | ||||||
mesh, err := mocknet.FullMeshLinked(2) | ||||||
require.NoError(t, err) | ||||||
|
||||||
var ( | ||||||
|
@@ -295,6 +324,7 @@ func Test_RequestInterval(t *testing.T) { | |||||
t.Cleanup(func() { | ||||||
assert.NoError(t, eg.Wait()) | ||||||
}) | ||||||
require.NoError(t, mesh.ConnectAllButSelf()) | ||||||
|
||||||
start := time.Now() | ||||||
for i := 0; i < maxReq; i++ { // fill the interval with requests (bursts up to maxReq are allowed) | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this:
has basically the same effect without a) needing to intercept the building process of the
libp2p
host and b) allowing us to pass a timeout toConnect
in case we want to abort early if something goes wrong.Connect
in both implementations ofHost
eventually callsIdentifyWait
which is also called byIdentifyCon
but allows passing a context in case we want to abort early.Wdyt?