p2p/discover: support incomplete node URLs, add Resolve

This commit is contained in:
Felix Lange
2015-10-22 23:46:01 +02:00
parent 82a024d425
commit d1f507b7f1
7 changed files with 158 additions and 54 deletions

View File

@ -17,10 +17,12 @@
package discover
import (
"fmt"
"math/big"
"math/rand"
"net"
"reflect"
"strings"
"testing"
"testing/quick"
"time"
@ -29,6 +31,27 @@ import (
"github.com/ethereum/go-ethereum/crypto"
)
func ExampleNewNode() {
id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439")
// Complete nodes contain UDP and TCP endpoints:
n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303)
fmt.Println("n1:", n1)
fmt.Println("n1.Incomplete() ->", n1.Incomplete())
// An incomplete node can be created by passing zero values
// for all parameters except id.
n2 := NewNode(id, nil, 0, 0)
fmt.Println("n2:", n2)
fmt.Println("n2.Incomplete() ->", n2.Incomplete())
// Output:
// n1: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:30303?discport=52150
// n1.Incomplete() -> false
// n2: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439
// n2.Incomplete() -> true
}
var parseNodeTests = []struct {
rawurl string
wantError string
@ -38,14 +61,11 @@ var parseNodeTests = []struct {
rawurl: "http://foobar",
wantError: `invalid URL scheme, want "enode"`,
},
{
rawurl: "enode://foobar",
wantError: `does not contain node ID`,
},
{
rawurl: "enode://01010101@123.124.125.126:3",
wantError: `invalid node ID (wrong length, need 64 hex bytes)`,
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
},
// Complete nodes with IP address.
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
wantError: `invalid IP address`,
@ -60,7 +80,7 @@ var parseNodeTests = []struct {
},
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
wantResult: newNode(
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
net.IP{0x7f, 0x0, 0x0, 0x1},
52150,
@ -69,7 +89,7 @@ var parseNodeTests = []struct {
},
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
wantResult: newNode(
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
net.ParseIP("::"),
52150,
@ -78,7 +98,7 @@ var parseNodeTests = []struct {
},
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
wantResult: newNode(
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
52150,
@ -87,33 +107,62 @@ var parseNodeTests = []struct {
},
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
wantResult: newNode(
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
net.IP{0x7f, 0x0, 0x0, 0x1},
22334,
52150,
),
},
// Incomplete nodes with no address.
{
rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
nil, 0, 0,
),
},
{
rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
wantResult: NewNode(
MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
nil, 0, 0,
),
},
// Invalid URLs
{
rawurl: "01010101",
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
},
{
rawurl: "enode://01010101",
wantError: `invalid node ID (wrong length, want 128 hex chars)`,
},
{
// This test checks that errors from url.Parse are handled.
rawurl: "://foo",
wantError: `parse ://foo: missing protocol scheme`,
},
}
func TestParseNode(t *testing.T) {
for i, test := range parseNodeTests {
for _, test := range parseNodeTests {
n, err := ParseNode(test.rawurl)
if test.wantError != "" {
if err == nil {
t.Errorf("test %d: got nil error, expected %#q", i, test.wantError)
t.Errorf("test %q:\n got nil error, expected %#q", test.rawurl, test.wantError)
continue
} else if err.Error() != test.wantError {
t.Errorf("test %d: got error %#q, expected %#q", i, err.Error(), test.wantError)
t.Errorf("test %q:\n got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
continue
}
} else {
if err != nil {
t.Errorf("test %d: unexpected error: %v", i, err)
t.Errorf("test %q:\n unexpected error: %v", test.rawurl, err)
continue
}
if !reflect.DeepEqual(n, test.wantResult) {
t.Errorf("test %d: result mismatch:\ngot: %#v, want: %#v", i, n, test.wantResult)
t.Errorf("test %q:\n result mismatch:\ngot: %#v, want: %#v", test.rawurl, n, test.wantResult)
}
}
}
@ -121,12 +170,11 @@ func TestParseNode(t *testing.T) {
func TestNodeString(t *testing.T) {
for i, test := range parseNodeTests {
if test.wantError != "" {
continue
}
str := test.wantResult.String()
if str != test.rawurl {
t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl)
if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
str := test.wantResult.String()
if str != test.rawurl {
t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl)
}
}
}
}