go-libp2p-circuit
go-libp2p-circuit copied to clipboard
Multi-Relay Hopping
It would be great to have a way for multi-relay hopping.
Let's say there's the following network:
[ Peer A ] - [ Relay 1 ] - [ Relay 2 ] - [ Peer B ]
In this example Peer A could reach Peer B via Relay 1 and Relay 2. Nevertheless it looks like this is not possible at the moment.
The following implementation uses Relay 1 as the relay and tries to connected to Peer B.
This results in HOP_NO_CONN_TO_DST
. Which is comprehensible, as Relay 1 has no direct connection to Peer B.
package main
import (
"context"
"fmt"
logging "github.com/ipfs/go-log"
"github.com/libp2p/go-libp2p"
circuit "github.com/libp2p/go-libp2p-circuit"
"github.com/libp2p/go-libp2p-core/network"
"github.com/libp2p/go-libp2p-core/peer"
ma "github.com/multiformats/go-multiaddr"
"log"
)
func main() {
h1, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptHop))
if err != nil {
log.Fatalln(err)
}
h2, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptHop))
if err != nil {
log.Fatalln(err)
}
h3, err := libp2p.New(context.Background(), libp2p.EnableRelay(circuit.OptHop))
if err != nil {
log.Fatalln(err)
}
h4, err := libp2p.New(context.Background(), libp2p.ListenAddrs(), libp2p.EnableRelay())
if err != nil {
log.Fatalln(err)
}
h2info := peer.AddrInfo{
ID: h2.ID(),
Addrs: h2.Addrs(),
}
h3info := peer.AddrInfo{
ID: h3.ID(),
Addrs: h3.Addrs(),
}
if err := h1.Connect(context.Background(), h2info); err != nil {
log.Fatalln(err)
}
if err := h2.Connect(context.Background(), h3info); err != nil {
log.Fatalln(err)
}
if err := h4.Connect(context.Background(), h3info); err != nil {
log.Fatalln(err)
}
h4.SetStreamHandler("/cats", func(s network.Stream) {
fmt.Println("Meow! It worked!")
s.Close()
})
relayaddr, err := ma.NewMultiaddr("/p2p/" + h2.ID().Pretty() + "/p2p-circuit/p2p/" + h4.ID().Pretty())
if err != nil {
log.Fatalln(err)
}
h4relayInfo := peer.AddrInfo{
ID: h4.ID(),
Addrs: []ma.Multiaddr{relayaddr},
}
if err := h1.Connect(context.Background(), h4relayInfo); err != nil {
log.Fatalln(err)
}
s, err := h1.NewStream(context.Background(), h4.ID(), "/cats")
if err != nil {
fmt.Println("huh, this should have worked: ", err)
return
}
s.Read(make([]byte, 1))
}
On the other hand, changing the relay address to "/p2p/" + h3.ID().Pretty() + "/p2p-circuit/p2p/" + h4.ID().Pretty()
(using Relay 2 instead of Relay 1), leads to a connection error - as Peer A is not able to connect to Relay 2.
To me it would be great to talk to Relay 1 and being able to connect to Peer B.
I can't comment on the Golang specifics.
Referencing the corresponding specification issue here: https://github.com/libp2p/specs/issues/21
See also Future work section in relay specification.