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

The Circuit Relay Specification: The first iteration #15

Closed
wants to merge 10 commits into from

Conversation

daviddias
Copy link
Member

In an attempt to converge all the relay spec notes and discussions, I'm listing them here, so that they can all be considered for the revamp of the relay spec. (Order represents the timeline of how theses appear, last should be considered as last 'discussed')

relay/README.md Outdated
- `/p2p-circuit`
- Use relay discovery to find a suitable relay node. (Neither specified nor implemented.)
- Listen for relayed connections.
- Dial through the discovered relay node for any `/p2p-circuit` multiaddr.

TODO: figure out forced addresses.
TODO: figure out nested relayed connections.
TODO: figure out forced addresses. -> what is forced addresses?
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lgierth Can you elaborate on what "forced addresses" are?

relay/README.md Outdated
- `/p2p/QmRelay/p2p-circuit`
- Same as previous example, but use peer routing to find an address for QmRelay.

?? I believe we don't need this one:
- `/p2p-circuit`
- Use relay discovery to find a suitable relay node. (Neither specified nor implemented.)
- Listen for relayed connections.
- Dial through the discovered relay node for any `/p2p-circuit` multiaddr.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me, the act of 'enabling relayed connections' is a config value and not a multiaddr. Do you agree @lgierth ?

Copy link
Member

@dryajov dryajov Mar 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diasdavid @lgierth @whyrusleeping

I think it depends on how you look at relay. To me, relay is just another transport, hence making it behave like any other transport makes sense - here, I'm specifically talking about the dialer/listener (/stop) parts of the relay. The circuit-relay itself, can/should be controlled by config options.

Example:

Swarm: {
  Addresses: [
    '/p2p-circuit/<multiaddr of the Relay>' // or just plain /p2p-circuit enables circuit for listening (/stop) and dialing
  ]
},
Relay: {
  Circuit: {
    Enabled: false, // enable/disable circuit-relaying
    list-peers: false // I think this will be moved to its own proto that implements `ls`
    Proactive: false // should be renamed `Active`? (Active/Passive) naming
  }
}

Edit:

Thinking about this a bit more, I think we should enable circuit transport by default, no need for an explicit p2p-circuit in the swarm addrs.

relay/README.md Outdated
- The relay node will use peer routing to find an address for QmTwo.
- Also makes QmRelay available for relayed dialing, based on how listeners currently relate to dialers.
- `/p2p/QmRelay/p2p-circuit`
- Same as previous example, but use peer routing to find an address for QmRelay.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm, these addresses exist to have a way to make the node always dial to the relay peer (punch out), correct?

@daviddias
Copy link
Member Author

From now on, all comments, reviews, edits and so on, should be applied directly to the document so that we keep everything in place :)

relay/README.md Outdated
| 260 | "passive relay has no connection to dst" | |
| 261 | "active relay could not connect to dst: connection refused" | relay could not form new connection to target peer |
| 262 | "could not open new stream to dst: BAD ERROR" | relay has connection to dst, but failed to open a new stream |
| 270 | "<dst> does not support relay" | |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really want to use 2XX+3XX for errors? Can we follow the pattern laid by HTTP:

- 1×× Informational
- 2×× Success
- 3×× Redirection
- 4×× Client Error
- 5×× Server Error

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍HTTP codes are well known, which makes them more intuitive and expected.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It doesnt map exactly though, i'm fine moving the 100 OK to 200 OK.

I guess we could map all the 200 errors to 400 'client' errors, and map all the 300 errors to 500 'server' errors

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@whyrusleeping exactly what I was hoping for ❤️

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@diasdavid @whyrusleeping

After, re-reading the table... They don't really map to HTTP at all... 200s are relay codes and 300 are dst errors. So, I think 1xx, 2xx, 3xx make sense here.

relay/README.md Outdated
| 261 | "active relay could not connect to dst: connection refused" | relay could not form new connection to target peer |
| 262 | "could not open new stream to dst: BAD ERROR" | relay has connection to dst, but failed to open a new stream |
| 270 | "<dst> does not support relay" | |
| 320 | "src address too long" | |
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From IRC:

14:13 <@daviddias> I don't understand why the 'send the src' addr keeps appearing as a thing for relay
16:05 <+dryajov> diasdavid re srs addr: I dont think we need it anymore, you are right. We can always do getPeerInfo on the circuited conn and should be able to get the src addrs. It would only make sense, if the full relay addr is sent so that the relay can be rebuilt from the dst to the src, if that ever makes sense?
16:23 <@daviddias> " It would only make sense, if the full relay addr is sent so that the relay can be rebuilt from the dst to the src, if that ever makes sense?" even in that case, we can always verify who dialed us with the getPeerInfo call
16:26 <+dryajov> True, that would be a swarm addr and should come back with the getPeerInfo. We don't need it.

relay/README.md Outdated

This opens the room for multiple hop relay, where the first relay is encapsulated in the seconf relay multiaddr, such as:

`/p2p-circuit/p2p-circuit/<first relay>/<first hop multiaddr>/<destination peer multiaddr>`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To me it makes a lot more sense to do something like - /p2p-circuit<first relay>/<first hop multiaddr>/p2p-circuit<second relay>/<second hop multiaddr>/<destination peer multiaddr>

relay/README.md Outdated
Once it receives that, it checks if the status code is `OK`. If it is, it passes the new connection to its `NewConnHandler`.
Otherwise, it returns the error message to the caller.

### 'hop' protocol handler
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By hop, you mean /libp2p/circuit/relay ?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, i mean /libp2p/circuit/relay/1.0.0/hop

relay/README.md Outdated
<uvarint 'OK'><uvarint len(msg)><string "OK">
```

And passes the relayed connection into its `NewConnHandler`.
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused by this stop handler. What case is it enabling exactly?

Copy link
Member

@dryajov dryajov Mar 28, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thats the end point in the relay flow, hop is the relay listener, stop listens for relayed connections coming from hop. This is needed because you can be both a relay and listener on the same node - hence hop and stop sub protos.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood.

@daviddias
Copy link
Member Author

One thing that the current spec is missing is versioning. Right now we have:

  • /libp2p/circuit/relay/hop
  • /libp2p/circuit/relay/stop

We the possibility of having a /libp2p/circuit/relay/ls, still on discussion.

If we were to add versioning, it makes it a tad complicated because it would create a version for each of these protocols (and we already know that assuming that something will never change is an antipattern™), ending up on:

  • /libp2p/circuit/relay/hop/1.0.0
  • /libp2p/circuit/relay/stop/1.0.0

This can be ok (and maybe a question of preference), but I would rather have a single /libp2p/circuit/relay/1.0.0 to maintain a single versioning over the circuit relay protocol, having the selection of {hop, stop, ls} as part of the RPC.

// cbor encoded json
{
  type: `hop`
  dstAddr: <some multiaddr>
}

It is not that we are trying to avoid RPC messages, we are already sending the multiaddr after first dial and we have the status codes going on.

relay/README.md Outdated

A `/p2p-circuit` circuit address, is formated following:

`/p2p-circuit[<relay peer multiaddr>]<destination peer multiaddr>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe put slashes in here?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, after @lgierth clarifications this should be <relay peer multiaddr>/p2p-circuit/<destination peer multiaddr>

@dryajov
Copy link
Member

dryajov commented Mar 28, 2017

@diasdavid re versioning:

<•lgierth>  /libp2p/relay/circuit/1.0.0/{hop,stop}
15:37 W<•whyrusleeping> because theyre sub-endpoints of the same protocol
15:38 L<•lgierth> yeah and they're different semantics on the same wire format
15:38 D<•dryajov> ah, sure… I had the impression that the version would always come at the end
15:39 that makes sense tho
15:39 L<•lgierth> well i guess until now it always has
15:39 "it's always been like this" is usually a good reason to do it differently eventually :D
15:39 D<•dryajov> problem is that now its non deterministic… if its always at the end, you can easily extract it, if its not, you need to define syntax around it
15:40 L<•lgierth> no you just go through all the mounted protocols you have, and pick the one which supports /libp2p/relay/circuit/$versionRange
15:40 W— •whyrusleeping checks his parsing code
15:40 L<•lgierth> hah yeah better check
15:40 W— •whyrusleeping is sure that this will break his parsing code
15:40 W<•whyrusleeping> but no worries
15:41 we have to update that package anyways
15:41 can fix it along the way
15:41 or just use explicit protocol matching for now
15:41 D<•dryajov> yeah… but… how do you know whats a version and whats not :D?
15:41 L<•lgierth> your mount protocols know
15:41 W<•whyrusleeping> Yeah, that does get hard
15:41 L<•lgierth> transports work similarly, just without a version
15:41 D<•dryajov> ah… I see what you mean
15:42 L<•lgierth> each transport has a Matches() func
15:42 D<•dryajov> yeah, you don’t really need to check anything, just do an exact match
15:42 :D

Boils down to /libp2p/relay/circuit/1.0.0/{hop,stop} with the version not coming at the end anymore. This works if you're doing exact matching, but makes it hard to extract if you try to do semantic versioning, specially since semver supports tags in version numbers.

@whyrusleeping
Copy link
Contributor

what should the 'remote multiaddr' look like on a relay connection?

My proposal is:

<src maddr, from header>/p2p-circuit/QmRelayPeerID

@daviddias
Copy link
Member Author

@whyrusleeping can you enlighten me on the src being something that is transferred here? See #15 (comment)

@whyrusleeping
Copy link
Contributor

Irc logs for context: http://lets.git.sexy/relaynotes

@dryajov
Copy link
Member

dryajov commented Mar 28, 2017

@whyrusleeping can you clarify what's the

  • src maddr
  • from header

in this - <src maddr, from header>

@whyrusleeping
Copy link
Contributor

@dryajov I mean the source multiaddr that is sent by 'A' in their initial relay request

@whyrusleeping
Copy link
Contributor

Another question, is it /p2p-relay/PEERID or /p2p-relay/<multiaddr> ?

@dryajov
Copy link
Member

dryajov commented Mar 28, 2017

@whyrusleeping - both. In the first case it's peer routing, the second is over an explicit transport.

Oh, and its /p2p-circuit not p2p-crelay :)

@daviddias
Copy link
Member Author

2017-03-27 17:48:29	+dryajov	hsanhuan brought some valid points there, basically, the idea is that you can rebuild the circuit from dst to src
2017-03-27 17:48:47	+dryajov	thats why src address is written to dst,
2017-03-27 17:48:54	+dryajov	otherwise it would work
2017-03-27 17:49:27	@whyrusleeping	Then we should go back to lgierth's original spec with both a src and a dst

I see you want to the full initial multiaddr, including any IPs, ports and so on. I question the usefulness of this, as you would only really need the peer Id (which you get from secio) and the relay addr (which you know, because you also have a conn established with it). But I guess it doesn't hurt.

@dryajov
Copy link
Member

dryajov commented Mar 28, 2017

@whyrusleeping or do you mean,

  • /p2p-circuit/QmPeer (not a valid mr as it is right now?)
  • /p2p-circuit/ipfs/QmPeer - peer routing ma
  • /p2p-circuit/ip4/127.0.0.1/tcp/80/ipfs/QmPeer

?

@whyrusleeping
Copy link
Contributor

as you would only really need the peer Id (which you get from secio)

No, we reallllllly have to stop assuming "we will just get it from secio". Thats an assumption that hurts us

I think its important to know where the connection is coming from. Though I think with the two separate protocols we could now get away with a single address, with different meaning per protocol (hop vs stop)

@whyrusleeping
Copy link
Contributor

@dryajov

  • /p2p-circuit/QmPeer (not a valid mr as it is right now?)
  • /p2p-circuit/ipfs/QmPeer - peer routing ma
  • /p2p-circuit/ip4/127.0.0.1/tcp/80/ipfs/QmPeer

The issue here is that <anything>/ipfs/QmPeerID implies that this multiaddress is connecting to that peer. I think doing <anything>/p2p-circuit/QmPeerID makes the most sense, as its saying we are relaying through peer QmPeerID.

