-
Notifications
You must be signed in to change notification settings - Fork 1
fix: use correct id sequence (dialer even/listener odd) #3
Conversation
Crap. I now finally know why this protocol has separate tags for messages from the initiator and the receiver but have no idea why Go and JS can even talk to each other. Go does use odd numbers. It looks like the original protocol didn't specify odd/even stream IDs. Instead, each endpoint had two separate sets of streams, ones that the endpoint initiated and ones that the endpoint received. That's why there are two different message tags for each type of message. Sending a message with the It looks like JS does this so, really, the even-odd distinction shouldn't make a difference there but go doesn't. So, I'd expect streams from Go to JS to work but not the other way around. I'll chat with @diasdavid about this. |
yeah, actually it looks like it doesn't care about even/odd ids at all and for some reason it would just always use even ids for initiators in the original implementation - https://github.com/maxogden/multiplex/blob/master/index.js#L162...L164 We might have introduced the the even/odd numbering when porting that over to libp2p, but it still doesn't matter since we keep two separate lists for initiators and receivers, which are selected based on the tag type - https://github.com/libp2p/js-libp2p-mplex/blob/master/src/internals/index.js#L199. The reason it works, seems to be because the tag eve/odd'nes matches - https://github.com/libp2p/go-mplex/blob/master/multiplex.go#L36...L42, odd for initiator, even for receiver, which is reversed again from the id numbering 🙃 |
....? I'd expect that to break it completely... Luckily, we only use this for go/js interop so simply fix the spec and the go implementation (don't care about go/go interop). So, spec updates:
Does the session (not stream) initiator even matter? |
I think there was a misunderstanding, the go tags are correct, the IDs were reversed. But the IDs didn't affect anything in js because it uses the tag to select the list where to look the stream in. That said, I like the even/odd Id distinction because it allows to use the same list without clashing. |
@dryajov you might have found the reason why DHT interop breaks. Could you had a set of tests to interop that actively test the creation of multiple muxed streams (lots of different bitswap, ping, dht and other streams?) |
It doesn't matter unless we care about the Id even/oddess. I think the original intent with that was precisely not having to use two lists, but it probably changed during implementation and the initator flag was left kinda dangling. |
So, I would still like to keep even/odd numbering of steams - even for initiator odd for receiver, same as the tags. It would keep it backwards compatible with the original js implementation, and fixing the ids would make it work with the new pull-stream implementation https://github.com/dryajov/pull-plex. So the changes to the spec would be:
|
With respect to the even/odd IDs, I'm pretty sure the none of the JS implementations relied on this at any point (the current version uses even/odd IDs but still stores the streams in separate tables). I can make the go implementation use even IDs for the initiator but I don't think there's much of a reason to do so (and, on go at least, it won't simplify anything). |
See: libp2p/mplex#3 (massive thanks to @dyajov for finding this)
Fix here (without the alternating stream IDs for now): libp2p/go-mplex#26 Can someone test it? |
I'll give it a go.
Fair enough - it changes little on my side as well. |
@dryajov I've written a short interop test (checked into that branch) and everything appears to work. I believe the new update to the spec will be:
|
@Stebalien LGTM! Thanks for the interop, I'll try it out with my new implementation as well 👍 |
remove mention of even/odd id numbering
@Stebalien I've added the clarification to the spec. |
README.md
Outdated
@@ -52,13 +52,13 @@ necessarily send the first packet, this distinction is just made to make the all | |||
|
|||
### Opening a new stream | |||
|
|||
To open a new stream, first allocate a new unique stream ID; the session initiator allocates odd IDs and the session receiver allocates even IDs. Then, send a message with the flag set to `NewStream`, the ID set to the newly | |||
To open a new stream, first allocate a new unique stream ID. Then, send a message with the flag set to `NewStream`, the ID set to the newly |
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.
Stream IDs are no longer unique session-wide.
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.
Hmm, good point. I think we can word it as unique for each end, as in reusing IDs is not supported? Suggestions welcome.
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.
Each endpoint has an independent pool of stream IDs. To open a new stream, send a message with the flag set to
NewStream
, the ID set to the next available ID (for this endpoint), and the data of the message set to the name of the stream.
?
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.
Note: We should still note somewhere that streams are identified by the (streamID, initiatedByMe)
tuple.
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.
who is me? The peerId?
README.md
Outdated
allocated stream ID, and the data of the message set to the name of the stream. | ||
|
||
Stream names are purely for interfaces and are not otherwise considered by the protocol. An empty string may also be used for the stream name, and they may also be repeated (using the same stream name for every stream is valid). Reusing | ||
a stream ID after closing a stream may result in undefined behaviour. | ||
|
||
The party that opens a stream is called the stream initiator. This is used for numbering the streams. | ||
The party that opens a stream is called the stream initiator. This is used for numbering the streams as well as identifying whether the message comes from a channel opened locally or remotely. Thus, the stream initiator always uses even flags and stream receivers uses odd flags. |
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.
This is used for numbering the streams
Not anymore (in go at least).
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.
True, I'll change it.
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.
What's the trick to number streams then?
@@ -52,13 +52,13 @@ necessarily send the first packet, this distinction is just made to make the all | |||
|
|||
### Opening a new stream |
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.
In the section above ^^, we should also get rid of all information about stream IDs, initiators, and receivers.
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.
we should also get rid of all information about stream IDs, initiators, and receivers.
There is one part where mentioning initiators makes sense - when talking about flag's oddness.
How short? The issue only started to appear with multiple streams were open. Can we have a serious interop test that tests with hundreds to thousands of streams? |
Short in terms of code length/complexity. Each side opens 100 streams (in parallel) and read/write 100 different messages. The test fails with all previous versions of mplex (that I've tested). A longer test would hammer on stream open/close events, resets, slow reads, small writes, large writes, etc. This test doesn't do all that. |
@dryajov is there a PR coming with these changes for libp2p-mplex? |
@diasdavid this PR is the spec change, the go fix is here: libp2p/go-mplex#26 @dryajov said that the interop tests didn't work for him, any help with that would be appreciated (they work for me 100% of the time). |
We shouldn't need to make any changes to the js code, it should already work as expected. I'll look into what's breaking with the interop tests and see if it works with @Stebalien's changes, but what's breaking seems to be specific to my env. |
I've merged the go changes (@dryajov found the issue with the test). The only thing left is to finish this up and bubble the go changes. |
@Stebalien that is awesome to hear! Is it coming on next go-ipfs? Sign me up for that release :) |
@diasdavid the one after the next one. IIRC, we have an RC1 for the next release already cut. |
That really drags things for us. Are we looking into something like 6~8 weeks? |
@diasdavid the answer is ASAP. We're cutting this release because we want to fix a burning windows bug. |
also, relays; we need rapid deployment for that. |
fix: use correct id sequence (dialer even/listener odd)
fix: use correct id sequence (dialer even/listener odd)
There is an inconsistency in the spec. It says odd IDs are used for initiators and even ids for receiver. This is reverced from the current js implementation - https://github.com/libp2p/js-libp2p-mplex/blob/master/src/internals/index.js#L83-L91.