github.com/arieschain/arieschain@v0.0.0-20191023063405-37c074544356/p2p/discover/node_test.go (about)

     1  package discover
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"math/big"
     7  	"math/rand"
     8  	"net"
     9  	"reflect"
    10  	"strings"
    11  	"testing"
    12  	"testing/quick"
    13  	"time"
    14  
    15  	"github.com/quickchainproject/quickchain/common"
    16  	"github.com/quickchainproject/quickchain/crypto"
    17  )
    18  
    19  func ExampleNewNode() {
    20  	id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439")
    21  
    22  	// Complete nodes contain UDP and TCP endpoints:
    23  	n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 36663)
    24  	fmt.Println("n1:", n1)
    25  	fmt.Println("n1.Incomplete() ->", n1.Incomplete())
    26  
    27  	// An incomplete node can be created by passing zero values
    28  	// for all parameters except id.
    29  	n2 := NewNode(id, nil, 0, 0)
    30  	fmt.Println("n2:", n2)
    31  	fmt.Println("n2.Incomplete() ->", n2.Incomplete())
    32  
    33  	// Output:
    34  	// n1: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:36663?discport=52150
    35  	// n1.Incomplete() -> false
    36  	// n2: enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439
    37  	// n2.Incomplete() -> true
    38  }
    39  
    40  var parseNodeTests = []struct {
    41  	rawurl     string
    42  	wantError  string
    43  	wantResult *Node
    44  }{
    45  	{
    46  		rawurl:    "http://foobar",
    47  		wantError: `invalid URL scheme, want "enode"`,
    48  	},
    49  	{
    50  		rawurl:    "enode://01010101@123.124.125.126:3",
    51  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    52  	},
    53  	// Complete nodes with IP address.
    54  	{
    55  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3",
    56  		wantError: `invalid IP address`,
    57  	},
    58  	{
    59  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo",
    60  		wantError: `invalid port`,
    61  	},
    62  	{
    63  		rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo",
    64  		wantError: `invalid discport in query`,
    65  	},
    66  	{
    67  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150",
    68  		wantResult: NewNode(
    69  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    70  			net.IP{0x7f, 0x0, 0x0, 0x1},
    71  			52150,
    72  			52150,
    73  		),
    74  	},
    75  	{
    76  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150",
    77  		wantResult: NewNode(
    78  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    79  			net.ParseIP("::"),
    80  			52150,
    81  			52150,
    82  		),
    83  	},
    84  	{
    85  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150",
    86  		wantResult: NewNode(
    87  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    88  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
    89  			52150,
    90  			52150,
    91  		),
    92  	},
    93  	{
    94  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334",
    95  		wantResult: NewNode(
    96  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    97  			net.IP{0x7f, 0x0, 0x0, 0x1},
    98  			22334,
    99  			52150,
   100  		),
   101  	},
   102  	// Incomplete nodes with no address.
   103  	{
   104  		rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   105  		wantResult: NewNode(
   106  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   107  			nil, 0, 0,
   108  		),
   109  	},
   110  	{
   111  		rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   112  		wantResult: NewNode(
   113  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   114  			nil, 0, 0,
   115  		),
   116  	},
   117  	// Invalid URLs
   118  	{
   119  		rawurl:    "01010101",
   120  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   121  	},
   122  	{
   123  		rawurl:    "enode://01010101",
   124  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   125  	},
   126  	{
   127  		// This test checks that errors from url.Parse are handled.
   128  		rawurl:    "://foo",
   129  		wantError: `parse ://foo: missing protocol scheme`,
   130  	},
   131  }
   132  
   133  func TestParseNode(t *testing.T) {
   134  	for _, test := range parseNodeTests {
   135  		n, err := ParseNode(test.rawurl)
   136  		if test.wantError != "" {
   137  			if err == nil {
   138  				t.Errorf("test %q:\n  got nil error, expected %#q", test.rawurl, test.wantError)
   139  				continue
   140  			} else if err.Error() != test.wantError {
   141  				t.Errorf("test %q:\n  got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
   142  				continue
   143  			}
   144  		} else {
   145  			if err != nil {
   146  				t.Errorf("test %q:\n  unexpected error: %v", test.rawurl, err)
   147  				continue
   148  			}
   149  			if !reflect.DeepEqual(n, test.wantResult) {
   150  				t.Errorf("test %q:\n  result mismatch:\ngot:  %#v, want: %#v", test.rawurl, n, test.wantResult)
   151  			}
   152  		}
   153  	}
   154  }
   155  
   156  func TestNodeString(t *testing.T) {
   157  	for i, test := range parseNodeTests {
   158  		if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") {
   159  			str := test.wantResult.String()
   160  			if str != test.rawurl {
   161  				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, test.rawurl)
   162  			}
   163  		}
   164  	}
   165  }
   166  
   167  func TestHexID(t *testing.T) {
   168  	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}
   169  	id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   170  	id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   171  
   172  	if id1 != ref {
   173  		t.Errorf("wrong id1\ngot  %v\nwant %v", id1[:], ref[:])
   174  	}
   175  	if id2 != ref {
   176  		t.Errorf("wrong id2\ngot  %v\nwant %v", id2[:], ref[:])
   177  	}
   178  }
   179  
   180  func TestNodeID_textEncoding(t *testing.T) {
   181  	ref := NodeID{
   182  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
   183  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
   184  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
   185  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
   186  		0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50,
   187  		0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60,
   188  		0x61, 0x62, 0x63, 0x64,
   189  	}
   190  	hex := "01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364"
   191  
   192  	text, err := ref.MarshalText()
   193  	if err != nil {
   194  		t.Fatal(err)
   195  	}
   196  	if !bytes.Equal(text, []byte(hex)) {
   197  		t.Fatalf("text encoding did not match\nexpected: %s\ngot:      %s", hex, text)
   198  	}
   199  
   200  	id := new(NodeID)
   201  	if err := id.UnmarshalText(text); err != nil {
   202  		t.Fatal(err)
   203  	}
   204  	if *id != ref {
   205  		t.Fatalf("text decoding did not match\nexpected: %s\ngot:      %s", ref, id)
   206  	}
   207  }
   208  
   209  func TestNodeID_recover(t *testing.T) {
   210  	prv := newkey()
   211  	hash := make([]byte, 32)
   212  	sig, err := crypto.Sign(hash, prv)
   213  	if err != nil {
   214  		t.Fatalf("signing error: %v", err)
   215  	}
   216  
   217  	pub := PubkeyID(&prv.PublicKey)
   218  	recpub, err := recoverNodeID(hash, sig)
   219  	if err != nil {
   220  		t.Fatalf("recovery error: %v", err)
   221  	}
   222  	if pub != recpub {
   223  		t.Errorf("recovered wrong pubkey:\ngot:  %v\nwant: %v", recpub, pub)
   224  	}
   225  
   226  	ecdsa, err := pub.Pubkey()
   227  	if err != nil {
   228  		t.Errorf("Pubkey error: %v", err)
   229  	}
   230  	if !reflect.DeepEqual(ecdsa, &prv.PublicKey) {
   231  		t.Errorf("Pubkey mismatch:\n  got:  %#v\n  want: %#v", ecdsa, &prv.PublicKey)
   232  	}
   233  }
   234  
   235  func TestNodeID_pubkeyBad(t *testing.T) {
   236  	ecdsa, err := NodeID{}.Pubkey()
   237  	if err == nil {
   238  		t.Error("expected error for zero ID")
   239  	}
   240  	if ecdsa != nil {
   241  		t.Error("expected nil result")
   242  	}
   243  }
   244  
   245  func TestNodeID_distcmp(t *testing.T) {
   246  	distcmpBig := func(target, a, b common.Hash) int {
   247  		tbig := new(big.Int).SetBytes(target[:])
   248  		abig := new(big.Int).SetBytes(a[:])
   249  		bbig := new(big.Int).SetBytes(b[:])
   250  		return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig))
   251  	}
   252  	if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg()); err != nil {
   253  		t.Error(err)
   254  	}
   255  }
   256  
   257  // the random tests is likely to miss the case where they're equal.
   258  func TestNodeID_distcmpEqual(t *testing.T) {
   259  	base := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   260  	x := common.Hash{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
   261  	if distcmp(base, x, x) != 0 {
   262  		t.Errorf("distcmp(base, x, x) != 0")
   263  	}
   264  }
   265  
   266  func TestNodeID_logdist(t *testing.T) {
   267  	logdistBig := func(a, b common.Hash) int {
   268  		abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:])
   269  		return new(big.Int).Xor(abig, bbig).BitLen()
   270  	}
   271  	if err := quick.CheckEqual(logdist, logdistBig, quickcfg()); err != nil {
   272  		t.Error(err)
   273  	}
   274  }
   275  
   276  // the random tests is likely to miss the case where they're equal.
   277  func TestNodeID_logdistEqual(t *testing.T) {
   278  	x := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   279  	if logdist(x, x) != 0 {
   280  		t.Errorf("logdist(x, x) != 0")
   281  	}
   282  }
   283  
   284  func TestNodeID_hashAtDistance(t *testing.T) {
   285  	// we don't use quick.Check here because its output isn't
   286  	// very helpful when the test fails.
   287  	cfg := quickcfg()
   288  	for i := 0; i < cfg.MaxCount; i++ {
   289  		a := gen(common.Hash{}, cfg.Rand).(common.Hash)
   290  		dist := cfg.Rand.Intn(len(common.Hash{}) * 8)
   291  		result := hashAtDistance(a, dist)
   292  		actualdist := logdist(result, a)
   293  
   294  		if dist != actualdist {
   295  			t.Log("a:     ", a)
   296  			t.Log("result:", result)
   297  			t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist)
   298  		}
   299  	}
   300  }
   301  
   302  func quickcfg() *quick.Config {
   303  	return &quick.Config{
   304  		MaxCount: 5000,
   305  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   306  	}
   307  }
   308  
   309  // TODO: The Generate method can be dropped when we require Go >= 1.5
   310  // because testing/quick learned to generate arrays in 1.5.
   311  
   312  func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value {
   313  	var id NodeID
   314  	m := rand.Intn(len(id))
   315  	for i := len(id) - 1; i > m; i-- {
   316  		id[i] = byte(rand.Uint32())
   317  	}
   318  	return reflect.ValueOf(id)
   319  }