github.com/jonasnick/go-ethereum@v0.7.12-0.20150216215225-22176f05d387/p2p/discover/node_test.go (about) 1 package discover 2 3 import ( 4 "math/big" 5 "math/rand" 6 "net" 7 "reflect" 8 "testing" 9 "testing/quick" 10 "time" 11 12 "github.com/jonasnick/go-ethereum/crypto" 13 ) 14 15 var ( 16 quickrand = rand.New(rand.NewSource(time.Now().Unix())) 17 quickcfg = &quick.Config{MaxCount: 5000, Rand: quickrand} 18 ) 19 20 var parseNodeTests = []struct { 21 rawurl string 22 wantError string 23 wantResult *Node 24 }{ 25 { 26 rawurl: "http://foobar", 27 wantError: `invalid URL scheme, want "enode"`, 28 }, 29 { 30 rawurl: "enode://foobar", 31 wantError: `does not contain node ID`, 32 }, 33 { 34 rawurl: "enode://01010101@123.124.125.126:3", 35 wantError: `invalid node ID (wrong length, need 64 hex bytes)`, 36 }, 37 { 38 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3", 39 wantError: `invalid IP address`, 40 }, 41 { 42 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo", 43 wantError: `invalid port`, 44 }, 45 { 46 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo", 47 wantError: `invalid discport in query`, 48 }, 49 { 50 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150", 51 wantResult: &Node{ 52 ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 53 IP: net.ParseIP("127.0.0.1"), 54 DiscPort: 52150, 55 TCPPort: 52150, 56 }, 57 }, 58 { 59 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", 60 wantResult: &Node{ 61 ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 62 IP: net.ParseIP("::"), 63 DiscPort: 52150, 64 TCPPort: 52150, 65 }, 66 }, 67 { 68 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=223344", 69 wantResult: &Node{ 70 ID: MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 71 IP: net.ParseIP("127.0.0.1"), 72 DiscPort: 223344, 73 TCPPort: 52150, 74 }, 75 }, 76 } 77 78 func TestParseNode(t *testing.T) { 79 for i, test := range parseNodeTests { 80 n, err := ParseNode(test.rawurl) 81 if err == nil && test.wantError != "" { 82 t.Errorf("test %d: got nil error, expected %#q", i, test.wantError) 83 continue 84 } 85 if err != nil && err.Error() != test.wantError { 86 t.Errorf("test %d: got error %#q, expected %#q", i, err.Error(), test.wantError) 87 continue 88 } 89 if !reflect.DeepEqual(n, test.wantResult) { 90 t.Errorf("test %d: result mismatch:\ngot: %#v, want: %#v", i, n, test.wantResult) 91 } 92 } 93 } 94 95 func TestNodeString(t *testing.T) { 96 for i, test := range parseNodeTests { 97 if test.wantError != "" { 98 continue 99 } 100 str := test.wantResult.String() 101 if str != test.rawurl { 102 t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl) 103 } 104 } 105 } 106 107 func TestHexID(t *testing.T) { 108 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} 109 id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") 110 id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") 111 112 if id1 != ref { 113 t.Errorf("wrong id1\ngot %v\nwant %v", id1[:], ref[:]) 114 } 115 if id2 != ref { 116 t.Errorf("wrong id2\ngot %v\nwant %v", id2[:], ref[:]) 117 } 118 } 119 120 func TestNodeID_recover(t *testing.T) { 121 prv := newkey() 122 hash := make([]byte, 32) 123 sig, err := crypto.Sign(hash, prv) 124 if err != nil { 125 t.Fatalf("signing error: %v", err) 126 } 127 128 pub := PubkeyID(&prv.PublicKey) 129 recpub, err := recoverNodeID(hash, sig) 130 if err != nil { 131 t.Fatalf("recovery error: %v", err) 132 } 133 if pub != recpub { 134 t.Errorf("recovered wrong pubkey:\ngot: %v\nwant: %v", recpub, pub) 135 } 136 } 137 138 func TestNodeID_distcmp(t *testing.T) { 139 distcmpBig := func(target, a, b NodeID) int { 140 tbig := new(big.Int).SetBytes(target[:]) 141 abig := new(big.Int).SetBytes(a[:]) 142 bbig := new(big.Int).SetBytes(b[:]) 143 return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig)) 144 } 145 if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg); err != nil { 146 t.Error(err) 147 } 148 } 149 150 // the random tests is likely to miss the case where they're equal. 151 func TestNodeID_distcmpEqual(t *testing.T) { 152 base := NodeID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 153 x := NodeID{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} 154 if distcmp(base, x, x) != 0 { 155 t.Errorf("distcmp(base, x, x) != 0") 156 } 157 } 158 159 func TestNodeID_logdist(t *testing.T) { 160 logdistBig := func(a, b NodeID) int { 161 abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:]) 162 return new(big.Int).Xor(abig, bbig).BitLen() 163 } 164 if err := quick.CheckEqual(logdist, logdistBig, quickcfg); err != nil { 165 t.Error(err) 166 } 167 } 168 169 // the random tests is likely to miss the case where they're equal. 170 func TestNodeID_logdistEqual(t *testing.T) { 171 x := NodeID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 172 if logdist(x, x) != 0 { 173 t.Errorf("logdist(x, x) != 0") 174 } 175 } 176 177 func TestNodeID_randomID(t *testing.T) { 178 // we don't use quick.Check here because its output isn't 179 // very helpful when the test fails. 180 for i := 0; i < quickcfg.MaxCount; i++ { 181 a := gen(NodeID{}, quickrand).(NodeID) 182 dist := quickrand.Intn(len(NodeID{}) * 8) 183 result := randomID(a, dist) 184 actualdist := logdist(result, a) 185 186 if dist != actualdist { 187 t.Log("a: ", a) 188 t.Log("result:", result) 189 t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist) 190 } 191 } 192 } 193 194 func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value { 195 var id NodeID 196 m := rand.Intn(len(id)) 197 for i := len(id) - 1; i > m; i-- { 198 id[i] = byte(rand.Uint32()) 199 } 200 return reflect.ValueOf(id) 201 }