/p2p-circuit/ip4/127.0.0.1/tcp/80/ipfs/QmPeer is very confusing. Consider the following:
``/p2p-circuit/ip4/127.0.0.1/tcp/80/ipfs/QmPeer/p2p-circuit/ip4/127.0.0.1/tcp/123/ipfs/QmOtherPeer`

Am I relaying through QmPeer to QmOtherPeer? Or is this a relay whose exit point is QmOtherPeer?

In a diagram so i can more clearly explain myself:

A -> [QmPeer] -> [QmOtherPeer] -> ?
or
A -> [QmPeer] -> QmOtherPeer
or
A -> [QmPeer -> [QmOtherPeer]] -> ?

relay/README.md Outdated

`/p2p-circuit[<relay peer multiaddr>]<destination peer multiaddr>`

This opens the room for multiple hop relay, where the first relay is encapsulated in the seconf relay multiaddr, such as:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: s/seconf/second/

relay/README.md Outdated

Specify a relay:

- `/p2p-circuit/p2p/QmRelay/p2p/QmTwo`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be:

/p2p/QmRelay/p2p-circuit/p2p/QmTwo

relay/README.md Outdated
- Dial QmTwo, through QmRelay.
- Use peer routing to find an address for QmRelay.
- The relay node will also use peer routing, to find an address for QmTwo.
- `/p2p-circuit/ip4/../tcp/../p2p/QmRelay/p2p/QmTwo`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be:

/ip4/../tcp/../p2p/QmRelay/p2p-circuit/p2p/QmTwo

relay/README.md Outdated
- R writes `/ipfs/QmB` on `sRB`
- B receives stream `sRB` and reads `/ipfs/QmB` from it.
- B sees that the multiaddr it read is its own and chooses to handle this stream as an endpoint instead of attempting to relay further
- TODO: step for R to send back status code to A
Copy link
Member

@dryajov dryajov Mar 29, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on status codes:

  • R doesn't send any success codes to A, only failure codes
    • R would potentially also send err codes from B if the circuit is not yet established
  • A would get a success or failure code from B once the circuit is established

* feat: adding err code 280 "can't relay to itlsef"

* doc: reworded 280 description
Copy link
Member

@dryajov dryajov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've added some more comments and clarifications. Lets get this reviewed one more time.

@ghost ghost self-requested a review April 14, 2017 19:42
@daviddias
Copy link
Member Author

daviddias commented May 8, 2017

I've reviewed:

  • Overview
  • Dramatization
  • Addressing

Missing:

I'll review these last 3 in separate PRs to this one to make sure I don't merge anything to the PR without having everyone in the same page.

@ghost
Copy link

ghost commented May 8, 2017

Three comments, then LGTM 👍

@daviddias
Copy link
Member Author

Applied @lgierth review, now onto the remaining bits.

@daviddias
Copy link
Member Author

#18 up for review

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's merge this one, thanks @diasdavid!

Copy link
Member

@dryajov dryajov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lets get this merged! 👍

@daviddias
Copy link
Member Author

daviddias commented May 21, 2017

Not yet, #15 (comment) needs to happen. The spec is not ready.

@ghost
Copy link

ghost commented May 22, 2017

@diasdavid there's an inaccurate spec already merged though -- this PR is a great improvement over the existing document, and isn't technically blocked by the remaining tasks. Anyhow I added a note about this work-in-progress in #20 as an alternative.

review Wire protocol section from the relay spec
@daviddias daviddias changed the title Update the relay spec The Circuit Relay Specification Jul 8, 2017
@daviddias
Copy link
Member Author

daviddias commented Jul 8, 2017

A new chapter

Following up the discussion on IRC (#ipfs-dev@freenode), I'll be working on finishing this spec to my best understanding and contemplating all the improvements discussed. Once this revamp is done, I'll open a new PR for formal review.

@daviddias daviddias changed the title The Circuit Relay Specification The Circuit Relay Specification: The first iteration Jul 8, 2017
@daviddias
Copy link
Member Author

It is here! #22

Guess what, using a protobuf simplifies so much the 'under the microscope section' :)

@daviddias daviddias closed this Jul 8, 2017
@daviddias daviddias deleted the feat/update-relay-spec branch February 20, 2018 22:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants