Skip to content
This repository has been archived by the owner on Oct 10, 2018. It is now read-only.

fix: use correct id sequence (dialer even/listener odd) #3

Merged
merged 3 commits into from
Oct 1, 2018

Conversation

dryajov
Copy link
Member

@dryajov dryajov commented Apr 11, 2018

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.

@Stebalien
Copy link
Member

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 MessageInitiator tag means that it's a message on a stream that I initiated. That means we can use the same stream IDs and everything "just works".

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.

@dryajov
Copy link
Member Author

dryajov commented Apr 12, 2018

It looks like the original protocol didn't specify odd/even stream IDs

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 🙃

@Stebalien
Copy link
Member

The reason it works, seems to be because the tag eve/odd'nes matches

....? 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:

  1. IDs are allocated out of the local pool.
  2. Use tag + 1 when sending a message on a stream initiated by the other side.

Does the session (not stream) initiator even matter?

@dryajov
Copy link
Member Author

dryajov commented Apr 13, 2018

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.

@daviddias
Copy link
Member

@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?)

@dryajov
Copy link
Member Author

dryajov commented Apr 13, 2018

Does the session (not stream) initiator even matter?

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.

@dryajov
Copy link
Member Author

dryajov commented Apr 13, 2018

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:

  1. change the id to even for initiators odd for receivers
  2. use even tags for initiator and odd for receiver

@Stebalien
Copy link
Member

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).

Stebalien added a commit to libp2p/go-mplex that referenced this pull request Apr 16, 2018
See: libp2p/mplex#3

(massive thanks to @dyajov for finding this)
@Stebalien
Copy link
Member

Fix here (without the alternating stream IDs for now): libp2p/go-mplex#26

Can someone test it?

@dryajov
Copy link
Member Author

dryajov commented Apr 17, 2018

Can someone test it?

I'll give it a go.

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).

Fair enough - it changes little on my side as well.

@Stebalien
Copy link
Member

Stebalien commented Apr 23, 2018

@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:

  • Remove mentions of ID selection (each side just selects an ID that doesn't correspond to a channel that they've opened).
  • The initiator uses even tags to indicate that the stream is theirs. That is, the full stream ID is a tuple (id, mine) = (header >> 3, (header&1) == 1)

@dryajov
Copy link
Member Author

dryajov commented Apr 23, 2018

@Stebalien LGTM!

Thanks for the interop, I'll try it out with my new implementation as well 👍

remove mention of even/odd id numbering
@dryajov
Copy link
Member Author

dryajov commented Apr 23, 2018

@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
Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

@Stebalien Stebalien Apr 23, 2018

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.

?

Copy link
Member

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.

Copy link
Member

@daviddias daviddias Apr 25, 2018

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.
Copy link
Member

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).

Copy link
Member Author

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.

Copy link
Member

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
Copy link
Member

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.

Copy link
Member Author

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.

@daviddias
Copy link
Member

I've written a short interop test (checked into that branch)

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?

@Stebalien
Copy link
Member

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.

@daviddias
Copy link
Member

daviddias commented Apr 25, 2018

@dryajov is there a PR coming with these changes for libp2p-mplex?

@Stebalien
Copy link
Member

@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).

@dryajov
Copy link
Member Author

dryajov commented Apr 25, 2018

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.

@Stebalien
Copy link
Member

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.

@daviddias
Copy link
Member

@Stebalien that is awesome to hear! Is it coming on next go-ipfs? Sign me up for that release :)

@Stebalien
Copy link
Member

@diasdavid the one after the next one. IIRC, we have an RC1 for the next release already cut.

@daviddias
Copy link
Member

That really drags things for us. Are we looking into something like 6~8 weeks?

@Stebalien
Copy link
Member

@diasdavid the answer is ASAP. We're cutting this release because we want to fix a burning windows bug.

@vyzo
Copy link

vyzo commented May 6, 2018

also, relays; we need rapid deployment for that.

@ghost ghost assigned dryajov May 30, 2018
@ghost ghost added the in progress label May 30, 2018
@ghost ghost mentioned this pull request Jun 20, 2018
@Stebalien Stebalien merged commit e43bb01 into master Oct 1, 2018
@ghost ghost removed the in progress label Oct 1, 2018
@Stebalien Stebalien deleted the fix/id-sequence branch October 1, 2018 18:56
Stebalien added a commit that referenced this pull request Oct 10, 2018
fix: use correct id sequence (dialer even/listener odd)
Stebalien added a commit that referenced this pull request Oct 10, 2018
fix: use correct id sequence (dialer even/listener odd)
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants