github.com/neatio-net/neatio@v1.7.3-0.20231114194659-f4d7a2226baa/network/p2p/discv5/node_test.go (about) 1 package discv5 2 3 import ( 4 "fmt" 5 "math/big" 6 "math/rand" 7 "net" 8 "reflect" 9 "strings" 10 "testing" 11 "testing/quick" 12 "time" 13 14 "github.com/neatio-net/neatio/utilities/common" 15 "github.com/neatio-net/neatio/utilities/crypto" 16 ) 17 18 func ExampleNewNode() { 19 id := MustHexID("1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439") 20 21 n1 := NewNode(id, net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 52150, 30303) 22 fmt.Println("n1:", n1) 23 fmt.Println("n1.Incomplete() ->", n1.Incomplete()) 24 25 n2 := NewNode(id, nil, 0, 0) 26 fmt.Println("n2:", n2) 27 fmt.Println("n2.Incomplete() ->", n2.Incomplete()) 28 29 } 30 31 var parseNodeTests = []struct { 32 rawurl string 33 wantError string 34 wantResult *Node 35 }{ 36 { 37 rawurl: "http://foobar", 38 wantError: `invalid URL scheme, want "enode"`, 39 }, 40 { 41 rawurl: "enode://01010101@123.124.125.126:3", 42 wantError: `invalid node ID (wrong length, want 128 hex chars)`, 43 }, 44 { 45 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@hostname:3", 46 wantError: `invalid IP address`, 47 }, 48 { 49 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:foo", 50 wantError: `invalid port`, 51 }, 52 { 53 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:3?discport=foo", 54 wantError: `invalid discport in query`, 55 }, 56 { 57 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150", 58 wantResult: NewNode( 59 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 60 net.IP{0x7f, 0x0, 0x0, 0x1}, 61 52150, 62 52150, 63 ), 64 }, 65 { 66 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[::]:52150", 67 wantResult: NewNode( 68 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 69 net.ParseIP("::"), 70 52150, 71 52150, 72 ), 73 }, 74 { 75 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@[2001:db8:3c4d:15::abcd:ef12]:52150", 76 wantResult: NewNode( 77 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 78 net.ParseIP("2001:db8:3c4d:15::abcd:ef12"), 79 52150, 80 52150, 81 ), 82 }, 83 { 84 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439@127.0.0.1:52150?discport=22334", 85 wantResult: NewNode( 86 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 87 net.IP{0x7f, 0x0, 0x0, 0x1}, 88 22334, 89 52150, 90 ), 91 }, 92 { 93 rawurl: "1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", 94 wantResult: NewNode( 95 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 96 nil, 0, 0, 97 ), 98 }, 99 { 100 rawurl: "enode://1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439", 101 wantResult: NewNode( 102 MustHexID("0x1dd9d65c4552b5eb43d5ad55a2ee3f56c6cbc1c64a5c8d659f51fcd51bace24351232b8d7821617d2b29b54b81cdefb9b3e9c37d7fd5f63270bcc9e1a6f6a439"), 103 nil, 0, 0, 104 ), 105 }, 106 { 107 rawurl: "01010101", 108 wantError: `invalid node ID (wrong length, want 128 hex chars)`, 109 }, 110 { 111 rawurl: "enode://01010101", 112 wantError: `invalid node ID (wrong length, want 128 hex chars)`, 113 }, 114 { 115 rawurl: "://foo", 116 wantError: `parse ://foo: missing protocol scheme`, 117 }, 118 } 119 120 func TestParseNode(t *testing.T) { 121 for _, test := range parseNodeTests { 122 n, err := ParseNode(test.rawurl) 123 if test.wantError != "" { 124 if err == nil { 125 t.Errorf("test %q:\n got nil error, expected %#q", test.rawurl, test.wantError) 126 continue 127 } else if err.Error() != test.wantError { 128 t.Errorf("test %q:\n got error %#q, expected %#q", test.rawurl, err.Error(), test.wantError) 129 continue 130 } 131 } else { 132 if err != nil { 133 t.Errorf("test %q:\n unexpected error: %v", test.rawurl, err) 134 continue 135 } 136 if !reflect.DeepEqual(n, test.wantResult) { 137 t.Errorf("test %q:\n result mismatch:\ngot: %#v, want: %#v", test.rawurl, n, test.wantResult) 138 } 139 } 140 } 141 } 142 143 func TestNodeString(t *testing.T) { 144 for i, test := range parseNodeTests { 145 if test.wantError == "" && strings.HasPrefix(test.rawurl, "enode://") { 146 str := test.wantResult.String() 147 if str != test.rawurl { 148 t.Errorf("test %d: Node.String() mismatch:\ngot: %s\nwant: %s", i, str, test.rawurl) 149 } 150 } 151 } 152 } 153 154 func TestHexID(t *testing.T) { 155 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} 156 id1 := MustHexID("0x000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") 157 id2 := MustHexID("000000000000000000000000000000000000000000000000000000000000000000000000000000806ad9b61fa5ae014307ebdc964253adcd9f2c0a392aa11abc") 158 159 if id1 != ref { 160 t.Errorf("wrong id1\ngot %v\nwant %v", id1[:], ref[:]) 161 } 162 if id2 != ref { 163 t.Errorf("wrong id2\ngot %v\nwant %v", id2[:], ref[:]) 164 } 165 } 166 167 func TestNodeID_recover(t *testing.T) { 168 prv := newkey() 169 hash := make([]byte, 32) 170 sig, err := crypto.Sign(hash, prv) 171 if err != nil { 172 t.Fatalf("signing error: %v", err) 173 } 174 175 pub := PubkeyID(&prv.PublicKey) 176 recpub, err := recoverNodeID(hash, sig) 177 if err != nil { 178 t.Fatalf("recovery error: %v", err) 179 } 180 if pub != recpub { 181 t.Errorf("recovered wrong pubkey:\ngot: %v\nwant: %v", recpub, pub) 182 } 183 184 ecdsa, err := pub.Pubkey() 185 if err != nil { 186 t.Errorf("Pubkey error: %v", err) 187 } 188 if !reflect.DeepEqual(ecdsa, &prv.PublicKey) { 189 t.Errorf("Pubkey mismatch:\n got: %#v\n want: %#v", ecdsa, &prv.PublicKey) 190 } 191 } 192 193 func TestNodeID_pubkeyBad(t *testing.T) { 194 ecdsa, err := NodeID{}.Pubkey() 195 if err == nil { 196 t.Error("expected error for zero ID") 197 } 198 if ecdsa != nil { 199 t.Error("expected nil result") 200 } 201 } 202 203 func TestNodeID_distcmp(t *testing.T) { 204 distcmpBig := func(target, a, b common.Hash) int { 205 tbig := new(big.Int).SetBytes(target[:]) 206 abig := new(big.Int).SetBytes(a[:]) 207 bbig := new(big.Int).SetBytes(b[:]) 208 return new(big.Int).Xor(tbig, abig).Cmp(new(big.Int).Xor(tbig, bbig)) 209 } 210 if err := quick.CheckEqual(distcmp, distcmpBig, quickcfg()); err != nil { 211 t.Error(err) 212 } 213 } 214 215 func TestNodeID_distcmpEqual(t *testing.T) { 216 base := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 217 x := common.Hash{15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0} 218 if distcmp(base, x, x) != 0 { 219 t.Errorf("distcmp(base, x, x) != 0") 220 } 221 } 222 223 func TestNodeID_logdist(t *testing.T) { 224 logdistBig := func(a, b common.Hash) int { 225 abig, bbig := new(big.Int).SetBytes(a[:]), new(big.Int).SetBytes(b[:]) 226 return new(big.Int).Xor(abig, bbig).BitLen() 227 } 228 if err := quick.CheckEqual(logdist, logdistBig, quickcfg()); err != nil { 229 t.Error(err) 230 } 231 } 232 233 func TestNodeID_logdistEqual(t *testing.T) { 234 x := common.Hash{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 235 if logdist(x, x) != 0 { 236 t.Errorf("logdist(x, x) != 0") 237 } 238 } 239 240 func TestNodeID_hashAtDistance(t *testing.T) { 241 cfg := quickcfg() 242 for i := 0; i < cfg.MaxCount; i++ { 243 a := gen(common.Hash{}, cfg.Rand).(common.Hash) 244 dist := cfg.Rand.Intn(len(common.Hash{}) * 8) 245 result := hashAtDistance(a, dist) 246 actualdist := logdist(result, a) 247 248 if dist != actualdist { 249 t.Log("a: ", a) 250 t.Log("result:", result) 251 t.Fatalf("#%d: distance of result is %d, want %d", i, actualdist, dist) 252 } 253 } 254 } 255 256 func quickcfg() *quick.Config { 257 return &quick.Config{ 258 MaxCount: 5000, 259 Rand: rand.New(rand.NewSource(time.Now().Unix())), 260 } 261 } 262 263 func (NodeID) Generate(rand *rand.Rand, size int) reflect.Value { 264 var id NodeID 265 m := rand.Intn(len(id)) 266 for i := len(id) - 1; i > m; i-- { 267 id[i] = byte(rand.Uint32()) 268 } 269 return reflect.ValueOf(id) 270 }