|
| 1 | + |
| 2 | + |
| 3 | +NOTE: This document is structured in an `if-then/else[if]-then` manner, each line is a precondition for following lines with a higher number of indentation |
| 4 | + |
| 5 | +Example: |
| 6 | + |
| 7 | +- if there are apples |
| 8 | + - eat them |
| 9 | +- if not, check for pears |
| 10 | + - then eat them |
| 11 | +- if not, check for cherries |
| 12 | + - then eat them |
| 13 | + |
| 14 | +Or, |
| 15 | + |
| 16 | +- if there are apples |
| 17 | + - eat them |
| 18 | +- if not |
| 19 | + - check for pears |
| 20 | + - then eat them |
| 21 | +- if not |
| 22 | + - check for cherries |
| 23 | + - then eat them |
| 24 | + |
| 25 | +In order to minimize nesting, the first example is preferred |
| 26 | + |
| 27 | +# Relay flow |
| 28 | + |
| 29 | +## Relay transport (dialer/listener) |
| 30 | + |
| 31 | +- ### Dial over a relay |
| 32 | + - See if there is a relay that's already connected to the destination peer, if not |
| 33 | + - Ask all the peer's known relays to dial the destination peer until an active relay (one that can dial on behalf of other peers), or a relay that may have recently acquired a connection to the destination peer is successful. |
| 34 | + - If successful |
| 35 | + - Write the `/ipfs/relay/circuit/1.0.0` header to the relay, followed by the destination address |
| 36 | + - e.g. `/ipfs/relay/circuit/1.0.0\n/p2p-circuit/ipfs/QmDest`. |
| 37 | + - If no relays could connect, fail the same way a regular transport would |
| 38 | + - Once the connection has been established, the swarm should treat it as a regular connection, |
| 39 | + - i.e. muxing, encrypt, etc should all be performed on the relayed connection |
| 40 | + |
| 41 | +- ### Listen for relayed connections |
| 42 | + - Peer mounts the `/ipfs/relay/circuit/1.0.0` proto and listens for relayed connections |
| 43 | + - A connection arrives |
| 44 | + - read the address of the source peer from the incoming connection stream |
| 45 | + - if valid, create a PeerInfo object for that peer and add the incoming address to its multiaddresses list |
| 46 | + - pass the connection to `protocolMuxer(swarm.protocols, conn)` to have it go through the regular muxing/encryption flow |
| 47 | + |
| 48 | +- ### Relay discovery and static relay addresses in swarm config |
| 49 | + |
| 50 | + - #### Relay address in swarm config |
| 51 | + - A peer has relay addresses in its swarm config section |
| 52 | + - On node startup, connect to the relays in swarm config |
| 53 | + - if successful add address to swarms PeerInfo's multiaddresses |
| 54 | + - `identify` should take care of announcing that the peer is reachable over the listed relays |
| 55 | + |
| 56 | + - #### Passive relay discovery |
| 57 | + - A peer that can dial over `/ipfs/relay/circuit/1.0.0` listens for the `peer-mux-established` swarm event, every time a new muxed connection arrives, it checks if the incoming peer is a relay. (How would this work? Some way of discovering if its a relay is required.) |
| 58 | + - *Useful in cases when the peer/node doesn't know of any relays on startup and also, to learn of as many additional relays in the network as possible* |
| 59 | + - *Useful during startup, when connecting to bootstrap nodes. It allows us to implicitly learn if its a relay without having to explicitly add `/p2p-circuit` addresses to the bootstrap list* |
| 60 | + - *Also useful if the relay communicates its capabilities upon connecting to it, as to avoid additional unnecessary requests/queries. I.e. if it supports weather its able to forward connections and weather it supports the `ls` or other commands.* |
| 61 | + - *Should it be possible to disable passive relay discovery?* |
| 62 | + - This could be useful when the peer wants to be reachable **only** over the listed relays |
| 63 | + - If the incoming peer is a relay, send an `ls` and record its peers |
| 64 | + |
| 65 | +## Relay Nodes |
| 66 | + |
| 67 | +- ### Passive relay node |
| 68 | + - *A passive relay does not explicitly dial into any requested peer, only those that it's swarm already has connections to.* |
| 69 | + - When the relay gets a request, read the the destination peer's multiaddr from the connection stream and if its a valid address and peer id |
| 70 | + - check its swarm's peerbook(?) see if its a known peer, if it is |
| 71 | + - use the swarms existing connection and |
| 72 | + - send the multistream header and the source peer address to the dest peer |
| 73 | + - e.g. `/ipfs/relay/circuit/1.0.0\n/p2p-circuit/ipfs/QmSource` |
| 74 | + - circuit the source and dest connections |
| 75 | + - if couldn't dial, or the connection/stream to the dest peer closed prematurelly |
| 76 | + - close the src stream |
| 77 | + |
| 78 | + |
| 79 | +- ### Active relay node |
| 80 | + - *An active relay node can dial other peers even if its swarm doesnt know about those peers* |
| 81 | + - When the relay gets a request, read the the destination peer's multiaddr from the connection stream and if its a valid address and peer id |
| 82 | + - use the swarm to dial to the dest node |
| 83 | + - send the multistream header and the source peer address to the dest peer |
| 84 | + - e.g. `/ipfs/relay/circuit/1.0.0\n/p2p-circuit/ipfs/QmSource` |
| 85 | + - circuit the source and dest connections |
| 86 | + - if couldn't dial, or the connection/stream to the dest peer closed prematurely |
| 87 | + - close the src stream |
| 88 | + |
| 89 | +- ### `ls` command |
| 90 | + - *A relay node can allow the peers known to it's swarm to be listed* |
| 91 | + - *this should be possible to enable/disable from the config* |
| 92 | + - when a relay gets the `ls` request |
| 93 | + - if enabled, get its swarm's peerbook's known peers and return their ids and multiaddrs |
| 94 | + - e.g `[{id: /ipfs/QmPeerId, addrs: ['ma1', 'ma2', 'ma3']}, ...]` |
| 95 | + - if disabled, respond with `na` |
| 96 | + |
| 97 | + |
| 98 | +## Relay Implementation notes |
| 99 | + |
| 100 | +- ### Relay transport |
| 101 | + - Currently I've implemented the dialer and listener parts of the relay as a transport, meaning that it *tries* to implement the `interface-transport` interface as closely as possible. This seems to work pretty well and it's makes the dialer/listener parts really easy to plug in into the swarm. I think this is the cleanest solution. |
| 102 | + |
| 103 | +- ### `circuit-relay` |
| 104 | + - This is implemented as a separate piece (not a transport), and it can be enabled/disabled with a config. The transport listener however, will do the initial parsing of the incoming header and figure out weather it's a connection that's needs to be handled by the circuit-relay, or its a connection that is being relayed from a circuit-relay. |
| 105 | + |
| 106 | +## Relay swarm integration |
| 107 | + |
| 108 | +- The relay transport is mounted explicitly by calling the `swarm.connection.relay(config.relay)` from libp2p |
| 109 | + - Swarm will register the dialer and listener using the swarm `transport.add` and `transport.listen` methods |
| 110 | + |
| 111 | + - ### Listener |
| 112 | + - the listener registers itself as a multistream handler on the `/ipfs/relay/circuit/1.0.0` proto |
| 113 | + - if `circuit-relay` is enabled, the listener will delegate connections to it if appropriate |
| 114 | + - when the listener receives a connection, it will read the multiaddr and determine if its a connection that needs to be relayed, or its a connection that is being relayed |
| 115 | + |
| 116 | + - ### Dialer |
| 117 | + - When the swarm attempts to dial to a peer, it will filter the protocols that the peer can be reached on |
| 118 | + - *The relay will be used in two cases* |
| 119 | + - If the peer has an explicit relay address that it can be reached on |
| 120 | + - no other transport is available |
| 121 | + - The relay will attempt to dial the peer over that relay |
| 122 | + - If no explicit relay address is provided |
| 123 | + - no other transport is available |
| 124 | + - A generic circuit address will be added to the peers multiaddr list |
| 125 | + - i.e. `/p2p-circuit/ipfs/QmDest` |
| 126 | + - If another transport is available, then use that instead of the relay |
| 127 | + |
| 128 | + |
0 commit comments