github.com/core-coin/go-core/v2@v2.1.9/p2p/discover/v4_lookup_test.go (about) 1 // Copyright 2019 by the Authors 2 // This file is part of the go-core library. 3 // 4 // The go-core 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-core 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-core library. If not, see <http://www.gnu.org/licenses/>. 16 17 package discover 18 19 import ( 20 "fmt" 21 "net" 22 "sort" 23 "testing" 24 25 "github.com/core-coin/go-core/v2/crypto" 26 "github.com/core-coin/go-core/v2/p2p/discover/v4wire" 27 "github.com/core-coin/go-core/v2/p2p/enode" 28 "github.com/core-coin/go-core/v2/p2p/enr" 29 ) 30 31 func TestUDPv4_Lookup(t *testing.T) { 32 t.Parallel() 33 test := newUDPTest(t) 34 35 // Lookup on empty table returns no nodes. 36 targetKey, _ := decodePubkey(lookupTestnet.target[:]) 37 if results := test.udp.LookupPubkey(targetKey); len(results) > 0 { 38 t.Fatalf("lookup on empty table returned %d results: %#v", len(results), results) 39 } 40 41 // Seed table with initial node. 42 fillTable(test.table, []*node{wrapNode(lookupTestnet.node(256, 0))}) 43 44 // Start the lookup. 45 resultC := make(chan []*enode.Node, 1) 46 go func() { 47 resultC <- test.udp.LookupPubkey(targetKey) 48 test.close() 49 }() 50 51 // Answer lookup packets. 52 serveTestnet(test, lookupTestnet) 53 54 // Verify result nodes. 55 results := <-resultC 56 t.Logf("results:") 57 for _, e := range results { 58 t.Logf(" ld=%d, %x", enode.LogDist(lookupTestnet.target.id(), e.ID()), e.ID().Bytes()) 59 } 60 if len(results) != bucketSize { 61 t.Errorf("wrong number of results: got %d, want %d", len(results), bucketSize) 62 } 63 checkLookupResults(t, lookupTestnet, results) 64 } 65 66 func TestUDPv4_LookupIterator(t *testing.T) { 67 t.Parallel() 68 test := newUDPTest(t) 69 defer test.close() 70 71 // Seed table with initial nodes. 72 bootnodes := make([]*node, len(lookupTestnet.dists[256])) 73 for i := range lookupTestnet.dists[256] { 74 bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) 75 } 76 fillTable(test.table, bootnodes) 77 go serveTestnet(test, lookupTestnet) 78 79 // Create the iterator and collect the nodes it yields. 80 iter := test.udp.RandomNodes() 81 seen := make(map[enode.ID]*enode.Node) 82 for limit := lookupTestnet.len(); iter.Next() && len(seen) < limit; { 83 seen[iter.Node().ID()] = iter.Node() 84 } 85 iter.Close() 86 87 // Check that all nodes in lookupTestnet were seen by the iterator. 88 results := make([]*enode.Node, 0, len(seen)) 89 for _, n := range seen { 90 results = append(results, n) 91 } 92 sortByID(results) 93 want := lookupTestnet.nodes() 94 if err := checkNodesEqual(results, want); err != nil { 95 t.Fatal(err) 96 } 97 } 98 99 // TestUDPv4_LookupIteratorClose checks that lookupIterator ends when its Close 100 // method is called. 101 func TestUDPv4_LookupIteratorClose(t *testing.T) { 102 t.Parallel() 103 test := newUDPTest(t) 104 defer test.close() 105 106 // Seed table with initial nodes. 107 bootnodes := make([]*node, len(lookupTestnet.dists[256])) 108 for i := range lookupTestnet.dists[256] { 109 bootnodes[i] = wrapNode(lookupTestnet.node(256, i)) 110 } 111 fillTable(test.table, bootnodes) 112 go serveTestnet(test, lookupTestnet) 113 114 it := test.udp.RandomNodes() 115 if ok := it.Next(); !ok || it.Node() == nil { 116 t.Fatalf("iterator didn't return any node") 117 } 118 119 it.Close() 120 121 ncalls := 0 122 for ; ncalls < 100 && it.Next(); ncalls++ { 123 if it.Node() == nil { 124 t.Error("iterator returned Node() == nil node after Next() == true") 125 } 126 } 127 t.Logf("iterator returned %d nodes after close", ncalls) 128 if it.Next() { 129 t.Errorf("Next() == true after close and %d more calls", ncalls) 130 } 131 if n := it.Node(); n != nil { 132 t.Errorf("iterator returned non-nil node after close and %d more calls", ncalls) 133 } 134 } 135 136 func serveTestnet(test *udpTest, testnet *preminedTestnet) { 137 for done := false; !done; { 138 done = test.waitPacketOut(func(p v4wire.Packet, to *net.UDPAddr, hash []byte) { 139 n, key := testnet.nodeByAddr(to) 140 switch p.(type) { 141 case *v4wire.Ping: 142 test.packetInFrom(nil, key, to, &v4wire.Pong{Expiration: futureExp, ReplyTok: hash}) 143 case *v4wire.Findnode: 144 dist := enode.LogDist(n.ID(), testnet.target.id()) 145 nodes := testnet.nodesAtDistance(dist - 1) 146 test.packetInFrom(nil, key, to, &v4wire.Neighbors{Expiration: futureExp, Nodes: nodes}) 147 } 148 }) 149 } 150 } 151 152 // checkLookupResults verifies that the results of a lookup are the closest nodes to 153 // the testnet's target. 154 func checkLookupResults(t *testing.T, tn *preminedTestnet, results []*enode.Node) { 155 t.Helper() 156 t.Logf("results:") 157 for _, e := range results { 158 t.Logf(" ld=%d, %x", enode.LogDist(tn.target.id(), e.ID()), e.ID().Bytes()) 159 } 160 if hasDuplicates(wrapNodes(results)) { 161 t.Errorf("result set contains duplicate entries") 162 } 163 if !sortedByDistanceTo(tn.target.id(), wrapNodes(results)) { 164 t.Errorf("result set not sorted by distance to target") 165 } 166 wantNodes := tn.closest(len(results)) 167 if err := checkNodesEqual(results, wantNodes); err != nil { 168 t.Error(err) 169 } 170 } 171 172 // This is the test network for the Lookup test. 173 // The nodes were obtained by running lookupTestnet.mine with a random NodeID as target. 174 var lookupTestnet = &preminedTestnet{ 175 target: hexEncPubkey("1033b1bac4c731e800b6399a357e51cf1b20eec942aac608c90b89553003e2ed3f94bd80613ee9006b1e62b6bb45109d0db9a4833e78363991"), 176 dists: [257][]*crypto.PrivateKey{ 177 252: { 178 hexEncPrivkey("bebf794fd362a6792e3d7067f3de2617a1d5e88476665c446ec8e935411c2af0a118f9daa577d29ca9354d40929d074368347d13bba4260011"), 179 hexEncPrivkey("d66e4f8a6710394d176f7d8c5c7d2d670f46604f08dd087c7c3209826f7632f2150555c66263c5a10468696b754d3197a12f45be589bce8f47"), 180 hexEncPrivkey("fd3a176f84fea182cd8f26a0266320a078dfb4ed301bf934968cfedbd381046b01c985c11c406da95fbdbd6935cff506c44dc9c946ee994922"), 181 hexEncPrivkey("6c6f07be1b0a5f5c9f7ccc0baafa2a7bec1613edd65ca626e1ca9e3c083bf5be9a4250385cae574b48bd639328751ee4edb63bb8f34c6c4260"), 182 hexEncPrivkey("51e312adda9f0e79b10230ebe2291f883516cf58ae1484fd5114622aaf55df51da4e4a0436679a99175ee9bbe9a10d74bcc181faaa97aa663f"), 183 hexEncPrivkey("827cc2fad638bff047eac8fe72a8014772ddb1afbf7ead026c9bba79ae37fcf435d299885656bf8a7188c9237f0760cb20480b4274945f8c38"), 184 hexEncPrivkey("a6b70ebf683daf2a45d35b8f11b3ff4b862a6ddbcb0abd8e84a143223c30fc8f189a29e89c1879797773f36a27f80b1d1dde1789c9228af67c"), 185 hexEncPrivkey("27cf27280654c003d01cd9bef5ce6229076b47b3d8cdc8961fc51aa01e81930c2c3c874f3f41b4e2075f09227ef5ea885bf74d6a23b18b485d"), 186 }, 187 253: { 188 hexEncPrivkey("4081b41fcdcd6b37516600587e988f4163fdc62b3be481fb59484be0f64d7f2b6c61ac0c1a3a08276d1aeff4d730fca53f880865868b44070d"), 189 hexEncPrivkey("a9ffa5a151b0c2c3322a87a996ca53aee1913585b6f8da1536a8159c6ff8181d6151a0b3a94bd91c98d2bcc6e2e955495696be3c0ac677bd63"), 190 hexEncPrivkey("4e17d8213d936d55ecf74dac615cdb1c8c027b8ed6c17d1be8d218f9e6a537c7198a80db4d5cf1bbdedb2db390859d7506a9285b5f027ae87c"), 191 hexEncPrivkey("13a04805c5520d94a2ba0d1ef1a569d07dcc4c755581facb78b9bb978e1cd1bdc1063c0b21ac60cab6468a4cede008fe68db06397daafd4709"), 192 hexEncPrivkey("9aa7545a4a02d674a75e7bd28cd05c40fb741b6afe8a3f413ba9e0fcf45244baa9e86ef66e49056a2bdbda78cc833a105f5d37c77b79072426"), 193 hexEncPrivkey("1fe288abdde49133b1b326248364cce118e5c65315497232f2dde6fe7e699d362b31128667de573038285eb9db1af8132fa0805a08083f5d0a"), 194 hexEncPrivkey("8644b2e1bc1156ddd45cc1baba9277177ea395f12255280e1ca17e8023704a1aed46e65c166e190f608ba36bb8a4e0b98536d72b0f075af902"), 195 hexEncPrivkey("56ebbea0e8e6359ec7346c8b4788305be98a52d3f1a51718a426616df4d9706b579db36287d1a5c7dba9d06aee91f0dd46f401afb7760bf15e"), 196 }, 197 254: { 198 hexEncPrivkey("1f41987fb42a7f2bae3ce3f8e307978d284bb97187055e7188399b0a8ae11f94b77a5996b0f0cdcfb23e2cb73ea3304e0b42d659fb5c0e467e"), 199 hexEncPrivkey("3db577f0081c659d29a50a9dcbb0fbeafeb7c6802f6c2133dd46b2509e7815609586d12150290d32e9c0d0d0281f1f3a82187dca72826e510a"), 200 hexEncPrivkey("99a1e743ecec28c7f6113260d9c7b1caba3f7af1cbef356c022b407d4bda91b37c83fdc27ba3b0754355dc868dcb6d764346830e5250737f7e"), 201 hexEncPrivkey("54e2df17fc6f6f587e205a694424b773fac19423ea80d7d8c89a0dbb3e5a007fea913e93cc6cd348e2e301aaa3ea32b55b9bd0e95d44065669"), 202 hexEncPrivkey("e95b80812a230beb081880619c1b87e3d066b57594308edc33b26cb70a433f6195e236808ddb7999af61c401d912557a63495868e60397717e"), 203 hexEncPrivkey("c28a0283131c5e86f67089ce609f67981105a149425670898019c0cb62af39bdf7a29a1f64dace8858b304c4560e612718d50d1d8ed523b21a"), 204 hexEncPrivkey("0428d8bfbfa899c9ac4a200cadc557965dbf339c632582ef32a77621d8313316cf377203bc61793f2ce557ff3c23db77b80d44b26774807b0b"), 205 hexEncPrivkey("4f12886917556baa4d946a4957a64860c9a7411a69fd092c4a7f2e5f24edd5e94f2775565506dd6c6f9fc10be41980d0e8b78380ac7d086120"), 206 }, 207 255: { 208 hexEncPrivkey("2fc8bd43bfd3135ad641a9cd210051e99e02cefd36035b7aa1b5719ff0a2d08dccf3b3eebfc9da9637f6cf6d9adb1abff30e47137f249f6527"), 209 hexEncPrivkey("24c32a500364ebc9d788d2f835dcc3eb5a366618252211a63ac4b34c79f37c575d9f4af0c0be39b1d6da2f129b4be3fba2f2bea40a1b718046"), 210 hexEncPrivkey("8a49050a9a2bbf2770bb81dc8d24d441c872a2b3d705c36ec9e790bd9ba901e466c0fc928a8aeb5c6a5855413a4d4353c23111a599de5daf16"), 211 hexEncPrivkey("eec97595492c8dd546d547ec5e89f88995f88de7502c3e8bab9f12c69beeabe4a7118d71bede4d0585ae626dabad34a0a8b3ef250cf952d311"), 212 hexEncPrivkey("5dfab09f5711258141f0911162e9b6e45058444dbf14fb30b3b7cf8008060ff9af4c8a204a2b1775328db0a6893ff22691da8875b5ca600b01"), 213 hexEncPrivkey("c0c59cd75ef165fe9efeb18d1174a501d20be2807dad3f78b154cc6da674c3ccb0f7eb86e2478eefb1c47de93edc39ad714acc58a6bfad8272"), 214 hexEncPrivkey("e8c0bbbff285d0c52174a7d3369b322bc32fc3c9c4f1f4076dd4ff7f8cbab3578654fb2cad1b4b73df7e274be32ceff8e364e6c55542bc2550"), 215 hexEncPrivkey("dc1415311d36f9d679d9420e47573a60b32378743f95a103f9601bc2009eaa937384cd759338fa69875043c1b98d4c0cedc7de63872e3c4803"), 216 }, 217 256: { 218 hexEncPrivkey("e8be3ec0aeaead80a4083359c8a701b6763a057c1d404e23c9fe126a2e1a82c91164b2d1c4212109e0d3e282f07ffbc55f0681006ac68dfd23"), 219 hexEncPrivkey("b8c107152f99567ef59a79172812b98dbd18f4f0ea2742461dcabf5a6b68e2248f72186510edb72e456456ed7d581287ddcb49cec944f19e16"), 220 hexEncPrivkey("a6755841a42a0335e548ef0669f660aae85795883671f6cc6aedbda7b99e13c0da91a73d04aedf735870a016eafac8d47c32c6fdc20db0f12c"), 221 hexEncPrivkey("738dafc9e041a91195a06bbc6605f6feb7d885c0e1637d3bc84144ea5c03e2a0397fe3b7b7d1487751b4e4f861bfed8cbee1100c2dc4ee5b2f"), 222 hexEncPrivkey("4835941961ecbe18e3409cd8321ddb4c8af298311ad4264e48d8a792e1bc3732569544fa190893fcff5a3706a18334f64e9e15474f92f0dc30"), 223 hexEncPrivkey("556e3483f534b5f142522bcbf7678a3897be6b1d40127938c043e6eb692580cc9152e5f6cae0ab1c5a9f762beccb557165e164df62ced6e94d"), 224 hexEncPrivkey("477f69b000be223c5405a042345b5e95565dd4363d854392a4e27f394d2ba903ba5ef0e3b758640be5144f137929d204d953f798b85a38d955"), 225 hexEncPrivkey("76bcdf6cba61484498cc797fb051c867dc32fb12f80fbc1cacc439d810ce0bdd84372a72675e36202ba9eca3dd8e4ee7d7c66d51392b63eb1b"), 226 }, 227 }, 228 } 229 230 type preminedTestnet struct { 231 target encPubkey 232 dists [hashBits + 1][]*crypto.PrivateKey 233 } 234 235 func (tn *preminedTestnet) len() int { 236 n := 0 237 for _, keys := range tn.dists { 238 n += len(keys) 239 } 240 return n 241 } 242 243 func (tn *preminedTestnet) nodes() []*enode.Node { 244 result := make([]*enode.Node, 0, tn.len()) 245 for dist, keys := range tn.dists { 246 for index := range keys { 247 result = append(result, tn.node(dist, index)) 248 } 249 } 250 sortByID(result) 251 return result 252 } 253 254 func (tn *preminedTestnet) node(dist, index int) *enode.Node { 255 key := tn.dists[dist][index] 256 rec := new(enr.Record) 257 rec.Set(enr.IP{127, byte(dist >> 8), byte(dist), byte(index)}) 258 rec.Set(enr.UDP(5000)) 259 err := enode.SignV4(rec, key) 260 if err != nil { 261 panic(err) 262 } 263 n, err := enode.New(enode.ValidSchemes, rec) 264 if err != nil { 265 panic(err) 266 } 267 return n 268 } 269 270 func (tn *preminedTestnet) nodeByAddr(addr *net.UDPAddr) (*enode.Node, *crypto.PrivateKey) { 271 dist := int(addr.IP[1])<<8 + int(addr.IP[2]) 272 index := int(addr.IP[3]) 273 key := tn.dists[dist][index] 274 return tn.node(dist, index), key 275 } 276 277 func (tn *preminedTestnet) nodesAtDistance(dist int) []v4wire.Node { 278 result := make([]v4wire.Node, len(tn.dists[dist])) 279 for i := range result { 280 result[i] = nodeToRPC(wrapNode(tn.node(dist, i))) 281 } 282 return result 283 } 284 285 func (tn *preminedTestnet) neighborsAtDistances(base *enode.Node, distances []uint, elems int) []*enode.Node { 286 var result []*enode.Node 287 for d := range lookupTestnet.dists { 288 for i := range lookupTestnet.dists[d] { 289 n := lookupTestnet.node(d, i) 290 d := enode.LogDist(base.ID(), n.ID()) 291 if containsUint(uint(d), distances) { 292 result = append(result, n) 293 if len(result) >= elems { 294 return result 295 } 296 } 297 } 298 } 299 return result 300 } 301 302 func (tn *preminedTestnet) closest(n int) (nodes []*enode.Node) { 303 for d := range tn.dists { 304 for i := range tn.dists[d] { 305 nodes = append(nodes, tn.node(d, i)) 306 } 307 } 308 sort.Slice(nodes, func(i, j int) bool { 309 return enode.DistCmp(tn.target.id(), nodes[i].ID(), nodes[j].ID()) < 0 310 }) 311 return nodes[:n] 312 } 313 314 var _ = (*preminedTestnet).mine // avoid linter warning about mine being dead code. 315 316 // mine generates a testnet struct literal with nodes at 317 // various distances to the network's target. 318 func (tn *preminedTestnet) mine() { 319 // Clear existing slices first (useful when re-mining). 320 for i := range tn.dists { 321 tn.dists[i] = nil 322 } 323 324 targetSha := tn.target.id() 325 found, need := 0, 40 326 for found < need { 327 k := newkey() 328 ld := enode.LogDist(targetSha, encodePubkey(k.PublicKey()).id()) 329 if ld > 251 { 330 if len(tn.dists[ld]) < 8 { 331 tn.dists[ld] = append(tn.dists[ld], k) 332 found++ 333 fmt.Printf("found ID with ld %d (%d/%d)\n", ld, found, need) 334 } 335 } 336 } 337 fmt.Printf("&preminedTestnet{\n") 338 fmt.Printf(" target: hexEncPubkey(\"%x\"),\n", tn.target[:]) 339 fmt.Printf(" dists: [%d][]*crypto.PrivateKey{\n", len(tn.dists)) 340 for ld, ns := range tn.dists { 341 if len(ns) == 0 { 342 continue 343 } 344 fmt.Printf(" %d: {\n", ld) 345 for _, key := range ns { 346 fmt.Printf(" hexEncPrivkey(\"%x\"),\n", key.PrivateKey()) 347 } 348 fmt.Printf(" },\n") 349 } 350 fmt.Printf(" },\n") 351 fmt.Printf("}\n") 352 }