github.com/klaytn/klaytn@v1.12.1/networks/p2p/discover/node_test.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from p2p/discover/node_test.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package discover
    22  
    23  import (
    24  	"bytes"
    25  	"errors"
    26  	"fmt"
    27  	"math/big"
    28  	"math/rand"
    29  	"net"
    30  	"reflect"
    31  	"strings"
    32  	"testing"
    33  	"testing/quick"
    34  	"time"
    35  
    36  	"github.com/klaytn/klaytn/common"
    37  	"github.com/klaytn/klaytn/crypto"
    38  )
    39  
    40  func init() {
    41  	lookupIPFunc = func(name string) ([]net.IP, error) {
    42  		if name == "node.example.org" {
    43  			return []net.IP{{33, 44, 55, 66}}, nil
    44  		}
    45  		if name == "1234.com" {
    46  			return []net.IP{{11, 22, 33, 44}}, nil
    47  		}
    48  		return nil, errors.New("no such host")
    49  	}
    50  }
    51  
    52  func ExampleNewNode() {
    53  	id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439")
    54  
    55  	// Complete nodes contain UDP and TCP endpoints:
    56  	n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303, nil, NodeTypeUnknown)
    57  	fmt.Println("n1:", n1)
    58  	fmt.Println("n1.Incomplete() ->", n1.Incomplete())
    59  
    60  	// An incomplete node can be created by passing zero values
    61  	// for all parameters except id.
    62  	n2 := NewNode(id, nil, 0, 0, nil, NodeTypeUnknown)
    63  	fmt.Println("n2:", n2)
    64  	fmt.Println("n2.Incomplete() ->", n2.Incomplete())
    65  
    66  	// Output:
    67  	// n1: kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:30303?discport=52150
    68  	// n1.Incomplete() -> false
    69  	// n2: kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439
    70  	// n2.Incomplete() -> true
    71  }
    72  
    73  var parseNodeTests = []struct {
    74  	rawurl         string
    75  	wantError      string
    76  	wantResult     *Node
    77  	wantNodeString string
    78  }{
    79  	{
    80  		rawurl:    "http://foobar",
    81  		wantError: `invalid URL scheme, want "kni"`,
    82  	},
    83  	{
    84  		rawurl:    "enode://01010101@123.124.125.126:3",
    85  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    86  	},
    87  	{
    88  		rawurl:    "kni://01010101@123.124.125.126:3",
    89  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    90  	},
    91  	// Complete nodes with IP address.
    92  	{
    93  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
    94  		wantError: `no such host`,
    95  	},
    96  	{
    97  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
    98  		wantError: `invalid port`,
    99  	},
   100  	{
   101  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
   102  		wantError: `invalid discport in query`,
   103  	},
   104  	{
   105  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
   106  		wantResult: NewNode(
   107  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   108  			net.IP{127, 0, 0, 1},
   109  			52150,
   110  			52150,
   111  			nil,
   112  			NodeTypeUnknown,
   113  		),
   114  	},
   115  	{
   116  		rawurl:         "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@node.example.org:52150",
   117  		wantNodeString: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@33.44.55.66:52150",
   118  		wantResult: NewNode(
   119  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   120  			net.IP{33, 44, 55, 66},
   121  			52150,
   122  			52150,
   123  			nil,
   124  			NodeTypeUnknown,
   125  		),
   126  	},
   127  	{
   128  		rawurl:         "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@1234.com:52150",
   129  		wantNodeString: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@11.22.33.44:52150",
   130  		wantResult: NewNode(
   131  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   132  			net.IP{11, 22, 33, 44},
   133  			52150,
   134  			52150,
   135  			nil,
   136  			NodeTypeUnknown,
   137  		),
   138  	},
   139  	{
   140  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
   141  		wantResult: NewNode(
   142  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   143  			net.ParseIP("::"),
   144  			52150,
   145  			52150,
   146  			nil,
   147  			NodeTypeUnknown,
   148  		),
   149  	},
   150  	{
   151  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
   152  		wantResult: NewNode(
   153  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   154  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   155  			52150,
   156  			52150,
   157  			nil,
   158  			NodeTypeUnknown,
   159  		),
   160  	},
   161  	{
   162  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
   163  		wantResult: NewNode(
   164  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   165  			net.IP{0x7f, 0x0, 0x0, 0x1},
   166  			22334,
   167  			52150,
   168  			nil,
   169  			NodeTypeUnknown,
   170  		),
   171  	},
   172  	{
   173  		rawurl:    "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
   174  		wantError: `no such host`,
   175  	},
   176  	{
   177  		rawurl:    "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
   178  		wantError: `invalid port`,
   179  	},
   180  	{
   181  		rawurl:    "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
   182  		wantError: `invalid discport in query`,
   183  	},
   184  	{
   185  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
   186  		wantResult: NewNode(
   187  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   188  			net.IP{0x7f, 0x0, 0x0, 0x1},
   189  			52150,
   190  			52150,
   191  			nil,
   192  			NodeTypeUnknown,
   193  		),
   194  	},
   195  	{
   196  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
   197  		wantResult: NewNode(
   198  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   199  			net.ParseIP("::"),
   200  			52150,
   201  			52150,
   202  			nil,
   203  			NodeTypeUnknown,
   204  		),
   205  	},
   206  	{
   207  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
   208  		wantResult: NewNode(
   209  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   210  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   211  			52150,
   212  			52150,
   213  			nil,
   214  			NodeTypeUnknown,
   215  		),
   216  	},
   217  	{
   218  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
   219  		wantResult: NewNode(
   220  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   221  			net.IP{0x7f, 0x0, 0x0, 0x1},
   222  			22334,
   223  			52150,
   224  			nil,
   225  			NodeTypeUnknown,
   226  		),
   227  	},
   228  	// Incomplete nodes with no address.
   229  	{
   230  		rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   231  		wantResult: NewNode(
   232  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   233  			nil, 0, 0, nil,
   234  			NodeTypeUnknown,
   235  		),
   236  	},
   237  	{
   238  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   239  		wantResult: NewNode(
   240  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   241  			nil, 0, 0, nil,
   242  			NodeTypeUnknown,
   243  		),
   244  	},
   245  	{
   246  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   247  		wantResult: NewNode(
   248  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   249  			nil, 0, 0, nil,
   250  			NodeTypeUnknown,
   251  		),
   252  	},
   253  	{
   254  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?subport=1",
   255  		wantResult: NewNode(
   256  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   257  			net.IP{0x7f, 0x0, 0x0, 0x1},
   258  			52150,
   259  			52150,
   260  			[]uint16{1, 52150},
   261  			NodeTypeUnknown,
   262  		),
   263  	},
   264  	{
   265  		rawurl: "kni://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=123&subport=1&subport=2",
   266  		wantResult: NewNode(
   267  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   268  			net.IP{0x7f, 0x0, 0x0, 0x1},
   269  			123,
   270  			52150,
   271  			[]uint16{1, 2, 52150},
   272  			NodeTypeUnknown,
   273  		),
   274  	},
   275  	// Invalid URLs
   276  	{
   277  		rawurl:    "01010101",
   278  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   279  	},
   280  	{
   281  		rawurl:    "enode://01010101",
   282  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   283  	},
   284  	{
   285  		rawurl:    "kni://01010101",
   286  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   287  	},
   288  	{
   289  		// This test checks that errors from url.Parse are handled.
   290  		rawurl:    "://foo",
   291  		wantError: `missing protocol scheme`,
   292  	},
   293  }
   294  
   295  func convertNodeScheme(rawstr string) string {
   296  	converted := rawstr
   297  	if strings.HasPrefix(rawstr, "enode://") {
   298  		converted = "kni://" + rawstr[len("enode://"):]
   299  	}
   300  	return converted
   301  }
   302  
   303  func TestParseNode(t *testing.T) {
   304  	for _, test := range parseNodeTests {
   305  		n, err := ParseNode(test.rawurl)
   306  		if test.wantError != "" {
   307  			if err == nil {
   308  				t.Errorf("test %q:\n  got nil error, expected %#q", test.rawurl, test.wantError)
   309  				continue
   310  			} else if !strings.Contains(err.Error(), test.wantError) {
   311  				t.Errorf("test %q:\n  got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
   312  				continue
   313  			}
   314  		} else {
   315  			if err != nil {
   316  				t.Errorf("test %q:\n  unexpected error: %v", test.rawurl, err)
   317  				continue
   318  			}
   319  			if !reflect.DeepEqual(n, test.wantResult) {
   320  				t.Errorf("test %q:\n  result mismatch:\ngot:  %#v, want: %#v", test.rawurl, n, test.wantResult)
   321  			}
   322  		}
   323  	}
   324  }
   325  
   326  func TestNodeString(t *testing.T) {
   327  	for i, test := range parseNodeTests {
   328  		rawUrl := test.rawurl
   329  		if strings.HasPrefix(test.rawurl, "enode://") {
   330  			rawUrl = convertNodeScheme(test.rawurl)
   331  		}
   332  		if test.wantError == "" && strings.HasPrefix(rawUrl, "kni://") {
   333  			str := test.wantResult.String()
   334  			if str != rawUrl && str != test.wantNodeString && test.wantNodeString != "" {
   335  				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, rawUrl)
   336  			}
   337  		}
   338  	}
   339  }
   340  
   341  func TestHexID(t *testing.T) {
   342  	ref := NodeID{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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}
   343  	id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   344  	id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   345  
   346  	if id1 != ref {
   347  		t.Errorf("wrong id1\ngot  %v\nwant %v", id1[:], ref[:])
   348  	}
   349  	if id2 != ref {
   350  		t.Errorf("wrong id2\ngot  %v\nwant %v", id2[:], ref[:])
   351  	}
   352  }
   353  
   354  func TestNodeID_textEncoding(t *testing.T) {
   355  	ref := NodeID{
   356  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
   357  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
   358  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
   359  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
   360  		0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50,
   361  		0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60,
   362  		0x61, 0x62, 0x63, 0x64,
   363  	}
   364  	hex := "01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364"
   365  
   366  	text, err := ref.MarshalText()
   367  	if err != nil {
   368  		t.Fatal(err)
   369  	}
   370  	if !bytes.Equal(text, []byte(hex)) {
   371  		t.Fatalf("text encoding did not match\nexpected: %s\ngot:      %s", hex, text)
   372  	}
   373  
   374  	id := new(NodeID)
   375  	if err := id.UnmarshalText(text); err != nil {
   376  		t.Fatal(err)
   377  	}
   378  	if *id != ref {
   379  		t.Fatalf("text decoding did not match\nexpected: %s\ngot:      %s", ref, id)
   380  	}
   381  }
   382  
   383  func TestNodeID_recover(t *testing.T) {
   384  	prv := newkey()
   385  	hash := make([]byte, 32)
   386  	sig, err := crypto.Sign(hash, prv)
   387  	if err != nil {
   388  		t.Fatalf("signing error: %v", err)
   389  	}
   390  
   391  	pub := PubkeyID(&prv.PublicKey)
   392  	recpub, err := recoverNodeID(hash, sig)
   393  	if err != nil {
   394  		t.Fatalf("recovery error: %v", err)
   395  	}
   396  	if pub != recpub {
   397  		t.Errorf("recovered wrong pubkey:\ngot:  %v\nwant: %v", recpub, pub)
   398  	}
   399  
   400  	ecdsa, err := pub.Pubkey()
   401  	if err != nil {
   402  		t.Errorf("Pubkey error: %v", err)
   403  	}
   404  	if !reflect.DeepEqual(ecdsa, &prv.PublicKey) {
   405  		t.Errorf("Pubkey mismatch:\n  got:  %#v\n  want: %#v", ecdsa, &prv.PublicKey)
   406  	}
   407  }
   408  
   409  func TestNodeID_pubkeyBad(t *testing.T) {
   410  	ecdsa, err := NodeID{}.Pubkey()
   411  	if err == nil {
   412  		t.Error("expected error for zero ID")
   413  	}
   414  	if ecdsa != nil {
   415  		t.Error("expected nil result")
   416  	}
   417  }
   418  
   419  func TestNodeID_distcmp(t *testing.T) {
   420  	distcmpBig := func(target, a, b common.Hash) int {
   421  		tbig := new(big.Int).SetBytes(target[:])
   422  		abig := new(big.Int).SetBytes(a[:])
   423  		bbig := new(big.Int).SetBytes(b[:])
   424  		return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig))
   425  	}
   426  	if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg()); err != nil {
   427  		t.Error(err)
   428  	}
   429  }
   430  
   431  // the random tests is likely to miss the case where they're equal.
   432  func TestNodeID_distcmpEqual(t *testing.T) {
   433  	base := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   434  	x := common.Hash{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
   435  	if distcmp(base, x, x) != 0 {
   436  		t.Errorf("distcmp(base, x, x) != 0")
   437  	}
   438  }
   439  
   440  func TestNodeID_logdist(t *testing.T) {
   441  	logdistBig := func(a, b common.Hash) int {
   442  		abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:])
   443  		return new(big.Int).Xor(abig, bbig).BitLen()
   444  	}
   445  	if err := quick.CheckEqual(logdist, logdistBig, quickcfg()); err != nil {
   446  		t.Error(err)
   447  	}
   448  }
   449  
   450  // the random tests is likely to miss the case where they're equal.
   451  func TestNodeID_logdistEqual(t *testing.T) {
   452  	x := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   453  	if logdist(x, x) != 0 {
   454  		t.Errorf("logdist(x, x) != 0")
   455  	}
   456  }
   457  
   458  func TestNodeID_hashAtDistance(t *testing.T) {
   459  	// we don't use quick.Check here because its output isn't
   460  	// very helpful when the test fails.
   461  	cfg := quickcfg()
   462  	for i := 0; i < cfg.MaxCount; i++ {
   463  		a := gen(common.Hash{}, cfg.Rand).(common.Hash)
   464  		dist := cfg.Rand.Intn(len(common.Hash{}) * 8)
   465  		result := hashAtDistance(a, dist)
   466  		actualdist := logdist(result, a)
   467  
   468  		if dist != actualdist {
   469  			t.Log("a:     ", a)
   470  			t.Log("result:", result)
   471  			t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist)
   472  		}
   473  	}
   474  }
   475  
   476  func quickcfg() *quick.Config {
   477  	return &quick.Config{
   478  		MaxCount: 5000,
   479  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   480  	}
   481  }
   482  
   483  // TODO: The Generate method can be dropped when we require Go >= 1.5
   484  // because testing/quick learned to generate arrays in 1.5.
   485  
   486  func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value {
   487  	var id NodeID
   488  	m := rand.Intn(len(id))
   489  	for i := len(id) - 1; i > m; i-- {
   490  		id[i] = byte(rand.Uint32())
   491  	}
   492  	return reflect.ValueOf(id)
   493  }