github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/p2p/discover/node_test.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 12:09:43</date>
    10  //</624342655978967040>
    11  
    12  
    13  package discover
    14  
    15  import (
    16  	"bytes"
    17  	"fmt"
    18  	"math/big"
    19  	"math/rand"
    20  	"net"
    21  	"reflect"
    22  	"strings"
    23  	"testing"
    24  	"testing/quick"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/crypto"
    29  )
    30  
    31  func ExampleNewNode() {
    32  	id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439")
    33  
    34  //完整节点包含UDP和TCP终结点:
    35  	n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303)
    36  	fmt.Println("n1:", n1)
    37  	fmt.Println("n1.Incomplete() ->", n1.Incomplete())
    38  
    39  //通过传递零值可以创建不完整的节点
    40  //用于除ID以外的所有参数。
    41  	n2 := NewNode(id, nil, 0, 0)
    42  	fmt.Println("n2:", n2)
    43  	fmt.Println("n2.Incomplete() ->", n2.Incomplete())
    44  
    45  //输出:
    46  //n1:enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd512be2435232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:30303?磁盘端口=52150
    47  //n1.incomplete()->错误
    48  //n2:enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd512be2435232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439
    49  //n2.incomplete()->真
    50  }
    51  
    52  var parseNodeTests = []struct {
    53  	rawurl     string
    54  	wantError  string
    55  	wantResult *Node
    56  }{
    57  	{
    58  rawurl:    "http://“福巴”
    59  		wantError: `invalid URL scheme, want "enode"`,
    60  	},
    61  	{
    62  rawurl:    "enode://01010101@123.124.125.126:3“,
    63  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
    64  	},
    65  //使用IP地址完成节点。
    66  	{
    67  rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3“,
    68  		wantError: `invalid IP address`,
    69  	},
    70  	{
    71  rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo“,
    72  		wantError: `invalid port`,
    73  	},
    74  	{
    75  rawurl:    "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?迪斯科=
    76  		wantError: `invalid discport in query`,
    77  	},
    78  	{
    79  rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150“,
    80  		wantResult: NewNode(
    81  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    82  			net.IP{0x7f, 0x0, 0x0, 0x1},
    83  			52150,
    84  			52150,
    85  		),
    86  	},
    87  	{
    88  rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150“,
    89  		wantResult: NewNode(
    90  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
    91  			net.ParseIP("::"),
    92  			52150,
    93  			52150,
    94  		),
    95  	},
    96  	{
    97  rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150“,
    98  		wantResult: NewNode(
    99  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   100  			net.ParseIP("2001:db8:3c4d:15::abcd:ef12"),
   101  			52150,
   102  			52150,
   103  		),
   104  	},
   105  	{
   106  rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334“,
   107  		wantResult: NewNode(
   108  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   109  			net.IP{0x7f, 0x0, 0x0, 0x1},
   110  			22334,
   111  			52150,
   112  		),
   113  	},
   114  //没有地址的不完整节点。
   115  	{
   116  		rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439",
   117  		wantResult: NewNode(
   118  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   119  			nil, 0, 0,
   120  		),
   121  	},
   122  	{
   123  rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6c6c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439“,
   124  		wantResult: NewNode(
   125  			MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"),
   126  			nil, 0, 0,
   127  		),
   128  	},
   129  //无效网址
   130  	{
   131  		rawurl:    "01010101",
   132  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   133  	},
   134  	{
   135  rawurl:    "enode://01010101“,
   136  		wantError: `invalid node ID (wrong length, want 128 hex chars)`,
   137  	},
   138  	{
   139  //此测试检查是否处理了URL.Parse中的错误。
   140  rawurl:    "://“,”
   141  wantError: `parse ://foo:缺少协议方案`,
   142  	},
   143  }
   144  
   145  func TestParseNode(t *testing.T) {
   146  	for _, test := range parseNodeTests {
   147  		n, err := ParseNode(test.rawurl)
   148  		if test.wantError != "" {
   149  			if err == nil {
   150  				t.Errorf("test %q:\n  got nil error, expected %#q", test.rawurl, test.wantError)
   151  				continue
   152  			} else if err.Error() != test.wantError {
   153  				t.Errorf("test %q:\n  got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError)
   154  				continue
   155  			}
   156  		} else {
   157  			if err != nil {
   158  				t.Errorf("test %q:\n  unexpected error: %v", test.rawurl, err)
   159  				continue
   160  			}
   161  			if !reflect.DeepEqual(n, test.wantResult) {
   162  				t.Errorf("test %q:\n  result mismatch:\ngot:  %#v, want: %#v", test.rawurl, n, test.wantResult)
   163  			}
   164  		}
   165  	}
   166  }
   167  
   168  func TestNodeString(t *testing.T) {
   169  	for i, test := range parseNodeTests {
   170  if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://“”{
   171  			str := test.wantResult.String()
   172  			if str != test.rawurl {
   173  				t.Errorf("test %d: Node.String() mismatch:\ngot:  %s\nwant: %s", i, str, test.rawurl)
   174  			}
   175  		}
   176  	}
   177  }
   178  
   179  func TestHexID(t *testing.T) {
   180  	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}
   181  	id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   182  	id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc")
   183  
   184  	if id1 != ref {
   185  		t.Errorf("wrong id1\ngot  %v\nwant %v", id1[:], ref[:])
   186  	}
   187  	if id2 != ref {
   188  		t.Errorf("wrong id2\ngot  %v\nwant %v", id2[:], ref[:])
   189  	}
   190  }
   191  
   192  func TestNodeID_textEncoding(t *testing.T) {
   193  	ref := NodeID{
   194  		0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10,
   195  		0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x20,
   196  		0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x30,
   197  		0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x40,
   198  		0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50,
   199  		0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x60,
   200  		0x61, 0x62, 0x63, 0x64,
   201  	}
   202  	hex := "01020304050607080910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364"
   203  
   204  	text, err := ref.MarshalText()
   205  	if err != nil {
   206  		t.Fatal(err)
   207  	}
   208  	if !bytes.Equal(text, []byte(hex)) {
   209  		t.Fatalf("text encoding did not match\nexpected: %s\ngot:      %s", hex, text)
   210  	}
   211  
   212  	id := new(NodeID)
   213  	if err := id.UnmarshalText(text); err != nil {
   214  		t.Fatal(err)
   215  	}
   216  	if *id != ref {
   217  		t.Fatalf("text decoding did not match\nexpected: %s\ngot:      %s", ref, id)
   218  	}
   219  }
   220  
   221  func TestNodeID_recover(t *testing.T) {
   222  	prv := newkey()
   223  	hash := make([]byte, 32)
   224  	sig, err := crypto.Sign(hash, prv)
   225  	if err != nil {
   226  		t.Fatalf("signing error: %v", err)
   227  	}
   228  
   229  	pub := PubkeyID(&prv.PublicKey)
   230  	recpub, err := recoverNodeID(hash, sig)
   231  	if err != nil {
   232  		t.Fatalf("recovery error: %v", err)
   233  	}
   234  	if pub != recpub {
   235  		t.Errorf("recovered wrong pubkey:\ngot:  %v\nwant: %v", recpub, pub)
   236  	}
   237  
   238  	ecdsa, err := pub.Pubkey()
   239  	if err != nil {
   240  		t.Errorf("Pubkey error: %v", err)
   241  	}
   242  	if !reflect.DeepEqual(ecdsa, &prv.PublicKey) {
   243  		t.Errorf("Pubkey mismatch:\n  got:  %#v\n  want: %#v", ecdsa, &prv.PublicKey)
   244  	}
   245  }
   246  
   247  func TestNodeID_pubkeyBad(t *testing.T) {
   248  	ecdsa, err := NodeID{}.Pubkey()
   249  	if err == nil {
   250  		t.Error("expected error for zero ID")
   251  	}
   252  	if ecdsa != nil {
   253  		t.Error("expected nil result")
   254  	}
   255  }
   256  
   257  func TestNodeID_distcmp(t *testing.T) {
   258  	distcmpBig := func(target, a, b common.Hash) int {
   259  		tbig := new(big.Int).SetBytes(target[:])
   260  		abig := new(big.Int).SetBytes(a[:])
   261  		bbig := new(big.Int).SetBytes(b[:])
   262  		return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig))
   263  	}
   264  	if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg()); err != nil {
   265  		t.Error(err)
   266  	}
   267  }
   268  
   269  //随机测试很可能会错过它们相等的情况。
   270  func TestNodeID_distcmpEqual(t *testing.T) {
   271  	base := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   272  	x := common.Hash{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}
   273  	if distcmp(base, x, x) != 0 {
   274  		t.Errorf("distcmp(base, x, x) != 0")
   275  	}
   276  }
   277  
   278  func TestNodeID_logdist(t *testing.T) {
   279  	logdistBig := func(a, b common.Hash) int {
   280  		abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:])
   281  		return new(big.Int).Xor(abig, bbig).BitLen()
   282  	}
   283  	if err := quick.CheckEqual(logdist, logdistBig, quickcfg()); err != nil {
   284  		t.Error(err)
   285  	}
   286  }
   287  
   288  //随机测试很可能会错过它们相等的情况。
   289  func TestNodeID_logdistEqual(t *testing.T) {
   290  	x := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
   291  	if logdist(x, x) != 0 {
   292  		t.Errorf("logdist(x, x) != 0")
   293  	}
   294  }
   295  
   296  func TestNodeID_hashAtDistance(t *testing.T) {
   297  //我们不使用quick。请检查这里,因为它的输出不是
   298  //当测试失败时非常有用。
   299  	cfg := quickcfg()
   300  	for i := 0; i < cfg.MaxCount; i++ {
   301  		a := gen(common.Hash{}, cfg.Rand).(common.Hash)
   302  		dist := cfg.Rand.Intn(len(common.Hash{}) * 8)
   303  		result := hashAtDistance(a, dist)
   304  		actualdist := logdist(result, a)
   305  
   306  		if dist != actualdist {
   307  			t.Log("a:     ", a)
   308  			t.Log("result:", result)
   309  			t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist)
   310  		}
   311  	}
   312  }
   313  
   314  func quickcfg() *quick.Config {
   315  	return &quick.Config{
   316  		MaxCount: 5000,
   317  		Rand:     rand.New(rand.NewSource(time.Now().Unix())),
   318  	}
   319  }
   320  
   321  //TODO:当我们需要go大于等于1.5时,可以删除generate方法。
   322  //因为测试/快速学习在1.5中生成数组。
   323  
   324  func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value {
   325  	var id NodeID
   326  	m := rand.Intn(len(id))
   327  	for i := len(id) - 1; i > m; i-- {
   328  		id[i] = byte(rand.Uint32())
   329  	}
   330  	return reflect.ValueOf(id)
   331  }
   332