github.com/Blockdaemon/celo-blockchain@v0.0.0-20200129231733-e667f6b08419/p2p/enode/urlv4_test.go (about)

     1  // Copyright 2018 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package enode
    18  
    19  import (
    20  	"bytes"
    21  	"crypto/ecdsa"
    22  	"math/big"
    23  	"net"
    24  	"reflect"
    25  	"strings"
    26  	"testing"
    27  	"testing/quick"
    28  )
    29  
    30  var parseNodeTests = []struct {
    31  	rawurl      string
    32  	wantError   string
    33  	wantResult  *Node
    34  	wantPrivate bool
    35  }{
    36  	{
    37  		rawurl:    "http://foobar",
    38  		wantError: `invalid URL scheme, want "enode"`,
    39  	},
    40  	{
    41  		rawurl:    "enode://01010101@123.124.125.126:3",
    42  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    43  	},
    44  	// Complete nodes with IP address.
    45  	{
    46  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
    47  		wantError: `invalid IP address`,
    48  	},
    49  	{
    50  		// net/url.Parse(rawurl) returns an error with rawurl and why the parse failed.
    51  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
    52  		wantError: `invalid port`,
    53  	},
    54  	{
    55  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
    56  		wantError: `invalid discport in query`,
    57  	},
    58  	{
    59  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
    60  		wantResult: NewV4(
    61  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    62  			net.IP{0x7f, 0x0, 0x0, 0x1},
    63  			52150,
    64  			52150,
    65  		),
    66  		wantPrivate: true,
    67  	},
    68  	{
    69  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@5.1.1.1:52150",
    70  		wantResult: NewV4(
    71  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    72  			net.IP{0x5, 0x1, 0x1, 0x1},
    73  			52150,
    74  			52150,
    75  		),
    76  		wantPrivate: false,
    77  	},
    78  	{
    79  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
    80  		wantResult: NewV4(
    81  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    82  			net.ParseIP("::"),
    83  			52150,
    84  			52150,
    85  		),
    86  		wantPrivate: true,
    87  	},
    88  	{
    89  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@172.17.0.3:52150",
    90  		wantResult: NewV4(
    91  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    92  			net.ParseIP("172.17.0.3"),
    93  			52150,
    94  			52150,
    95  		),
    96  		wantPrivate: true,
    97  	},
    98  	{
    99  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
   100  		wantResult: NewV4(
   101  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   102  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   103  			52150,
   104  			52150,
   105  		),
   106  	},
   107  	{
   108  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
   109  		wantResult: NewV4(
   110  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   111  			net.IP{0x7f, 0x0, 0x0, 0x1},
   112  			52150,
   113  			22334,
   114  		),
   115  		wantPrivate: true,
   116  	},
   117  	// Incomplete nodes with no address.
   118  	{
   119  		rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   120  		wantResult: NewV4(
   121  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   122  			nil, 0, 0,
   123  		),
   124  	},
   125  	{
   126  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   127  		wantResult: NewV4(
   128  			hexPubkey("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   129  			nil, 0, 0,
   130  		),
   131  	},
   132  	// Invalid URLs
   133  	{
   134  		rawurl:    "01010101",
   135  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   136  	},
   137  	{
   138  		rawurl:    "enode://01010101",
   139  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   140  	},
   141  	{
   142  		// This test checks that errors from url.Parse are handled.
   143  		rawurl:    "://foo",
   144  		wantError: `parse ://foo: missing protocol scheme`,
   145  	},
   146  }
   147  
   148  func hexPubkey(h string) *ecdsa.PublicKey {
   149  	k, err := parsePubkey(h)
   150  	if err != nil {
   151  		panic(err)
   152  	}
   153  	return k
   154  }
   155  
   156  func TestParseNode(t *testing.T) {
   157  	for _, test := range parseNodeTests {
   158  		n, err := ParseV4(test.rawurl)
   159  		if test.wantError != "" {
   160  			if err == nil {
   161  				t.Errorf("test %q:\n  got nil error, expected %#q", test.rawurl, test.wantError)
   162  				continue
   163  			} else if !strings.Contains(err.Error(), test.wantError) {
   164  				t.Errorf("test %q:\n  got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
   165  				continue
   166  			}
   167  		} else {
   168  			if err != nil {
   169  				t.Errorf("test %q:\n  unexpected error: %v", test.rawurl, err)
   170  				continue
   171  			}
   172  			if !reflect.DeepEqual(n, test.wantResult) {
   173  				t.Errorf("test %q:\n  result mismatch:\ngot:  %#v\nwant: %#v", test.rawurl, n, test.wantResult)
   174  			}
   175  			if !n.Incomplete() && n.IsPrivateIP() != test.wantPrivate {
   176  				t.Errorf("test %q:\n  isPrivate mismatch:\nfor  %#v\ngot:  %#v\nwant: %#v", test.rawurl, n, n.IsPrivateIP(), test.wantPrivate)
   177  			}
   178  		}
   179  	}
   180  }
   181  
   182  func TestNodeString(t *testing.T) {
   183  	for i, test := range parseNodeTests {
   184  		if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
   185  			str := test.wantResult.String()
   186  			if str != test.rawurl {
   187  				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, test.rawurl)
   188  			}
   189  		}
   190  	}
   191  }
   192  
   193  func TestHexID(t *testing.T) {
   194  	ref := ID{0, 0, 0, 0, 0, 0, 0, 128, 106, 217, 182, 31, 165, 174, 1, 67, 7, 235, 220, 150, 66, 83, 173, 205, 159, 44, 10, 57, 42, 161, 26, 188}
   195  	id1 := HexID("0x00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   196  	id2 := HexID("00000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   197  
   198  	if id1 != ref {
   199  		t.Errorf("wrong id1\ngot  %v\nwant %v", id1[:], ref[:])
   200  	}
   201  	if id2 != ref {
   202  		t.Errorf("wrong id2\ngot  %v\nwant %v", id2[:], ref[:])
   203  	}
   204  }
   205  
   206  func TestID_textEncoding(t *testing.T) {
   207  	ref := ID{
   208  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
   209  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
   210  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
   211  		0x31, 0x32,
   212  	}
   213  	hex := "0102030405060708091011121314151617181920212223242526272829303132"
   214  
   215  	text, err := ref.MarshalText()
   216  	if err != nil {
   217  		t.Fatal(err)
   218  	}
   219  	if !bytes.Equal(text, []byte(hex)) {
   220  		t.Fatalf("text encoding did not match\nexpected: %s\ngot:      %s", hex, text)
   221  	}
   222  
   223  	id := new(ID)
   224  	if err := id.UnmarshalText(text); err != nil {
   225  		t.Fatal(err)
   226  	}
   227  	if *id != ref {
   228  		t.Fatalf("text decoding did not match\nexpected: %s\ngot:      %s", ref, id)
   229  	}
   230  }
   231  
   232  func TestNodeID_distcmp(t *testing.T) {
   233  	distcmpBig := func(target, a, b ID) int {
   234  		tbig := new(big.Int).SetBytes(target[:])
   235  		abig := new(big.Int).SetBytes(a[:])
   236  		bbig := new(big.Int).SetBytes(b[:])
   237  		return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig))
   238  	}
   239  	if err := quick.CheckEqual(DistCmp, distcmpBig, nil); err != nil {
   240  		t.Error(err)
   241  	}
   242  }
   243  
   244  // The random tests is likely to miss the case where a and b are equal,
   245  // this test checks it explicitly.
   246  func TestNodeID_distcmpEqual(t *testing.T) {
   247  	base := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   248  	x := ID{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
   249  	if DistCmp(base, x, x) != 0 {
   250  		t.Errorf("DistCmp(base, x, x) != 0")
   251  	}
   252  }
   253  
   254  func TestNodeID_logdist(t *testing.T) {
   255  	logdistBig := func(a, b ID) int {
   256  		abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:])
   257  		return new(big.Int).Xor(abig, bbig).BitLen()
   258  	}
   259  	if err := quick.CheckEqual(LogDist, logdistBig, nil); err != nil {
   260  		t.Error(err)
   261  	}
   262  }
   263  
   264  // The random tests is likely to miss the case where a and b are equal,
   265  // this test checks it explicitly.
   266  func TestNodeID_logdistEqual(t *testing.T) {
   267  	x := ID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   268  	if LogDist(x, x) != 0 {
   269  		t.Errorf("LogDist(x, x) != 0")
   270  	}
   271  }