github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/network/kademlia_test.go (about) 1 // Copyleft 2018 The susy-graviton Authors 2 // This file is part of the susy-graviton library. 3 // 4 // The susy-graviton 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 susy-graviton library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MSRCHANTABILITY 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 susy-graviton library. If not, see <http://www.gnu.org/licenses/>. 16 17 package network 18 19 import ( 20 "fmt" 21 "os" 22 "testing" 23 "time" 24 25 "github.com/susy-go/susy-graviton/common" 26 "github.com/susy-go/susy-graviton/log" 27 "github.com/susy-go/susy-graviton/p2p" 28 "github.com/susy-go/susy-graviton/p2p/enode" 29 "github.com/susy-go/susy-graviton/p2p/protocols" 30 "github.com/susy-go/susy-graviton/swarm/pot" 31 ) 32 33 func init() { 34 h := log.LvlFilterHandler(log.LvlWarn, log.StreamHandler(os.Stderr, log.TerminalFormat(true))) 35 log.Root().SetHandler(h) 36 } 37 38 func testKadPeerAddr(s string) *BzzAddr { 39 a := pot.NewAddressFromString(s) 40 return &BzzAddr{OAddr: a, UAddr: a} 41 } 42 43 func newTestKademliaParams() *KadParams { 44 params := NewKadParams() 45 params.MinBinSize = 2 46 params.NeighbourhoodSize = 2 47 return params 48 } 49 50 type testKademlia struct { 51 *Kademlia 52 t *testing.T 53 } 54 55 func newTestKademlia(t *testing.T, b string) *testKademlia { 56 base := pot.NewAddressFromString(b) 57 return &testKademlia{ 58 Kademlia: NewKademlia(base, newTestKademliaParams()), 59 t: t, 60 } 61 } 62 63 func (tk *testKademlia) newTestKadPeer(s string, lightNode bool) *Peer { 64 return NewPeer(&BzzPeer{BzzAddr: testKadPeerAddr(s), LightNode: lightNode}, tk.Kademlia) 65 } 66 67 func (tk *testKademlia) On(ons ...string) { 68 for _, s := range ons { 69 tk.Kademlia.On(tk.newTestKadPeer(s, false)) 70 } 71 } 72 73 func (tk *testKademlia) Off(offs ...string) { 74 for _, s := range offs { 75 tk.Kademlia.Off(tk.newTestKadPeer(s, false)) 76 } 77 } 78 79 func (tk *testKademlia) Register(regs ...string) { 80 var as []*BzzAddr 81 for _, s := range regs { 82 as = append(as, testKadPeerAddr(s)) 83 } 84 err := tk.Kademlia.Register(as...) 85 if err != nil { 86 panic(err.Error()) 87 } 88 } 89 90 // tests the validity of neighborhood depth calculations 91 // 92 // in particular, it tests that if there are one or more consecutive 93 // empty bins above the farthest "nearest neighbor-peer" then 94 // the depth should be set at the farthest of those empty bins 95 // 96 // TODO: Make test adapt to change in NeighbourhoodSize 97 func TestNeighbourhoodDepth(t *testing.T) { 98 baseAddressBytes := RandomAddr().OAddr 99 kad := NewKademlia(baseAddressBytes, NewKadParams()) 100 101 baseAddress := pot.NewAddressFromBytes(baseAddressBytes) 102 103 // generate the peers 104 var peers []*Peer 105 for i := 0; i < 7; i++ { 106 addr := pot.RandomAddressAt(baseAddress, i) 107 peers = append(peers, newTestDiscoveryPeer(addr, kad)) 108 } 109 var sevenPeers []*Peer 110 for i := 0; i < 2; i++ { 111 addr := pot.RandomAddressAt(baseAddress, 7) 112 sevenPeers = append(sevenPeers, newTestDiscoveryPeer(addr, kad)) 113 } 114 115 testNum := 0 116 // first try with empty kademlia 117 depth := kad.NeighbourhoodDepth() 118 if depth != 0 { 119 t.Fatalf("%d expected depth 0, was %d", testNum, depth) 120 } 121 testNum++ 122 123 // add one peer on 7 124 kad.On(sevenPeers[0]) 125 depth = kad.NeighbourhoodDepth() 126 if depth != 0 { 127 t.Fatalf("%d expected depth 0, was %d", testNum, depth) 128 } 129 testNum++ 130 131 // add a second on 7 132 kad.On(sevenPeers[1]) 133 depth = kad.NeighbourhoodDepth() 134 if depth != 0 { 135 t.Fatalf("%d expected depth 0, was %d", testNum, depth) 136 } 137 testNum++ 138 139 // add from 0 to 6 140 for i, p := range peers { 141 kad.On(p) 142 depth = kad.NeighbourhoodDepth() 143 if depth != i+1 { 144 t.Fatalf("%d.%d expected depth %d, was %d", i+1, testNum, i, depth) 145 } 146 } 147 testNum++ 148 149 kad.Off(sevenPeers[1]) 150 depth = kad.NeighbourhoodDepth() 151 if depth != 6 { 152 t.Fatalf("%d expected depth 6, was %d", testNum, depth) 153 } 154 testNum++ 155 156 kad.Off(peers[4]) 157 depth = kad.NeighbourhoodDepth() 158 if depth != 4 { 159 t.Fatalf("%d expected depth 4, was %d", testNum, depth) 160 } 161 testNum++ 162 163 kad.Off(peers[3]) 164 depth = kad.NeighbourhoodDepth() 165 if depth != 3 { 166 t.Fatalf("%d expected depth 3, was %d", testNum, depth) 167 } 168 testNum++ 169 } 170 171 // TestHighMinBinSize tests that the saturation function also works 172 // if MinBinSize is > 2, the connection count is < k.MinBinSize 173 // and there are more peers available than connected 174 func TestHighMinBinSize(t *testing.T) { 175 // a function to test for different MinBinSize values 176 testKad := func(minBinSize int) { 177 // create a test kademlia 178 tk := newTestKademlia(t, "11111111") 179 // set its MinBinSize to desired value 180 tk.KadParams.MinBinSize = minBinSize 181 182 // add a couple of peers (so we have NN and depth) 183 tk.On("00000000") // bin 0 184 tk.On("11100000") // bin 3 185 tk.On("11110000") // bin 4 186 187 first := "10000000" // add a first peer at bin 1 188 tk.Register(first) // register it 189 // we now have one registered peer at bin 1; 190 // iterate and connect one peer at each iteration; 191 // should be unhealthy until at minBinSize - 1 192 // we connect the unconnected but registered peer 193 for i := 1; i < minBinSize; i++ { 194 peer := fmt.Sprintf("1000%b", 8|i) 195 tk.On(peer) 196 if i == minBinSize-1 { 197 tk.On(first) 198 tk.checkHealth(true) 199 return 200 } 201 tk.checkHealth(false) 202 } 203 } 204 // test MinBinSizes of 3 to 5 205 testMinBinSizes := []int{3, 4, 5} 206 for _, k := range testMinBinSizes { 207 testKad(k) 208 } 209 } 210 211 // TestHealthStrict tests the simplest definition of health 212 // Which means whether we are connected to all neighbors we know of 213 func TestHealthStrict(t *testing.T) { 214 215 // base address is all zeros 216 // no peers 217 // unhealthy (and lonely) 218 tk := newTestKademlia(t, "11111111") 219 tk.checkHealth(false) 220 221 // know one peer but not connected 222 // unhealthy 223 tk.Register("11100000") 224 tk.checkHealth(false) 225 226 // know one peer and connected 227 // unhealthy: not saturated 228 tk.On("11100000") 229 tk.checkHealth(true) 230 231 // know two peers, only one connected 232 // unhealthy 233 tk.Register("11111100") 234 tk.checkHealth(false) 235 236 // know two peers and connected to both 237 // healthy 238 tk.On("11111100") 239 tk.checkHealth(true) 240 241 // know three peers, connected to the two deepest 242 // healthy 243 tk.Register("00000000") 244 tk.checkHealth(false) 245 246 // know three peers, connected to all three 247 // healthy 248 tk.On("00000000") 249 tk.checkHealth(true) 250 251 // add fourth peer deeper than current depth 252 // unhealthy 253 tk.Register("11110000") 254 tk.checkHealth(false) 255 256 // connected to three deepest peers 257 // healthy 258 tk.On("11110000") 259 tk.checkHealth(true) 260 261 // add additional peer in same bin as deepest peer 262 // unhealthy 263 tk.Register("11111101") 264 tk.checkHealth(false) 265 266 // four deepest of five peers connected 267 // healthy 268 tk.On("11111101") 269 tk.checkHealth(true) 270 271 // add additional peer in bin 0 272 // unhealthy: unsaturated bin 0, 2 known but 1 connected 273 tk.Register("00000001") 274 tk.checkHealth(false) 275 276 // Connect second in bin 0 277 // healthy 278 tk.On("00000001") 279 tk.checkHealth(true) 280 281 // add peer in bin 1 282 // unhealthy, as it is known but not connected 283 tk.Register("10000000") 284 tk.checkHealth(false) 285 286 // connect peer in bin 1 287 // depth change, is now 1 288 // healthy, 1 peer in bin 1 known and connected 289 tk.On("10000000") 290 tk.checkHealth(true) 291 292 // add second peer in bin 1 293 // unhealthy, as it is known but not connected 294 tk.Register("10000001") 295 tk.checkHealth(false) 296 297 // connect second peer in bin 1 298 // healthy, 299 tk.On("10000001") 300 tk.checkHealth(true) 301 302 // connect third peer in bin 1 303 // healthy, 304 tk.On("10000011") 305 tk.checkHealth(true) 306 307 // add peer in bin 2 308 // unhealthy, no depth change 309 tk.Register("11000000") 310 tk.checkHealth(false) 311 312 // connect peer in bin 2 313 // depth change - as we already have peers in bin 3 and 4, 314 // we have contiguous bins, no bin < po 5 is empty -> depth 5 315 // healthy, every bin < depth has the max available peers, 316 // even if they are < MinBinSize 317 tk.On("11000000") 318 tk.checkHealth(true) 319 320 // add peer in bin 2 321 // unhealthy, peer bin is below depth 5 but 322 // has more available peers (2) than connected ones (1) 323 // --> unsaturated 324 tk.Register("11000011") 325 tk.checkHealth(false) 326 } 327 328 func (tk *testKademlia) checkHealth(expectHealthy bool) { 329 tk.t.Helper() 330 kid := common.Bytes2Hex(tk.BaseAddr()) 331 addrs := [][]byte{tk.BaseAddr()} 332 tk.EachAddr(nil, 255, func(addr *BzzAddr, po int) bool { 333 addrs = append(addrs, addr.Address()) 334 return true 335 }) 336 337 pp := NewPeerPotMap(tk.NeighbourhoodSize, addrs) 338 healthParams := tk.GetHealthInfo(pp[kid]) 339 340 // definition of health, all conditions but be true: 341 // - we at least know one peer 342 // - we know all neighbors 343 // - we are connected to all known neighbors 344 health := healthParams.Healthy() 345 if expectHealthy != health { 346 tk.t.Fatalf("expected kademlia health %v, is %v\n%v", expectHealthy, health, tk.String()) 347 } 348 } 349 350 func (tk *testKademlia) checkSuggestPeer(expAddr string, expDepth int, expChanged bool) { 351 tk.t.Helper() 352 addr, depth, changed := tk.SuggestPeer() 353 log.Trace("suggestPeer return", "addr", addr, "depth", depth, "changed", changed) 354 if binStr(addr) != expAddr { 355 tk.t.Fatalf("incorrect peer address suggested. expected %v, got %v", expAddr, binStr(addr)) 356 } 357 if depth != expDepth { 358 tk.t.Fatalf("incorrect saturation depth suggested. expected %v, got %v", expDepth, depth) 359 } 360 if changed != expChanged { 361 tk.t.Fatalf("expected depth change = %v, got %v", expChanged, changed) 362 } 363 } 364 365 func binStr(a *BzzAddr) string { 366 if a == nil { 367 return "<nil>" 368 } 369 return pot.ToBin(a.Address())[:8] 370 } 371 372 func TestSuggestPeerFindPeers(t *testing.T) { 373 tk := newTestKademlia(t, "00000000") 374 tk.On("00100000") 375 tk.checkSuggestPeer("<nil>", 0, false) 376 377 tk.On("00010000") 378 tk.checkSuggestPeer("<nil>", 0, false) 379 380 tk.On("10000000", "10000001") 381 tk.checkSuggestPeer("<nil>", 0, false) 382 383 tk.On("01000000") 384 tk.Off("10000001") 385 tk.checkSuggestPeer("10000001", 0, true) 386 387 tk.On("00100001") 388 tk.Off("01000000") 389 tk.checkSuggestPeer("01000000", 0, false) 390 391 // second time disconnected peer not callable 392 // with reasonably set Interval 393 tk.checkSuggestPeer("<nil>", 0, false) 394 395 // on and off again, peer callable again 396 tk.On("01000000") 397 tk.Off("01000000") 398 tk.checkSuggestPeer("01000000", 0, false) 399 400 tk.On("01000000", "10000001") 401 tk.checkSuggestPeer("<nil>", 0, false) 402 403 tk.Register("00010001") 404 tk.checkSuggestPeer("00010001", 0, false) 405 406 tk.On("00010001") 407 tk.Off("01000000") 408 tk.checkSuggestPeer("01000000", 0, false) 409 410 tk.On("01000000") 411 tk.checkSuggestPeer("<nil>", 0, false) 412 413 tk.Register("01000001") 414 tk.checkSuggestPeer("01000001", 0, false) 415 416 tk.On("01000001") 417 tk.checkSuggestPeer("<nil>", 0, false) 418 419 tk.Register("10000010", "01000010", "00100010") 420 tk.checkSuggestPeer("<nil>", 0, false) 421 422 tk.Register("00010010") 423 tk.checkSuggestPeer("00010010", 0, false) 424 425 tk.Off("00100001") 426 tk.checkSuggestPeer("00100010", 2, true) 427 428 tk.Off("01000001") 429 tk.checkSuggestPeer("01000010", 1, true) 430 431 tk.checkSuggestPeer("01000001", 0, false) 432 tk.checkSuggestPeer("00100001", 0, false) 433 tk.checkSuggestPeer("<nil>", 0, false) 434 435 tk.On("01000001", "00100001") 436 tk.Register("10000100", "01000100", "00100100") 437 tk.Register("00000100", "00000101", "00000110") 438 tk.Register("00000010", "00000011", "00000001") 439 440 tk.checkSuggestPeer("00000110", 0, false) 441 tk.checkSuggestPeer("00000101", 0, false) 442 tk.checkSuggestPeer("00000100", 0, false) 443 tk.checkSuggestPeer("00000011", 0, false) 444 tk.checkSuggestPeer("00000010", 0, false) 445 tk.checkSuggestPeer("00000001", 0, false) 446 tk.checkSuggestPeer("<nil>", 0, false) 447 448 } 449 450 // a node should stay in the address book if it's removed from the kademlia 451 func TestOffEffectingAddressBookNormalNode(t *testing.T) { 452 tk := newTestKademlia(t, "00000000") 453 // peer added to kademlia 454 tk.On("01000000") 455 // peer should be in the address book 456 if tk.addrs.Size() != 1 { 457 t.Fatal("known peer addresses should contain 1 entry") 458 } 459 // peer should be among live connections 460 if tk.conns.Size() != 1 { 461 t.Fatal("live peers should contain 1 entry") 462 } 463 // remove peer from kademlia 464 tk.Off("01000000") 465 // peer should be in the address book 466 if tk.addrs.Size() != 1 { 467 t.Fatal("known peer addresses should contain 1 entry") 468 } 469 // peer should not be among live connections 470 if tk.conns.Size() != 0 { 471 t.Fatal("live peers should contain 0 entry") 472 } 473 } 474 475 // a light node should not be in the address book 476 func TestOffEffectingAddressBookLightNode(t *testing.T) { 477 tk := newTestKademlia(t, "00000000") 478 // light node peer added to kademlia 479 tk.Kademlia.On(tk.newTestKadPeer("01000000", true)) 480 // peer should not be in the address book 481 if tk.addrs.Size() != 0 { 482 t.Fatal("known peer addresses should contain 0 entry") 483 } 484 // peer should be among live connections 485 if tk.conns.Size() != 1 { 486 t.Fatal("live peers should contain 1 entry") 487 } 488 // remove peer from kademlia 489 tk.Kademlia.Off(tk.newTestKadPeer("01000000", true)) 490 // peer should not be in the address book 491 if tk.addrs.Size() != 0 { 492 t.Fatal("known peer addresses should contain 0 entry") 493 } 494 // peer should not be among live connections 495 if tk.conns.Size() != 0 { 496 t.Fatal("live peers should contain 0 entry") 497 } 498 } 499 500 func TestSuggestPeerRetries(t *testing.T) { 501 tk := newTestKademlia(t, "00000000") 502 tk.RetryInterval = int64(300 * time.Millisecond) // cycle 503 tk.MaxRetries = 50 504 tk.RetryExponent = 2 505 sleep := func(n int) { 506 ts := tk.RetryInterval 507 for i := 1; i < n; i++ { 508 ts *= int64(tk.RetryExponent) 509 } 510 time.Sleep(time.Duration(ts)) 511 } 512 513 tk.Register("01000000") 514 tk.On("00000001", "00000010") 515 tk.checkSuggestPeer("01000000", 0, false) 516 517 tk.checkSuggestPeer("<nil>", 0, false) 518 519 sleep(1) 520 tk.checkSuggestPeer("01000000", 0, false) 521 522 tk.checkSuggestPeer("<nil>", 0, false) 523 524 sleep(1) 525 tk.checkSuggestPeer("01000000", 0, false) 526 527 tk.checkSuggestPeer("<nil>", 0, false) 528 529 sleep(2) 530 tk.checkSuggestPeer("01000000", 0, false) 531 532 tk.checkSuggestPeer("<nil>", 0, false) 533 534 sleep(2) 535 tk.checkSuggestPeer("<nil>", 0, false) 536 } 537 538 func TestKademliaHiveString(t *testing.T) { 539 tk := newTestKademlia(t, "00000000") 540 tk.On("01000000", "00100000") 541 tk.Register("10000000", "10000001") 542 tk.MaxProxDisplay = 8 543 h := tk.String() 544 expH := "\n=========================================================================\nMon Feb 27 12:10:28 UTC 2017 KΛÐΞMLIΛ hive: queen's address: 000000\npopulation: 2 (4), NeighbourhoodSize: 2, MinBinSize: 2, MaxBinSize: 4\n============ DEPTH: 0 ==========================================\n000 0 | 2 8100 (0) 8000 (0)\n001 1 4000 | 1 4000 (0)\n002 1 2000 | 1 2000 (0)\n003 0 | 0\n004 0 | 0\n005 0 | 0\n006 0 | 0\n007 0 | 0\n=========================================================================" 545 if expH[104:] != h[104:] { 546 t.Fatalf("incorrect hive output. expected %v, got %v", expH, h) 547 } 548 } 549 550 func newTestDiscoveryPeer(addr pot.Address, kad *Kademlia) *Peer { 551 rw := &p2p.MsgPipeRW{} 552 p := p2p.NewPeer(enode.ID{}, "foo", []p2p.Cap{}) 553 pp := protocols.NewPeer(p, rw, &protocols.Spec{}) 554 bp := &BzzPeer{ 555 Peer: pp, 556 BzzAddr: &BzzAddr{ 557 OAddr: addr.Bytes(), 558 UAddr: []byte(fmt.Sprintf("%x", addr[:])), 559 }, 560 } 561 return NewPeer(bp, kad) 562 }