mirror of
https://source.quilibrium.com/quilibrium/ceremonyclient.git
synced 2024-12-26 00:25:17 +00:00
400 lines
8.9 KiB
Go
400 lines
8.9 KiB
Go
|
package dual
|
||
|
|
||
|
import (
|
||
|
"context"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
u "github.com/ipfs/boxo/util"
|
||
|
"github.com/ipfs/go-cid"
|
||
|
dht "github.com/libp2p/go-libp2p-kad-dht"
|
||
|
test "github.com/libp2p/go-libp2p-kad-dht/internal/testing"
|
||
|
record "github.com/libp2p/go-libp2p-record"
|
||
|
"github.com/libp2p/go-libp2p/core/host"
|
||
|
"github.com/libp2p/go-libp2p/core/peer"
|
||
|
peerstore "github.com/libp2p/go-libp2p/core/peerstore"
|
||
|
bhost "github.com/libp2p/go-libp2p/p2p/host/basic"
|
||
|
swarmt "github.com/libp2p/go-libp2p/p2p/net/swarm/testing"
|
||
|
"github.com/multiformats/go-multiaddr"
|
||
|
"github.com/stretchr/testify/require"
|
||
|
)
|
||
|
|
||
|
var wancid, lancid cid.Cid
|
||
|
|
||
|
func init() {
|
||
|
wancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("wan cid -- value")))
|
||
|
lancid = cid.NewCidV1(cid.DagCBOR, u.Hash([]byte("lan cid -- value")))
|
||
|
}
|
||
|
|
||
|
type blankValidator struct{}
|
||
|
|
||
|
func (blankValidator) Validate(_ string, _ []byte) error { return nil }
|
||
|
func (blankValidator) Select(_ string, _ [][]byte) (int, error) { return 0, nil }
|
||
|
|
||
|
type customRtHelper struct {
|
||
|
allow peer.ID
|
||
|
}
|
||
|
|
||
|
func MkFilterForPeer() (func(_ interface{}, p peer.ID) bool, *customRtHelper) {
|
||
|
helper := customRtHelper{}
|
||
|
|
||
|
type hasHost interface {
|
||
|
Host() host.Host
|
||
|
}
|
||
|
|
||
|
f := func(dht interface{}, p peer.ID) bool {
|
||
|
d := dht.(hasHost)
|
||
|
conns := d.Host().Network().ConnsToPeer(p)
|
||
|
|
||
|
for _, c := range conns {
|
||
|
if c.RemotePeer() == helper.allow {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
return f, &helper
|
||
|
}
|
||
|
|
||
|
func setupDHTWithFilters(ctx context.Context, t *testing.T, options ...dht.Option) (*DHT, []*customRtHelper) {
|
||
|
h, err := bhost.NewHost(swarmt.GenSwarm(t, swarmt.OptDisableReuseport), new(bhost.HostOpts))
|
||
|
require.NoError(t, err)
|
||
|
h.Start()
|
||
|
t.Cleanup(func() { h.Close() })
|
||
|
|
||
|
wanFilter, wanRef := MkFilterForPeer()
|
||
|
wanOpts := []dht.Option{
|
||
|
dht.NamespacedValidator("v", blankValidator{}),
|
||
|
dht.ProtocolPrefix("/test"),
|
||
|
dht.DisableAutoRefresh(),
|
||
|
dht.RoutingTableFilter(wanFilter),
|
||
|
}
|
||
|
wan, err := dht.New(ctx, h, wanOpts...)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
lanFilter, lanRef := MkFilterForPeer()
|
||
|
lanOpts := []dht.Option{
|
||
|
dht.NamespacedValidator("v", blankValidator{}),
|
||
|
dht.ProtocolPrefix("/test"),
|
||
|
dht.ProtocolExtension(LanExtension),
|
||
|
dht.DisableAutoRefresh(),
|
||
|
dht.RoutingTableFilter(lanFilter),
|
||
|
dht.Mode(dht.ModeServer),
|
||
|
}
|
||
|
lan, err := dht.New(ctx, h, lanOpts...)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
impl := DHT{wan, lan}
|
||
|
return &impl, []*customRtHelper{wanRef, lanRef}
|
||
|
}
|
||
|
|
||
|
func setupDHT(ctx context.Context, t *testing.T, options ...dht.Option) *DHT {
|
||
|
t.Helper()
|
||
|
|
||
|
host, err := bhost.NewHost(swarmt.GenSwarm(t, swarmt.OptDisableReuseport), new(bhost.HostOpts))
|
||
|
require.NoError(t, err)
|
||
|
host.Start()
|
||
|
t.Cleanup(func() { host.Close() })
|
||
|
|
||
|
baseOpts := []dht.Option{
|
||
|
dht.NamespacedValidator("v", blankValidator{}),
|
||
|
dht.ProtocolPrefix("/test"),
|
||
|
dht.DisableAutoRefresh(),
|
||
|
}
|
||
|
|
||
|
d, err := New(
|
||
|
ctx,
|
||
|
host,
|
||
|
append([]Option{DHTOption(baseOpts...)}, DHTOption(options...))...,
|
||
|
)
|
||
|
require.NoError(t, err)
|
||
|
|
||
|
return d
|
||
|
}
|
||
|
|
||
|
func connect(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
|
||
|
t.Helper()
|
||
|
bid := b.PeerID()
|
||
|
baddr := b.Host().Peerstore().Addrs(bid)
|
||
|
if len(baddr) == 0 {
|
||
|
t.Fatal("no addresses for connection.")
|
||
|
}
|
||
|
a.Host().Peerstore().AddAddrs(bid, baddr, peerstore.TempAddrTTL)
|
||
|
if err := a.Host().Connect(ctx, peer.AddrInfo{ID: bid}); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
wait(ctx, t, a, b)
|
||
|
}
|
||
|
|
||
|
func wait(ctx context.Context, t *testing.T, a, b *dht.IpfsDHT) {
|
||
|
t.Helper()
|
||
|
for a.RoutingTable().Find(b.PeerID()) == "" {
|
||
|
// fmt.Fprintf(os.Stderr, "%v\n", a.RoutingTable().GetPeerInfos())
|
||
|
select {
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal(ctx.Err())
|
||
|
case <-time.After(time.Millisecond * 5):
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func setupTier(ctx context.Context, t *testing.T) (*DHT, *dht.IpfsDHT, *dht.IpfsDHT) {
|
||
|
t.Helper()
|
||
|
baseOpts := []dht.Option{
|
||
|
dht.NamespacedValidator("v", blankValidator{}),
|
||
|
dht.ProtocolPrefix("/test"),
|
||
|
dht.DisableAutoRefresh(),
|
||
|
}
|
||
|
|
||
|
d, hlprs := setupDHTWithFilters(ctx, t)
|
||
|
|
||
|
whost, err := bhost.NewHost(swarmt.GenSwarm(t, swarmt.OptDisableReuseport), new(bhost.HostOpts))
|
||
|
require.NoError(t, err)
|
||
|
whost.Start()
|
||
|
t.Cleanup(func() { whost.Close() })
|
||
|
|
||
|
wan, err := dht.New(
|
||
|
ctx,
|
||
|
whost,
|
||
|
append(baseOpts, dht.Mode(dht.ModeServer))...,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
hlprs[0].allow = wan.PeerID()
|
||
|
connect(ctx, t, d.WAN, wan)
|
||
|
|
||
|
lhost, err := bhost.NewHost(swarmt.GenSwarm(t, swarmt.OptDisableReuseport), new(bhost.HostOpts))
|
||
|
require.NoError(t, err)
|
||
|
lhost.Start()
|
||
|
t.Cleanup(func() { lhost.Close() })
|
||
|
|
||
|
lan, err := dht.New(
|
||
|
ctx,
|
||
|
lhost,
|
||
|
append(baseOpts, dht.Mode(dht.ModeServer), dht.ProtocolExtension("/lan"))...,
|
||
|
)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
hlprs[1].allow = lan.PeerID()
|
||
|
connect(ctx, t, d.LAN, lan)
|
||
|
|
||
|
return d, wan, lan
|
||
|
}
|
||
|
|
||
|
func TestDualModes(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d := setupDHT(ctx, t)
|
||
|
defer d.Close()
|
||
|
|
||
|
if d.WAN.Mode() != dht.ModeAuto {
|
||
|
t.Fatal("wrong default mode for wan")
|
||
|
} else if d.LAN.Mode() != dht.ModeServer {
|
||
|
t.Fatal("wrong default mode for lan")
|
||
|
}
|
||
|
|
||
|
d2 := setupDHT(ctx, t, dht.Mode(dht.ModeClient))
|
||
|
defer d2.Close()
|
||
|
if d2.WAN.Mode() != dht.ModeClient ||
|
||
|
d2.LAN.Mode() != dht.ModeClient {
|
||
|
t.Fatal("wrong client mode operation")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFindProviderAsync(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d, wan, lan := setupTier(ctx, t)
|
||
|
defer d.Close()
|
||
|
defer wan.Close()
|
||
|
defer lan.Close()
|
||
|
|
||
|
time.Sleep(5 * time.Millisecond)
|
||
|
|
||
|
if err := wan.Provide(ctx, wancid, false); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
if err := lan.Provide(ctx, lancid, true); err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
wpc := d.FindProvidersAsync(ctx, wancid, 1)
|
||
|
select {
|
||
|
case p := <-wpc:
|
||
|
if p.ID != wan.PeerID() {
|
||
|
t.Fatal("wrong wan provider")
|
||
|
}
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal("find provider timeout.")
|
||
|
}
|
||
|
|
||
|
lpc := d.FindProvidersAsync(ctx, lancid, 1)
|
||
|
select {
|
||
|
case p := <-lpc:
|
||
|
if p.ID != lan.PeerID() {
|
||
|
t.Fatal("wrong lan provider")
|
||
|
}
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal("find provider timeout.")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestValueGetSet(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d, wan, lan := setupTier(ctx, t)
|
||
|
defer d.Close()
|
||
|
defer wan.Close()
|
||
|
defer lan.Close()
|
||
|
|
||
|
time.Sleep(5 * time.Millisecond)
|
||
|
|
||
|
err := d.PutValue(ctx, "/v/hello", []byte("valid"))
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
val, err := wan.GetValue(ctx, "/v/hello")
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if string(val) != "valid" {
|
||
|
t.Fatal("failed to get expected string.")
|
||
|
}
|
||
|
|
||
|
_, err = lan.GetValue(ctx, "/v/hello")
|
||
|
if err == nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestSearchValue(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d, wan, lan := setupTier(ctx, t)
|
||
|
defer d.Close()
|
||
|
defer wan.Close()
|
||
|
defer lan.Close()
|
||
|
|
||
|
d.WAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}
|
||
|
d.LAN.Validator.(record.NamespacedValidator)["v"] = test.TestValidator{}
|
||
|
|
||
|
_ = wan.PutValue(ctx, "/v/hello", []byte("valid"))
|
||
|
|
||
|
valCh, err := d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
select {
|
||
|
case v := <-valCh:
|
||
|
if string(v) != "valid" {
|
||
|
t.Errorf("expected 'valid', got '%s'", string(v))
|
||
|
}
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal(ctx.Err())
|
||
|
}
|
||
|
|
||
|
select {
|
||
|
case _, ok := <-valCh:
|
||
|
if ok {
|
||
|
t.Errorf("chan should close")
|
||
|
}
|
||
|
case <-ctx.Done():
|
||
|
t.Fatal(ctx.Err())
|
||
|
}
|
||
|
|
||
|
err = lan.PutValue(ctx, "/v/hello", []byte("newer"))
|
||
|
if err != nil {
|
||
|
t.Error(err)
|
||
|
}
|
||
|
|
||
|
valCh, err = d.SearchValue(ctx, "/v/hello", dht.Quorum(0))
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
|
||
|
var lastVal []byte
|
||
|
for c := range valCh {
|
||
|
lastVal = c
|
||
|
}
|
||
|
if string(lastVal) != "newer" {
|
||
|
t.Fatal("incorrect best search value")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestGetPublicKey(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d, wan, lan := setupTier(ctx, t)
|
||
|
defer d.Close()
|
||
|
defer wan.Close()
|
||
|
defer lan.Close()
|
||
|
|
||
|
time.Sleep(5 * time.Millisecond)
|
||
|
|
||
|
pk, err := d.GetPublicKey(ctx, wan.PeerID())
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
id, err := peer.IDFromPublicKey(pk)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if id != wan.PeerID() {
|
||
|
t.Fatal("incorrect PK")
|
||
|
}
|
||
|
|
||
|
pk, err = d.GetPublicKey(ctx, lan.PeerID())
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
id, err = peer.IDFromPublicKey(pk)
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
if id != lan.PeerID() {
|
||
|
t.Fatal("incorrect PK")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
func TestFindPeer(t *testing.T) {
|
||
|
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
|
||
|
defer cancel()
|
||
|
|
||
|
d, wan, lan := setupTier(ctx, t)
|
||
|
defer d.Close()
|
||
|
defer wan.Close()
|
||
|
defer lan.Close()
|
||
|
|
||
|
time.Sleep(5 * time.Millisecond)
|
||
|
|
||
|
p, err := d.FindPeer(ctx, lan.PeerID())
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
assertUniqueMultiaddrs(t, p.Addrs)
|
||
|
p, err = d.FindPeer(ctx, wan.PeerID())
|
||
|
if err != nil {
|
||
|
t.Fatal(err)
|
||
|
}
|
||
|
assertUniqueMultiaddrs(t, p.Addrs)
|
||
|
}
|
||
|
|
||
|
func assertUniqueMultiaddrs(t *testing.T, addrs []multiaddr.Multiaddr) {
|
||
|
set := make(map[string]bool)
|
||
|
for _, addr := range addrs {
|
||
|
if set[string(addr.Bytes())] {
|
||
|
t.Errorf("duplicate address %s", addr)
|
||
|
}
|
||
|
set[string(addr.Bytes())] = true
|
||
|
}
|
||
|
}
|