Skip to content

Commit

Permalink
cmd: alpha test peers - add direct connection test (#3073)
Browse files Browse the repository at this point in the history
Adding test for direct connection between peers. This should also implicitly test if our NAT is open.

There is a separate ticket for unit testing for all peers tests, as there are more things to be improved on that side - there need to be couple of nodes spin up, with local relay, to be able to properly test the `testpeers.go` code. As soon as that is done, there will be better testing suite for that test case as well.

To try locally, a local relay needs to be spin up first (or expose your IP and port, however, the former is easier):
`./charon relay --p2p-tcp-address="0.0.0.0:9000" --p2p-advertise-private-addresses`
`./charon alpha test peers --enrs="enr:-Iu4QJyserRukhG0Vgi2csu7GjpHYUGufNEbZ8Q7ZBrcZUb0KqpL5QzHonkh1xxHlxatTxrIcX_IS5J3SEWR_sa0ptGAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQMAUgEqczOjevyculnUIofhCj0DkgJudErM7qCYIvIkzIN0Y3CCDhqDdWRwgg4u" --p2p-relays="http://127.0.0.1:3640" --p2p-tcp-address="127.0.0.1:9001" --load-test-duration=30s`

I have also included small refactor of the return statements, making it a bit more readable.

category: feature
ticket: #3065
  • Loading branch information
KaloyanTanev authored May 14, 2024
1 parent a50b2c0 commit 9c65c8d
Showing 1 changed file with 48 additions and 34 deletions.
82 changes: 48 additions & 34 deletions cmd/testpeers.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

k1 "github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/libp2p/go-libp2p/core/host"
"github.com/libp2p/go-libp2p/core/network"
"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/protocol/ping"
"github.com/spf13/cobra"
Expand All @@ -34,12 +35,13 @@ import (

type testPeersConfig struct {
testConfig
ENRs []string
P2P p2p.Config
Log log.Config
DataDir string
KeepAlive time.Duration
LoadTestDuration time.Duration
ENRs []string
P2P p2p.Config
Log log.Config
DataDir string
KeepAlive time.Duration
LoadTestDuration time.Duration
DirectConnectionTimeout time.Duration
}

type testCasePeer func(context.Context, *testPeersConfig, host.Host, p2p.Peer) testResult
Expand Down Expand Up @@ -81,6 +83,7 @@ func bindTestPeersFlags(cmd *cobra.Command, config *testPeersConfig) {
cmd.Flags().StringSliceVar(&config.ENRs, enrs, nil, "[REQUIRED] Comma-separated list of each peer ENR address.")
cmd.Flags().DurationVar(&config.KeepAlive, "keep-alive", 30*time.Minute, "Time to keep TCP node alive after test completion, so connection is open for other peers to test on their end.")
cmd.Flags().DurationVar(&config.LoadTestDuration, "load-test-duration", 30*time.Second, "Time to keep running the load tests in seconds. For each second a new continuous ping instance is spawned.")
cmd.Flags().DurationVar(&config.DirectConnectionTimeout, "direct-connection-timeout", 2*time.Minute, "Time to keep trying to establish direct connection to peer.")
mustMarkFlagRequired(cmd, enrs)
}

Expand All @@ -96,6 +99,7 @@ func supportedPeerTestCases() map[testCaseName]testCasePeer {
{name: "ping", order: 1}: peerPingTest,
{name: "pingMeasure", order: 2}: peerPingMeasureTest,
{name: "pingLoad", order: 3}: peerPingLoadTest,
{name: "directConn", order: 4}: peerDirectConnTest,
}
}

Expand Down Expand Up @@ -463,32 +467,20 @@ func peerPingTest(ctx context.Context, _ *testPeersConfig, tcpNode host.Host, pe
for ; true; <-ticker.C {
select {
case <-ctx.Done():
testRes.Verdict = testVerdictFail
testRes.Error = errTimeoutInterrupted

return testRes
return failedTestResult(testRes, errTimeoutInterrupted)
default:
ticker.Reset(3 * time.Second)
result, err := pingPeerOnce(ctx, tcpNode, peer)
if err != nil {
testRes.Verdict = testVerdictFail
testRes.Error = testResultError{err}

return testRes
return failedTestResult(testRes, err)
}

if result.Error != nil {
switch {
case errors.Is(result.Error, context.DeadlineExceeded):
testRes.Verdict = testVerdictFail
testRes.Error = errTimeoutInterrupted

return testRes
return failedTestResult(testRes, errTimeoutInterrupted)
case p2p.IsRelayError(result.Error):
testRes.Verdict = testVerdictFail
testRes.Error = testResultError{result.Error}

return testRes
return failedTestResult(testRes, result.Error)
default:
log.Warn(ctx, "Ping to peer failed, retrying in 3 sec...", nil, z.Str("peer_name", peer.Name))
continue
Expand All @@ -512,16 +504,10 @@ func peerPingMeasureTest(ctx context.Context, _ *testPeersConfig, tcpNode host.H

result, err := pingPeerOnce(ctx, tcpNode, peer)
if err != nil {
testRes.Verdict = testVerdictFail
testRes.Error = testResultError{err}

return testRes
return failedTestResult(testRes, err)
}
if result.Error != nil {
testRes.Verdict = testVerdictFail
testRes.Error = testResultError{result.Error}

return testRes
return failedTestResult(testRes, result.Error)
}

if result.RTT > thresholdMeasureBad {
Expand Down Expand Up @@ -563,6 +549,7 @@ func peerPingLoadTest(ctx context.Context, conf *testPeersConfig, tcpNode host.H
}
wg.Wait()
close(testResCh)
log.Info(ctx, "Ping load tests finished", z.Any("target", peer.Name))

highestRTT := time.Duration(0)
for val := range testResCh {
Expand Down Expand Up @@ -606,6 +593,36 @@ func dialLibp2pTCPIP(ctx context.Context, address string) error {
return nil
}

func peerDirectConnTest(ctx context.Context, conf *testPeersConfig, tcpNode host.Host, p2pPeer p2p.Peer) testResult {
testRes := testResult{Name: "DirectConn"}

log.Info(ctx, "Trying to establish direct connection...",
z.Any("timeout", conf.DirectConnectionTimeout),
z.Any("target", p2pPeer.Name))

var err error
for i := 0; i < int(conf.DirectConnectionTimeout); i++ {
err = tcpNode.Connect(network.WithForceDirectDial(ctx, "relay_to_direct"), peer.AddrInfo{ID: p2pPeer.ID})
if err == nil {
break
}
time.Sleep(time.Second)
}
if err != nil {
return failedTestResult(testRes, err)
}
log.Info(ctx, "Direct connection established", z.Any("target", p2pPeer.Name))

conns := tcpNode.Network().ConnsToPeer(p2pPeer.ID)
if len(conns) < 2 {
return failedTestResult(testRes, errors.New("expected 2 connections to peer (relay and direct)", z.Int("connections", len(conns))))
}

testRes.Verdict = testVerdictOk

return testRes
}

func libp2pTCPPortOpenTest(ctx context.Context, cfg *testPeersConfig) testResult {
testRes := testResult{Name: "Libp2pTCPPortOpen"}

Expand All @@ -618,10 +635,7 @@ func libp2pTCPPortOpenTest(ctx context.Context, cfg *testPeersConfig) testResult

err := group.Wait()
if err != nil {
testRes.Verdict = testVerdictFail
testRes.Error = testResultError{err}

return testRes
return failedTestResult(testRes, err)
}

testRes.Verdict = testVerdictOk
Expand Down

0 comments on commit 9c65c8d

Please sign in to comment.