From e63a02507dd09eb467912223b5201adfbe93b7e0 Mon Sep 17 00:00:00 2001 From: Sukun Date: Fri, 25 Aug 2023 10:28:20 +0530 Subject: [PATCH] swarm: fix Unwrap for DialError, implement Unwrap for TransportError --- p2p/net/swarm/dial_error.go | 25 +++++++++++----- p2p/net/swarm/dial_error_test.go | 51 ++++++++++++++++++++++++++++++++ p2p/net/swarm/swarm_dial_test.go | 2 +- 3 files changed, 70 insertions(+), 8 deletions(-) create mode 100644 p2p/net/swarm/dial_error_test.go diff --git a/p2p/net/swarm/dial_error.go b/p2p/net/swarm/dial_error.go index 711ee06072..4de682204e 100644 --- a/p2p/net/swarm/dial_error.go +++ b/p2p/net/swarm/dial_error.go @@ -30,10 +30,7 @@ func (e *DialError) recordErr(addr ma.Multiaddr, err error) { e.Skipped++ return } - e.DialErrors = append(e.DialErrors, TransportError{ - Address: addr, - Cause: err, - }) + e.DialErrors = append(e.DialErrors, TransportError{Address: addr, Cause: err}) } func (e *DialError) Error() string { @@ -51,9 +48,19 @@ func (e *DialError) Error() string { return builder.String() } -// Unwrap implements https://godoc.org/golang.org/x/xerrors#Wrapper. -func (e *DialError) Unwrap() error { - return e.Cause +func (e *DialError) Unwrap() []error { + if e == nil { + return nil + } + + errs := make([]error, len(e.DialErrors)+1) + if e.Cause != nil { + errs = append(errs, e.Cause) + } + for i := 0; i < len(e.DialErrors); i++ { + errs = append(errs, &e.DialErrors[i]) + } + return errs } var _ error = (*DialError)(nil) @@ -68,4 +75,8 @@ func (e *TransportError) Error() string { return fmt.Sprintf("failed to dial %s: %s", e.Address, e.Cause) } +func (e *TransportError) Unwrap() error { + return e.Cause +} + var _ error = (*TransportError)(nil) diff --git a/p2p/net/swarm/dial_error_test.go b/p2p/net/swarm/dial_error_test.go new file mode 100644 index 0000000000..3231d6f010 --- /dev/null +++ b/p2p/net/swarm/dial_error_test.go @@ -0,0 +1,51 @@ +package swarm + +import ( + "net" + "os" + "testing" + + ma "github.com/multiformats/go-multiaddr" + "github.com/stretchr/testify/require" +) + +func TestTransportError(t *testing.T) { + aa := ma.StringCast("/ip4/1.2.3.4/tcp/1234") + te := &TransportError{Address: aa, Cause: ErrDialBackoff} + require.ErrorIs(t, te, ErrDialBackoff, "TransportError should implement Unwrap") +} + +func TestDialError(t *testing.T) { + de := &DialError{Peer: "pid", Cause: ErrGaterDisallowedConnection} + require.ErrorIs(t, de, ErrGaterDisallowedConnection, + "DialError Unwrap should handle DialError.Cause") + require.ErrorIs(t, de, de, "DialError Unwrap should handle match to self") + + aa := ma.StringCast("/ip4/1.2.3.4/tcp/1234") + ab := ma.StringCast("/ip6/1::1/udp/1234/quic-v1") + de = &DialError{ + Peer: "pid", + DialErrors: []TransportError{ + {Address: aa, Cause: ErrDialBackoff}, {Address: ab, Cause: ErrNoTransport}, + }, + } + require.ErrorIs(t, de, ErrDialBackoff, "DialError.Unwrap should traverse TransportErrors") + require.ErrorIs(t, de, ErrNoTransport, "DialError.Unwrap should traverse TransportErrors") + + de = &DialError{ + Peer: "pid", + DialErrors: []TransportError{{Address: ab, Cause: ErrNoTransport}, + // wrapped error 2 levels deep + {Address: aa, Cause: &net.OpError{ + Op: "write", + Net: "tcp", + Err: &os.SyscallError{ + Syscall: "connect", + Err: os.ErrPermission, + }, + }}, + }, + } + require.ErrorIs(t, de, os.ErrPermission, "DialError.Unwrap should traverse TransportErrors") + +} diff --git a/p2p/net/swarm/swarm_dial_test.go b/p2p/net/swarm/swarm_dial_test.go index 6a4088fe68..3079f9de7a 100644 --- a/p2p/net/swarm/swarm_dial_test.go +++ b/p2p/net/swarm/swarm_dial_test.go @@ -372,5 +372,5 @@ func TestBlackHoledAddrBlocked(t *testing.T) { if !errors.As(err, &de) { t.Fatalf("expected to receive an error of type *DialError, got %s of type %T", err, err) } - require.Contains(t, de.DialErrors, TransportError{Address: addr, Cause: ErrDialRefusedBlackHole}) + require.ErrorIs(t, err, ErrDialRefusedBlackHole) }