Skip to content
This repository has been archived by the owner on Sep 9, 2022. It is now read-only.

Multi-Relay Hopping #127

Open
elgohr opened this issue Apr 16, 2021 · 1 comment
Open

Multi-Relay Hopping #127

elgohr opened this issue Apr 16, 2021 · 1 comment

Comments

@elgohr
Copy link

elgohr commented Apr 16, 2021

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.

@mxinden
Copy link
Member

mxinden commented Apr 16, 2021

I can't comment on the Golang specifics.

Referencing the corresponding specification issue here: libp2p/specs#21

See also Future work section in relay specification.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants