ceremonyclient/go-libp2p/p2p/test/basichost/basic_host_test.go
2024-10-12 11:55:17 -07:00

207 lines
5.6 KiB
Go

package basichost
import (
"context"
"fmt"
"strings"
"testing"
"time"
"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/core/peerstore"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/client"
"github.com/libp2p/go-libp2p/p2p/protocol/circuitv2/relay"
libp2pwebrtc "github.com/libp2p/go-libp2p/p2p/transport/webrtc"
libp2pwebtransport "github.com/libp2p/go-libp2p/p2p/transport/webtransport"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func tStringCast(str string) ma.Multiaddr {
m, _ := ma.StringCast(str)
return m
}
func TestNoStreamOverTransientConnection(t *testing.T) {
h1, err := libp2p.New(
libp2p.NoListenAddrs,
libp2p.EnableRelay(),
libp2p.ResourceManager(&network.NullResourceManager{}),
)
require.NoError(t, err)
h2, err := libp2p.New(
libp2p.NoListenAddrs,
libp2p.EnableRelay(),
libp2p.ResourceManager(&network.NullResourceManager{}),
)
require.NoError(t, err)
relay1, err := libp2p.New()
require.NoError(t, err)
_, err = relay.New(relay1)
require.NoError(t, err)
relay1info := peer.AddrInfo{
ID: relay1.ID(),
Addrs: relay1.Addrs(),
}
err = h1.Connect(context.Background(), relay1info)
require.NoError(t, err)
err = h2.Connect(context.Background(), relay1info)
require.NoError(t, err)
h2.SetStreamHandler("/testprotocol", func(s network.Stream) {
fmt.Println("testprotocol")
// End the example
s.Close()
})
_, err = client.Reserve(context.Background(), h2, relay1info)
require.NoError(t, err)
relayaddr := tStringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String())
h2Info := peer.AddrInfo{
ID: h2.ID(),
Addrs: []ma.Multiaddr{relayaddr},
}
err = h1.Connect(context.Background(), h2Info)
require.NoError(t, err)
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
ctx = network.WithNoDial(ctx, "test")
_, err = h1.NewStream(ctx, h2.ID(), "/testprotocol")
require.Error(t, err)
_, err = h1.NewStream(network.WithAllowLimitedConn(context.Background(), "test"), h2.ID(), "/testprotocol")
require.NoError(t, err)
}
func TestNewStreamTransientConnection(t *testing.T) {
h1, err := libp2p.New(
libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"),
libp2p.EnableRelay(),
libp2p.ResourceManager(&network.NullResourceManager{}),
)
require.NoError(t, err)
h2, err := libp2p.New(
libp2p.ListenAddrStrings("/ip4/127.0.0.1/udp/0/quic-v1"),
libp2p.EnableRelay(),
libp2p.ResourceManager(&network.NullResourceManager{}),
)
require.NoError(t, err)
relay1, err := libp2p.New()
require.NoError(t, err)
_, err = relay.New(relay1)
require.NoError(t, err)
relay1info := peer.AddrInfo{
ID: relay1.ID(),
Addrs: relay1.Addrs(),
}
err = h1.Connect(context.Background(), relay1info)
require.NoError(t, err)
err = h2.Connect(context.Background(), relay1info)
require.NoError(t, err)
h2.SetStreamHandler("/testprotocol", func(s network.Stream) {
fmt.Println("testprotocol")
// End the example
s.Close()
})
_, err = client.Reserve(context.Background(), h2, relay1info)
require.NoError(t, err)
relayaddr := tStringCast("/p2p/" + relay1info.ID.String() + "/p2p-circuit/p2p/" + h2.ID().String())
h1.Peerstore().AddAddr(h2.ID(), relayaddr, peerstore.TempAddrTTL)
// NewStream should block transient connections till we have a direct connection
ctx, cancel := context.WithTimeout(context.Background(), 200*time.Millisecond)
defer cancel()
s, err := h1.NewStream(ctx, h2.ID(), "/testprotocol")
require.ErrorIs(t, err, context.DeadlineExceeded)
require.Nil(t, s)
// NewStream should return a stream if a direct connection is established
// while waiting
done := make(chan bool, 2)
go func() {
h1.Peerstore().AddAddrs(h2.ID(), h2.Addrs(), peerstore.TempAddrTTL)
ctx, cancel = context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
ctx = network.WithNoDial(ctx, "test")
s, err = h1.NewStream(ctx, h2.ID(), "/testprotocol")
require.NoError(t, err)
require.NotNil(t, s)
defer s.Close()
require.Equal(t, network.DirInbound, s.Conn().Stat().Direction)
done <- true
}()
go func() {
// connect h2 to h1 simulating connection reversal
h2.Peerstore().AddAddrs(h1.ID(), h1.Addrs(), peerstore.TempAddrTTL)
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
defer cancel()
ctx = network.WithForceDirectDial(ctx, "test")
err := h2.Connect(ctx, peer.AddrInfo{ID: h1.ID()})
assert.NoError(t, err)
done <- true
}()
<-done
<-done
}
func TestAddrFactorCertHashAppend(t *testing.T) {
wtAddr := "/ip4/1.2.3.4/udp/1/quic-v1/webtransport"
webrtcAddr := "/ip4/1.2.3.4/udp/2/webrtc-direct"
addrsFactory := func(addrs []ma.Multiaddr) []ma.Multiaddr {
return append(addrs,
tStringCast(wtAddr),
tStringCast(webrtcAddr),
)
}
h, err := libp2p.New(
libp2p.AddrsFactory(addrsFactory),
libp2p.Transport(libp2pwebrtc.New),
libp2p.Transport(libp2pwebtransport.New),
libp2p.ListenAddrStrings(
"/ip4/0.0.0.0/udp/0/quic-v1/webtransport",
"/ip4/0.0.0.0/udp/0/webrtc-direct",
),
)
require.NoError(t, err)
require.Eventually(t, func() bool {
addrs := h.Addrs()
var hasWebRTC, hasWebTransport bool
for _, addr := range addrs {
if strings.HasPrefix(addr.String(), webrtcAddr) {
if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err == nil {
hasWebRTC = true
}
}
if strings.HasPrefix(addr.String(), wtAddr) {
if _, err := addr.ValueForProtocol(ma.P_CERTHASH); err == nil {
hasWebTransport = true
}
}
}
return hasWebRTC && hasWebTransport
}, 5*time.Second, 100*time.Millisecond)
}