Michal Iskierko 6d31343205 feat: Waku v2 bridge
Issue #12610
2024-02-22 17:07:59 +01:00

179 lines
4.5 KiB
Go

package rendezvous
import (
"context"
"crypto/rand"
"fmt"
"time"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/p2p/enr"
"github.com/ethereum/go-ethereum/rlp"
libp2p "github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/crypto"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
ma "github.com/multiformats/go-multiaddr"
ethv4 "github.com/status-im/go-multiaddr-ethv4"
"github.com/status-im/rendezvous/protocol"
)
var logger = log.New("package", "rendezvous/client")
func NewEphemeral() (c Client, err error) {
priv, _, err := crypto.GenerateKeyPairWithReader(crypto.Secp256k1, 0, rand.Reader) // bits are ignored with edwards or secp251k1
if err != nil {
return Client{}, err
}
return New(priv)
}
func New(identity crypto.PrivKey) (c Client, err error) {
opts := []libp2p.Option{
libp2p.Identity(identity),
}
h, err := libp2p.New(opts...)
if err != nil {
return c, err
}
return Client{
h: h,
}, nil
}
func NewWithHost(h host.Host) (c Client, err error) {
return Client{
h: h,
}, nil
}
type Client struct {
h host.Host
}
func (c Client) Register(ctx context.Context, srv ma.Multiaddr, topic string, record enr.Record, ttl time.Duration) error {
s, err := c.newStream(ctx, srv)
if err != nil {
return err
}
defer s.Close()
if err = rlp.Encode(s, protocol.REGISTER); err != nil {
return err
}
if err = rlp.Encode(s, protocol.Register{Topic: topic, Record: record, TTL: uint64(ttl)}); err != nil {
return err
}
rs := rlp.NewStream(s, 0)
typ, err := rs.Uint()
if err != nil {
return err
}
if protocol.MessageType(typ) != protocol.REGISTER_RESPONSE {
return fmt.Errorf("expected %v as response, but got %v", protocol.REGISTER_RESPONSE, typ)
}
var val protocol.RegisterResponse
if err = rs.Decode(&val); err != nil {
return err
}
logger.Debug("received response to register", "status", val.Status, "message", val.Message)
if val.Status != protocol.OK {
return fmt.Errorf("register failed. status code %v", val.Status)
}
return nil
}
func (c Client) Discover(ctx context.Context, srv ma.Multiaddr, topic string, limit int) (rst []enr.Record, err error) {
s, err := c.newStream(ctx, srv)
if err != nil {
return
}
defer s.Close()
if err = rlp.Encode(s, protocol.DISCOVER); err != nil {
return
}
if err = rlp.Encode(s, protocol.Discover{Topic: topic, Limit: uint(limit)}); err != nil {
return
}
rs := rlp.NewStream(s, 0)
typ, err := rs.Uint()
if err != nil {
return nil, err
}
if protocol.MessageType(typ) != protocol.DISCOVER_RESPONSE {
return nil, fmt.Errorf("expected %v as response, but got %v", protocol.REGISTER_RESPONSE, typ)
}
var val protocol.DiscoverResponse
if err = rs.Decode(&val); err != nil {
return
}
if val.Status != protocol.OK {
return nil, fmt.Errorf("discover request failed. status code %v", val.Status)
}
logger.Debug("received response to discover request", "status", val.Status, "records lth", len(val.Records))
return val.Records, nil
}
func (c Client) RemoteIp(ctx context.Context, srv ma.Multiaddr) (value string, err error) {
s, err := c.newStream(ctx, srv)
if err != nil {
return
}
defer s.Close()
if err = rlp.Encode(s, protocol.REMOTEIP); err != nil {
return
}
rs := rlp.NewStream(s, 0)
typ, err := rs.Uint()
if err != nil {
return
}
if protocol.MessageType(typ) != protocol.REMOTEIP_RESPONSE {
err = fmt.Errorf("expected %v as response, but got %v", protocol.REMOTEIP_RESPONSE, typ)
return
}
var val protocol.RemoteIpResponse
if err = rs.Decode(&val); err != nil {
return
}
if val.Status != protocol.OK {
err = fmt.Errorf("remoteip request failed. status code %v", val.Status)
return
}
logger.Debug("received response to remoteip request", "status", val.Status, "ip", val.IP)
value = val.IP
return
}
func (c Client) newStream(ctx context.Context, srv ma.Multiaddr) (rw network.Stream, err error) {
pid, err := srv.ValueForProtocol(ethv4.P_ETHv4)
if err != nil {
return
}
peerid, err := peer.Decode(pid)
if err != nil {
return
}
// TODO there must be a better interface
targetPeerAddr, err := ma.NewMultiaddr(fmt.Sprintf("/ethv4/%s", pid))
if err != nil {
return
}
targetAddr := srv.Decapsulate(targetPeerAddr)
c.h.Peerstore().AddAddr(peerid, targetAddr, 5*time.Second)
s, err := c.h.NewStream(ctx, peerid, "/rend/0.1.0")
if err != nil {
return nil, err
}
return &InstrumentedStream{s}, nil
}
// Close shutdowns the host and all open connections.
func (c Client) Close() error {
return c.h.Close()
}