Skip to content
This repository was archived by the owner on Aug 23, 2019. It is now read-only.

Commit 0268a5d

Browse files
committed
adding this to keep track of requirements/ideas
1 parent 898a4bc commit 0268a5d

File tree

1 file changed

+128
-0
lines changed

1 file changed

+128
-0
lines changed

implementation-notes.md

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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

Comments
 (0)