github.com/bcskill/bcschain/v3@v3.4.9-beta2/p2p/discover/node_test.go (about)

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