mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
p2p/enode: implement base64 text format
This commit is contained in:
parent
e527144fe3
commit
fd41587237
3 changed files with 120 additions and 47 deletions
|
|
@ -18,6 +18,7 @@ package enode
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -27,8 +28,11 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/p2p/enr"
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var errMissingPrefix = errors.New("missing 'enr:' prefix for base64-encoded record")
|
||||||
|
|
||||||
// Node represents a host on the network.
|
// Node represents a host on the network.
|
||||||
type Node struct {
|
type Node struct {
|
||||||
r enr.Record
|
r enr.Record
|
||||||
|
|
@ -48,6 +52,34 @@ func New(validSchemes enr.IdentityScheme, r *enr.Record) (*Node, error) {
|
||||||
return node, nil
|
return node, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MustParse parses a node record or enode:// URL. It panics if the input is invalid.
|
||||||
|
func MustParse(rawurl string) *Node {
|
||||||
|
n, err := Parse(ValidSchemes, rawurl)
|
||||||
|
if err != nil {
|
||||||
|
panic("invalid node: " + err.Error())
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse decodes and verifies a base64-encoded node record.
|
||||||
|
func Parse(validSchemes enr.IdentityScheme, input string) (*Node, error) {
|
||||||
|
if strings.HasPrefix(input, "enode://") {
|
||||||
|
return ParseV4(input)
|
||||||
|
}
|
||||||
|
if !strings.HasPrefix(input, "enr:") {
|
||||||
|
return nil, errMissingPrefix
|
||||||
|
}
|
||||||
|
bin, err := base64.RawURLEncoding.DecodeString(input[4:])
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var r enr.Record
|
||||||
|
if err := rlp.DecodeBytes(bin, &r); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return New(validSchemes, &r)
|
||||||
|
}
|
||||||
|
|
||||||
// ID returns the node identifier.
|
// ID returns the node identifier.
|
||||||
func (n *Node) ID() ID {
|
func (n *Node) ID() ID {
|
||||||
return n.id
|
return n.id
|
||||||
|
|
@ -113,10 +145,11 @@ func (n *Node) Record() *enr.Record {
|
||||||
return &cpy
|
return &cpy
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks whether n is a valid complete node.
|
// ValidateComplete checks whether n has a valid IP and UDP port.
|
||||||
|
// Deprecated: don't use this method.
|
||||||
func (n *Node) ValidateComplete() error {
|
func (n *Node) ValidateComplete() error {
|
||||||
if n.Incomplete() {
|
if n.Incomplete() {
|
||||||
return errors.New("incomplete node")
|
return errors.New("missing IP address")
|
||||||
}
|
}
|
||||||
if n.UDP() == 0 {
|
if n.UDP() == 0 {
|
||||||
return errors.New("missing UDP port")
|
return errors.New("missing UDP port")
|
||||||
|
|
@ -130,20 +163,24 @@ func (n *Node) ValidateComplete() error {
|
||||||
return n.Load(&key)
|
return n.Load(&key)
|
||||||
}
|
}
|
||||||
|
|
||||||
// The string representation of a Node is a URL.
|
// String returns the text representation of the record.
|
||||||
// Please see ParseNode for a description of the format.
|
|
||||||
func (n *Node) String() string {
|
func (n *Node) String() string {
|
||||||
return n.v4URL()
|
if isNewV4(n) {
|
||||||
|
return n.URLv4() // backwards-compatibility glue for NewV4 nodes
|
||||||
|
}
|
||||||
|
enc, _ := rlp.EncodeToBytes(&n.r) // always succeeds because record is valid
|
||||||
|
b64 := base64.RawURLEncoding.EncodeToString(enc)
|
||||||
|
return "enr:" + b64
|
||||||
}
|
}
|
||||||
|
|
||||||
// MarshalText implements encoding.TextMarshaler.
|
// MarshalText implements encoding.TextMarshaler.
|
||||||
func (n *Node) MarshalText() ([]byte, error) {
|
func (n *Node) MarshalText() ([]byte, error) {
|
||||||
return []byte(n.v4URL()), nil
|
return []byte(n.String()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnmarshalText implements encoding.TextUnmarshaler.
|
// UnmarshalText implements encoding.TextUnmarshaler.
|
||||||
func (n *Node) UnmarshalText(text []byte) error {
|
func (n *Node) UnmarshalText(text []byte) error {
|
||||||
dec, err := ParseV4(string(text))
|
dec, err := Parse(ValidSchemes, string(text))
|
||||||
if err == nil {
|
if err == nil {
|
||||||
*n = *dec
|
*n = *dec
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ func ParseV4(rawurl string) (*Node, error) {
|
||||||
if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
|
if m := incompleteNodeURL.FindStringSubmatch(rawurl); m != nil {
|
||||||
id, err := parsePubkey(m[1])
|
id, err := parsePubkey(m[1])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
return nil, fmt.Errorf("invalid public key (%v)", err)
|
||||||
}
|
}
|
||||||
return NewV4(id, nil, 0, 0), nil
|
return NewV4(id, nil, 0, 0), nil
|
||||||
}
|
}
|
||||||
|
|
@ -98,6 +98,12 @@ func NewV4(pubkey *ecdsa.PublicKey, ip net.IP, tcp, udp int) *Node {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isNewV4 returns true for nodes created by NewV4.
|
||||||
|
func isNewV4(n *Node) bool {
|
||||||
|
var k s256raw
|
||||||
|
return n.r.IdentityScheme() == "" && n.r.Load(&k) == nil && len(n.r.Signature()) == 0
|
||||||
|
}
|
||||||
|
|
||||||
func parseComplete(rawurl string) (*Node, error) {
|
func parseComplete(rawurl string) (*Node, error) {
|
||||||
var (
|
var (
|
||||||
id *ecdsa.PublicKey
|
id *ecdsa.PublicKey
|
||||||
|
|
@ -116,7 +122,7 @@ func parseComplete(rawurl string) (*Node, error) {
|
||||||
return nil, errors.New("does not contain node ID")
|
return nil, errors.New("does not contain node ID")
|
||||||
}
|
}
|
||||||
if id, err = parsePubkey(u.User.String()); err != nil {
|
if id, err = parsePubkey(u.User.String()); err != nil {
|
||||||
return nil, fmt.Errorf("invalid node ID (%v)", err)
|
return nil, fmt.Errorf("invalid public key (%v)", err)
|
||||||
}
|
}
|
||||||
// Parse the IP address.
|
// Parse the IP address.
|
||||||
host, port, err := net.SplitHostPort(u.Host)
|
host, port, err := net.SplitHostPort(u.Host)
|
||||||
|
|
@ -153,7 +159,7 @@ func parsePubkey(in string) (*ecdsa.PublicKey, error) {
|
||||||
return crypto.UnmarshalPubkey(b)
|
return crypto.UnmarshalPubkey(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) v4URL() string {
|
func (n *Node) URLv4() string {
|
||||||
var (
|
var (
|
||||||
scheme enr.ID
|
scheme enr.ID
|
||||||
nodeid string
|
nodeid string
|
||||||
|
|
|
||||||
|
|
@ -22,36 +22,58 @@ import (
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/p2p/enr"
|
||||||
)
|
)
|
||||||
|
|
||||||
var parseNodeTests = []struct {
|
var parseNodeTests = []struct {
|
||||||
rawurl string
|
input string
|
||||||
wantError string
|
wantError string
|
||||||
wantResult *Node
|
wantResult *Node
|
||||||
}{
|
}{
|
||||||
|
// Records
|
||||||
{
|
{
|
||||||
rawurl: "http://foobar",
|
input: "enr:-IS4QGrdq0ugARp5T2BZ41TrZOqLc_oKvZoPuZP5--anqWE_J-Tucc1xgkOL7qXl0puJgT7qc2KSvcupc4NCb0nr4tdjgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQM6UUF2Rm-oFe1IH_rQkRCi00T2ybeMHRSvw1HDpRvjPYN1ZHCCdl8",
|
||||||
wantError: `invalid URL scheme, want "enode"`,
|
wantResult: func() *Node {
|
||||||
|
testKey, _ := crypto.HexToECDSA("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8")
|
||||||
|
var r enr.Record
|
||||||
|
r.Set(enr.IP{127, 0, 0, 1})
|
||||||
|
r.Set(enr.UDP(30303))
|
||||||
|
r.SetSeq(99)
|
||||||
|
SignV4(&r, testKey)
|
||||||
|
n, _ := New(ValidSchemes, &r)
|
||||||
|
return n
|
||||||
|
}(),
|
||||||
|
},
|
||||||
|
// Invalid Records
|
||||||
|
{
|
||||||
|
input: "enr:",
|
||||||
|
wantError: "EOF", // could be nicer
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://01010101@123.124.125.126:3",
|
input: "enr:x",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: "illegal base64 data at input byte 0",
|
||||||
},
|
},
|
||||||
// Complete nodes with IP address.
|
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
|
input: "enr:-EmGZm9vYmFyY4JpZIJ2NIJpcIR_AAABiXNlY3AyNTZrMaEDOlFBdkZvqBXtSB_60JEQotNE9sm3jB0Ur8NRw6Ub4z2DdWRwgnZf",
|
||||||
|
wantError: enr.ErrInvalidSig.Error(),
|
||||||
|
},
|
||||||
|
// Complete node URLs with IP address and ports
|
||||||
|
{
|
||||||
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
|
||||||
wantError: `invalid IP address`,
|
wantError: `invalid IP address`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
|
||||||
wantError: `invalid port`,
|
wantError: `invalid port`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
|
||||||
wantError: `invalid discport in query`,
|
wantError: `invalid discport in query`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
net.IP{0x7f, 0x0, 0x0, 0x1},
|
net.IP{0x7f, 0x0, 0x0, 0x1},
|
||||||
|
|
@ -60,7 +82,7 @@ var parseNodeTests = []struct {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
net.ParseIP("::"),
|
net.ParseIP("::"),
|
||||||
|
|
@ -69,7 +91,7 @@ var parseNodeTests = []struct {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
|
net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
|
||||||
|
|
@ -78,7 +100,7 @@ var parseNodeTests = []struct {
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
net.IP{0x7f, 0x0, 0x0, 0x1},
|
net.IP{0x7f, 0x0, 0x0, 0x1},
|
||||||
|
|
@ -86,16 +108,9 @@ var parseNodeTests = []struct {
|
||||||
22334,
|
22334,
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
// Incomplete nodes with no address.
|
// Incomplete node URLs with no address
|
||||||
{
|
{
|
||||||
rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
input: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
||||||
wantResult: NewV4(
|
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
|
||||||
nil, 0, 0,
|
|
||||||
),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
|
||||||
wantResult: NewV4(
|
wantResult: NewV4(
|
||||||
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
|
||||||
nil, 0, 0,
|
nil, 0, 0,
|
||||||
|
|
@ -103,17 +118,32 @@ var parseNodeTests = []struct {
|
||||||
},
|
},
|
||||||
// Invalid URLs
|
// Invalid URLs
|
||||||
{
|
{
|
||||||
rawurl: "01010101",
|
input: "",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: errMissingPrefix.Error(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
rawurl: "enode://01010101",
|
input: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
|
||||||
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
|
wantError: errMissingPrefix.Error(),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
// This test checks that errors from url.Parse are handled.
|
input: "01010101",
|
||||||
rawurl: "://foo",
|
wantError: errMissingPrefix.Error(),
|
||||||
wantError: `parse ://foo: missing protocol scheme`,
|
},
|
||||||
|
{
|
||||||
|
input: "enode://01010101@123.124.125.126:3",
|
||||||
|
wantError: `invalid public key (wrong length, want 128 hex chars)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "enode://01010101",
|
||||||
|
wantError: `invalid public key (wrong length, want 128 hex chars)`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "http://foobar",
|
||||||
|
wantError: errMissingPrefix.Error(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
input: "://foo",
|
||||||
|
wantError: errMissingPrefix.Error(),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -127,22 +157,22 @@ func hexPubkey(h string) *ecdsa.PublicKey {
|
||||||
|
|
||||||
func TestParseNode(t *testing.T) {
|
func TestParseNode(t *testing.T) {
|
||||||
for _, test := range parseNodeTests {
|
for _, test := range parseNodeTests {
|
||||||
n, err := ParseV4(test.rawurl)
|
n, err := Parse(ValidSchemes, test.input)
|
||||||
if test.wantError != "" {
|
if test.wantError != "" {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Errorf("test %q:\n got nil error, expected %#q", test.rawurl, test.wantError)
|
t.Errorf("test %q:\n got nil error, expected %#q", test.input, test.wantError)
|
||||||
continue
|
continue
|
||||||
} else if err.Error() != test.wantError {
|
} else if err.Error() != test.wantError {
|
||||||
t.Errorf("test %q:\n got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
|
t.Errorf("test %q:\n got error %#q, expected %#q", test.input, err.Error(), test.wantError)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("test %q:\n unexpected error: %v", test.rawurl, err)
|
t.Errorf("test %q:\n unexpected error: %v", test.input, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(n, test.wantResult) {
|
if !reflect.DeepEqual(n, test.wantResult) {
|
||||||
t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.rawurl, n, test.wantResult)
|
t.Errorf("test %q:\n result mismatch:\ngot: %#v\nwant: %#v", test.input, n, test.wantResult)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -150,10 +180,10 @@ func TestParseNode(t *testing.T) {
|
||||||
|
|
||||||
func TestNodeString(t *testing.T) {
|
func TestNodeString(t *testing.T) {
|
||||||
for i, test := range parseNodeTests {
|
for i, test := range parseNodeTests {
|
||||||
if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
|
if test.wantError == "" && strings.HasPrefix(test.input, "enode://") {
|
||||||
str := test.wantResult.String()
|
str := test.wantResult.String()
|
||||||
if str != test.rawurl {
|
if str != test.input {
|
||||||
t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl)
|
t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.input)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue