Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

p2p: refactor connectedness logger #1001

Merged
merged 3 commits into from
Aug 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion p2p/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func NewDiscoveryRouter(tcpNode host.Host, udpNode *MutableUDPNode, peers []Peer
// it returns false if the peer isn't discovered.
func getDiscoveredAddress(udpNode *MutableUDPNode, p Peer) (ma.Multiaddr, bool, error) {
resolved := udpNode.Resolve(&p.Enode)
if resolved.Seq() == 0 || resolved.TCP() == 0 {
if resolved.Seq() == p.Enode.Seq() || resolved.TCP() == 0 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not consider lock file ENRs as "discovered".

return nil, false, nil // Not discovered
}

Expand Down
86 changes: 86 additions & 0 deletions p2p/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright © 2022 Obol Labs Inc.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.

package p2p

import (
"strings"

"github.com/libp2p/go-libp2p/core/peer"
"github.com/libp2p/go-libp2p/p2p/net/swarm"
ma "github.com/multiformats/go-multiaddr"

"github.com/obolnetwork/charon/app/errors"
)

// hasErrDialBackoff returns true if the error contains swarm.ErrDialBackoff.
func hasErrDialBackoff(err error) bool {
dErr := new(swarm.DialError)
if !errors.As(err, &dErr) {
return false
}

for _, trErr := range dErr.DialErrors {
if errors.Is(trErr.Cause, swarm.ErrDialBackoff) {
return true
}
}

return false
}

// dialErrMsgs returns a map of dial error messages by named address or false if the error is not a swarm.DialError.
func dialErrMsgs(err error) (map[string]string, bool) {
dErr := new(swarm.DialError)
if !errors.As(err, &dErr) {
return nil, false
}

// We do not expect cause to be populated.
if dErr.Cause != nil {
return nil, false
}

resp := make(map[string]string)
for _, trErr := range dErr.DialErrors {
resp[NamedAddr(trErr.Address)] = trErr.Cause.Error()
}

return resp, true
}

// NamedAddr returns the multiaddr as a string with peer names instead of peer IDs.
func NamedAddr(addr ma.Multiaddr) string {
var resp []string

ma.ForEach(addr, func(c ma.Component) bool {
if c.Protocol().Code == ma.P_P2P {
if id, err := peer.Decode(c.Value()); err == nil {
resp = append(resp, c.Protocol().Name, PeerName(id))
return true
}
}
if c.Protocol().Name != "" {
resp = append(resp, c.Protocol().Name)
}
if c.Value() != "" {
resp = append(resp, strings.TrimPrefix(c.Value(), "/"))
}

return true
})

return "/" + strings.Join(resp, "/")
}
104 changes: 104 additions & 0 deletions p2p/errors_internal_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
// Copyright © 2022 Obol Labs Inc.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program. If not, see <http://www.gnu.org/licenses/>.

package p2p

import (
"context"
"testing"

"github.com/libp2p/go-libp2p"
"github.com/libp2p/go-libp2p/core/peerstore"
ma "github.com/multiformats/go-multiaddr"
"github.com/stretchr/testify/require"

"github.com/obolnetwork/charon/testutil"
)

//go:generate go test . -clean -update

func TestNamedAddr(t *testing.T) {
// Copied from github.com/multiformats/go-multiaddr/multiaddr_test.go
addrs := []string{
"/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234",
"/ip4/127.0.0.1/udp/1234",
"/ip4/127.0.0.1/udp/0",
"/ip4/127.0.0.1/tcp/1234",
"/ip4/127.0.0.1/tcp/1234/",
"/ip4/127.0.0.1/udp/1234/quic",
"/ip4/127.0.0.1/udp/1234/quic/webtransport",
"/ip4/127.0.0.1/udp/1234/quic/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmpy",
"/ip4/127.0.0.1/udp/1234/quic/webtransport/certhash/b2uaraocy6yrdblb4sfptaddgimjmmpy/certhash/zQmbWTwYGcmdyK9CYfNBcfs9nhZs17a6FQ4Y8oea278xx41",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip4/127.0.0.1/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7",
"/ip4/127.0.0.1/ipfs/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234",
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC",
"/ip4/127.0.0.1/p2p/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234",
"/ip4/127.0.0.1/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7",
"/ip4/127.0.0.1/p2p/k2k4r8oqamigqdo6o7hsbfwd45y70oyynp98usk7zmyfrzpqxh1pohl7/tcp/1234",
"/unix/a/b/c/d/e",
"/unix/stdio",
"/ip4/1.2.3.4/tcp/80/unix/a/b/c/d/e/f",
"/ip4/127.0.0.1/ipfs/QmcgpsyWgH8Y8ajJz1Cu72KnS5uo2Aa2LpzU7kinSupNKC/tcp/1234/unix/stdio",
}

var resp []string
for _, addr := range addrs {
a, err := ma.NewMultiaddr(addr)
require.NoError(t, err)

resp = append(resp, NamedAddr(a))
}

testutil.RequireGoldenJSON(t, resp)
}

func TestDialErrMsgs(t *testing.T) {
ctx := context.Background()

closed, err := NewConnGater(nil, nil)
require.NoError(t, err)
badAddr, err := ma.NewMultiaddr("/ip4/127.0.0.1/tcp/1234/")
require.NoError(t, err)

hostA := testutil.CreateHost(t, testutil.AvailableAddr(t))
hostB := testutil.CreateHost(t, testutil.AvailableAddr(t), libp2p.ConnectionGater(closed))
hostBAddr := hostB.Addrs()[0]

hostA.Peerstore().AddAddr(hostB.ID(), hostBAddr, peerstore.TempAddrTTL) // Gater will block these
hostA.Peerstore().AddAddr(hostB.ID(), badAddr, peerstore.TempAddrTTL) // Connection refused

_, err = hostA.Network().DialPeer(ctx, hostB.ID()) // Try dial
require.Error(t, err)

msgs, ok := dialErrMsgs(err)
require.True(t, ok)
require.False(t, hasErrDialBackoff(err))
require.Len(t, msgs, 2)
require.Contains(t, msgs[badAddr.String()], "connection refused")
require.Contains(t, msgs[hostBAddr.String()], "failed to negotiate stream multiplexer")

_, err = hostA.Network().DialPeer(ctx, hostB.ID()) // Try dial again
require.Error(t, err)

msgs, ok = dialErrMsgs(err)
require.True(t, ok)
require.True(t, hasErrDialBackoff(err))
require.Len(t, msgs, 2)
require.Contains(t, msgs[badAddr.String()], "dial backoff")
require.Contains(t, msgs[hostBAddr.String()], "dial backoff")
}
2 changes: 1 addition & 1 deletion p2p/name.go
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ func randomName(pk ecdsa.PublicKey) string { //nolint:deadcode
return fmt.Sprintf("%s-%s", adjectives[adjIdx], nouns[nounIdx])
}

// PeerName calculates the polynomial rolling hash of the peerID string.
// PeerName returns a deterministic pseudo random human friendly name for the peer ID.
func PeerName(id peer.ID) string {
// p is chosen to be 59 because it's prime and roughly equal to the no of different characters
// you can have in base58 encoded strings. Base58 encoded strings can consist of 58 different
Expand Down
Loading