github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/renter/hostdb/hostdb_test.go (about) 1 package hostdb 2 3 import ( 4 "bytes" 5 "io/ioutil" 6 "math" 7 "net" 8 "os" 9 "path/filepath" 10 "testing" 11 "time" 12 13 "SiaPrime/build" 14 "SiaPrime/crypto" 15 "SiaPrime/modules" 16 "SiaPrime/modules/consensus" 17 "SiaPrime/modules/gateway" 18 "SiaPrime/modules/miner" 19 "SiaPrime/modules/renter/hostdb/hosttree" 20 "SiaPrime/modules/transactionpool" 21 "SiaPrime/modules/wallet" 22 "SiaPrime/persist" 23 "SiaPrime/types" 24 ) 25 26 // hdbTester contains a hostdb and all dependencies. 27 type hdbTester struct { 28 cs modules.ConsensusSet 29 gateway modules.Gateway 30 miner modules.TestMiner 31 tpool modules.TransactionPool 32 wallet modules.Wallet 33 walletKey crypto.TwofishKey 34 35 hdb *HostDB 36 37 persistDir string 38 } 39 40 // bareHostDB returns a HostDB with its fields initialized, but without any 41 // dependencies or scanning threads. It is only intended for use in unit tests. 42 func bareHostDB() *HostDB { 43 hdb := &HostDB{ 44 log: persist.NewLogger(ioutil.Discard), 45 } 46 hdb.weightFunc = hdb.calculateHostWeightFn(modules.DefaultAllowance) 47 hdb.hostTree = hosttree.New(hdb.weightFunc, &modules.ProductionResolver{}) 48 return hdb 49 } 50 51 // makeHostDBEntry makes a new host entry with a random public key 52 func makeHostDBEntry() modules.HostDBEntry { 53 dbe := modules.HostDBEntry{} 54 _, pk := crypto.GenerateKeyPair() 55 56 dbe.AcceptingContracts = true 57 dbe.PublicKey = types.Ed25519PublicKey(pk) 58 dbe.ScanHistory = modules.HostDBScans{{ 59 Timestamp: time.Now(), 60 Success: true, 61 }} 62 return dbe 63 } 64 65 // newHDBTester returns a tester object wrapping a HostDB and some extra 66 // information for testing. 67 func newHDBTester(name string) (*hdbTester, error) { 68 return newHDBTesterDeps(name, modules.ProdDependencies) 69 } 70 71 // newHDBTesterDeps returns a tester object wrapping a HostDB and some extra 72 // information for testing, using the provided dependencies for the hostdb. 73 func newHDBTesterDeps(name string, deps modules.Dependencies) (*hdbTester, error) { 74 if testing.Short() { 75 panic("should not be calling newHDBTester during short tests") 76 } 77 testDir := build.TempDir("HostDB", name) 78 79 g, err := gateway.New("localhost:0", false, filepath.Join(testDir, modules.GatewayDir)) 80 if err != nil { 81 return nil, err 82 } 83 cs, err := consensus.New(g, false, filepath.Join(testDir, modules.ConsensusDir)) 84 if err != nil { 85 return nil, err 86 } 87 tp, err := transactionpool.New(cs, g, filepath.Join(testDir, modules.TransactionPoolDir)) 88 if err != nil { 89 return nil, err 90 } 91 w, err := wallet.New(cs, tp, filepath.Join(testDir, modules.WalletDir)) 92 if err != nil { 93 return nil, err 94 } 95 m, err := miner.New(cs, tp, w, filepath.Join(testDir, modules.MinerDir)) 96 if err != nil { 97 return nil, err 98 } 99 hdb, err := NewCustomHostDB(g, cs, filepath.Join(testDir, modules.RenterDir), deps) 100 if err != nil { 101 return nil, err 102 } 103 104 hdbt := &hdbTester{ 105 cs: cs, 106 gateway: g, 107 miner: m, 108 tpool: tp, 109 wallet: w, 110 111 hdb: hdb, 112 113 persistDir: testDir, 114 } 115 116 err = hdbt.initWallet() 117 if err != nil { 118 return nil, err 119 } 120 121 return hdbt, nil 122 } 123 124 // initWallet creates a wallet key, then initializes and unlocks the wallet. 125 func (hdbt *hdbTester) initWallet() error { 126 hdbt.walletKey = crypto.GenerateTwofishKey() 127 _, err := hdbt.wallet.Encrypt(hdbt.walletKey) 128 if err != nil { 129 return err 130 } 131 err = hdbt.wallet.Unlock(hdbt.walletKey) 132 if err != nil { 133 return err 134 } 135 return nil 136 } 137 138 // TestAverageContractPrice tests the AverageContractPrice method, which also depends on the 139 // randomHosts method. 140 func TestAverageContractPrice(t *testing.T) { 141 hdb := bareHostDB() 142 143 // empty 144 if avg := hdb.AverageContractPrice(); !avg.IsZero() { 145 t.Error("average of empty hostdb should be zero:", avg) 146 } 147 148 // with one host 149 h1 := makeHostDBEntry() 150 h1.ContractPrice = types.NewCurrency64(100) 151 hdb.hostTree.Insert(h1) 152 if avg := hdb.AverageContractPrice(); avg.Cmp(h1.ContractPrice) != 0 { 153 t.Error("average of one host should be that host's price:", avg) 154 } 155 156 // with two hosts 157 h2 := makeHostDBEntry() 158 h2.ContractPrice = types.NewCurrency64(300) 159 hdb.hostTree.Insert(h2) 160 if avg := hdb.AverageContractPrice(); avg.Cmp64(200) != 0 { 161 t.Error("average of two hosts should be their sum/2:", avg) 162 } 163 } 164 165 // TestNew tests the New function. 166 func TestNew(t *testing.T) { 167 if testing.Short() { 168 t.SkipNow() 169 } 170 testDir := build.TempDir("HostDB", t.Name()) 171 g, err := gateway.New("localhost:0", false, filepath.Join(testDir, modules.GatewayDir)) 172 if err != nil { 173 t.Fatal(err) 174 } 175 cs, err := consensus.New(g, false, filepath.Join(testDir, modules.ConsensusDir)) 176 if err != nil { 177 t.Fatal(err) 178 } 179 180 // Vanilla HDB, nothing should go wrong. 181 hdbName := filepath.Join(testDir, modules.RenterDir) 182 _, err = New(g, cs, hdbName+"1") 183 if err != nil { 184 t.Fatal(err) 185 } 186 187 // Nil gateway. 188 _, err = New(nil, cs, hdbName+"2") 189 if err != errNilGateway { 190 t.Fatalf("expected %v, got %v", errNilGateway, err) 191 } 192 // Nil consensus set. 193 _, err = New(g, nil, hdbName+"3") 194 if err != errNilCS { 195 t.Fatalf("expected %v, got %v", errNilCS, err) 196 } 197 // Bad persistDir. 198 _, err = New(g, cs, "") 199 if !os.IsNotExist(err) { 200 t.Fatalf("expected invalid directory, got %v", err) 201 } 202 } 203 204 // quitAfterLoadDeps will quit startup in newHostDB 205 type disableScanLoopDeps struct { 206 modules.ProductionDependencies 207 } 208 209 // Send a disrupt signal to the quitAfterLoad codebreak. 210 func (*disableScanLoopDeps) Disrupt(s string) bool { 211 if s == "disableScanLoop" { 212 return true 213 } 214 return false 215 } 216 217 // TestRandomHosts tests the hostdb's exported RandomHosts method. 218 func TestRandomHosts(t *testing.T) { 219 if testing.Short() { 220 t.SkipNow() 221 } 222 hdbt, err := newHDBTesterDeps(t.Name(), &disableScanLoopDeps{}) 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 entries := make(map[string]modules.HostDBEntry) 228 nEntries := int(1e3) 229 for i := 0; i < nEntries; i++ { 230 entry := makeHostDBEntry() 231 entries[string(entry.PublicKey.Key)] = entry 232 err := hdbt.hdb.hostTree.Insert(entry) 233 if err != nil { 234 t.Error(err) 235 } 236 } 237 238 // Check that all hosts can be queried. 239 for i := 0; i < 25; i++ { 240 hosts, err := hdbt.hdb.RandomHosts(nEntries, nil, nil) 241 if err != nil { 242 t.Fatal("Failed to get hosts", err) 243 } 244 if len(hosts) != nEntries { 245 t.Errorf("RandomHosts returned few entries. got %v wanted %v\n", len(hosts), nEntries) 246 } 247 dupCheck := make(map[string]modules.HostDBEntry) 248 for _, host := range hosts { 249 _, exists := entries[string(host.PublicKey.Key)] 250 if !exists { 251 t.Error("hostdb returning host that doesn't exist.") 252 } 253 _, exists = dupCheck[string(host.PublicKey.Key)] 254 if exists { 255 t.Error("RandomHosts returning duplicates") 256 } 257 dupCheck[string(host.PublicKey.Key)] = host 258 } 259 } 260 261 // Base case, fill out a map exposing hosts from a single RH query. 262 dupCheck1 := make(map[string]modules.HostDBEntry) 263 hosts, err := hdbt.hdb.RandomHosts(nEntries/2, nil, nil) 264 if err != nil { 265 t.Fatal("Failed to get hosts", err) 266 } 267 if len(hosts) != nEntries/2 { 268 t.Fatalf("RandomHosts returned few entries. got %v wanted %v\n", len(hosts), nEntries/2) 269 } 270 for _, host := range hosts { 271 _, exists := entries[string(host.PublicKey.Key)] 272 if !exists { 273 t.Error("hostdb returning host that doesn't exist.") 274 } 275 _, exists = dupCheck1[string(host.PublicKey.Key)] 276 if exists { 277 t.Error("RandomHosts returning duplicates") 278 } 279 dupCheck1[string(host.PublicKey.Key)] = host 280 } 281 282 // Iterative case. Check that every time you query for random hosts, you 283 // get different responses. 284 for i := 0; i < 10; i++ { 285 dupCheck2 := make(map[string]modules.HostDBEntry) 286 var overlap, disjoint bool 287 hosts, err = hdbt.hdb.RandomHosts(nEntries/2, nil, nil) 288 if err != nil { 289 t.Fatal("Failed to get hosts", err) 290 } 291 if len(hosts) != nEntries/2 { 292 t.Fatalf("RandomHosts returned few entries. got %v wanted %v\n", len(hosts), nEntries/2) 293 } 294 for _, host := range hosts { 295 _, exists := entries[string(host.PublicKey.Key)] 296 if !exists { 297 t.Error("hostdb returning host that doesn't exist.") 298 } 299 _, exists = dupCheck2[string(host.PublicKey.Key)] 300 if exists { 301 t.Error("RandomHosts returning duplicates") 302 } 303 _, exists = dupCheck1[string(host.PublicKey.Key)] 304 if exists { 305 overlap = true 306 } else { 307 disjoint = true 308 } 309 dupCheck2[string(host.PublicKey.Key)] = host 310 311 } 312 if !overlap || !disjoint { 313 t.Error("Random hosts does not seem to be random") 314 } 315 dupCheck1 = dupCheck2 316 } 317 318 // Try exclude list by excluding every host except for the last one, and 319 // doing a random select. 320 for i := 0; i < 25; i++ { 321 hosts, err := hdbt.hdb.RandomHosts(nEntries, nil, nil) 322 if err != nil { 323 t.Fatal("Failed to get hosts", err) 324 } 325 var exclude []types.SiaPublicKey 326 for j := 1; j < len(hosts); j++ { 327 exclude = append(exclude, hosts[j].PublicKey) 328 } 329 rand, err := hdbt.hdb.RandomHosts(1, exclude, nil) 330 if err != nil { 331 t.Fatal("Failed to get hosts", err) 332 } 333 if len(rand) != 1 { 334 t.Fatal("wrong number of hosts returned") 335 } 336 if string(rand[0].PublicKey.Key) != string(hosts[0].PublicKey.Key) { 337 t.Error("exclude list seems to be excluding the wrong hosts.") 338 } 339 340 // Try again but request more hosts than are available. 341 rand, err = hdbt.hdb.RandomHosts(5, exclude, nil) 342 if err != nil { 343 t.Fatal("Failed to get hosts", err) 344 } 345 if len(rand) != 1 { 346 t.Fatal("wrong number of hosts returned") 347 } 348 if string(rand[0].PublicKey.Key) != string(hosts[0].PublicKey.Key) { 349 t.Error("exclude list seems to be excluding the wrong hosts.") 350 } 351 352 // Create an include map, and decrease the number of excluded hosts. 353 // Make sure all hosts returned by rand function are in the include 354 // map. 355 includeMap := make(map[string]struct{}) 356 for j := 0; j < 50; j++ { 357 includeMap[string(hosts[j].PublicKey.Key)] = struct{}{} 358 } 359 exclude = exclude[49:] 360 361 // Select only 20 hosts. 362 dupCheck := make(map[string]struct{}) 363 rand, err = hdbt.hdb.RandomHosts(20, exclude, nil) 364 if err != nil { 365 t.Fatal("Failed to get hosts", err) 366 } 367 if len(rand) != 20 { 368 t.Error("random hosts is returning the wrong number of hosts") 369 } 370 for _, host := range rand { 371 _, exists := dupCheck[string(host.PublicKey.Key)] 372 if exists { 373 t.Error("RandomHosts is seleccting duplicates") 374 } 375 dupCheck[string(host.PublicKey.Key)] = struct{}{} 376 _, exists = includeMap[string(host.PublicKey.Key)] 377 if !exists { 378 t.Error("RandomHosts returning excluded hosts") 379 } 380 } 381 382 // Select exactly 50 hosts. 383 dupCheck = make(map[string]struct{}) 384 rand, err = hdbt.hdb.RandomHosts(50, exclude, nil) 385 if err != nil { 386 t.Fatal("Failed to get hosts", err) 387 } 388 if len(rand) != 50 { 389 t.Error("random hosts is returning the wrong number of hosts") 390 } 391 for _, host := range rand { 392 _, exists := dupCheck[string(host.PublicKey.Key)] 393 if exists { 394 t.Error("RandomHosts is seleccting duplicates") 395 } 396 dupCheck[string(host.PublicKey.Key)] = struct{}{} 397 _, exists = includeMap[string(host.PublicKey.Key)] 398 if !exists { 399 t.Error("RandomHosts returning excluded hosts") 400 } 401 } 402 403 // Select 100 hosts. 404 dupCheck = make(map[string]struct{}) 405 rand, err = hdbt.hdb.RandomHosts(100, exclude, nil) 406 if err != nil { 407 t.Fatal("Failed to get hosts", err) 408 } 409 if len(rand) != 50 { 410 t.Error("random hosts is returning the wrong number of hosts") 411 } 412 for _, host := range rand { 413 _, exists := dupCheck[string(host.PublicKey.Key)] 414 if exists { 415 t.Error("RandomHosts is seleccting duplicates") 416 } 417 dupCheck[string(host.PublicKey.Key)] = struct{}{} 418 _, exists = includeMap[string(host.PublicKey.Key)] 419 if !exists { 420 t.Error("RandomHosts returning excluded hosts") 421 } 422 } 423 } 424 } 425 426 // TestRemoveNonexistingHostFromHostTree checks that the host tree interface 427 // correctly responds to having a nonexisting host removed from the host tree. 428 func TestRemoveNonexistingHostFromHostTree(t *testing.T) { 429 if testing.Short() { 430 t.SkipNow() 431 } 432 hdbt, err := newHDBTester(t.Name()) 433 if err != nil { 434 t.Fatal(err) 435 } 436 437 // Remove a host that doesn't exist from the tree. 438 err = hdbt.hdb.hostTree.Remove(types.SiaPublicKey{}) 439 if err == nil { 440 t.Fatal("There should be an error, but not a panic:", err) 441 } 442 } 443 444 // TestUpdateHistoricInteractions is a simple check to ensure that incrementing 445 // the recent and historic host interactions works 446 func TestUpdateHistoricInteractions(t *testing.T) { 447 if testing.Short() { 448 t.SkipNow() 449 } 450 451 // create a HostDB tester without scanloop to be able to manually increment 452 // the interactions without interference. 453 hdbt, err := newHDBTesterDeps(t.Name(), &disableScanLoopDeps{}) 454 if err != nil { 455 t.Fatal(err) 456 } 457 458 // create a HostDBEntry and add it to the tree 459 host := makeHostDBEntry() 460 err = hdbt.hdb.hostTree.Insert(host) 461 if err != nil { 462 t.Error(err) 463 } 464 465 // increment successful and failed interactions by 100 466 interactions := 100.0 467 for i := 0.0; i < interactions; i++ { 468 hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey) 469 hdbt.hdb.IncrementFailedInteractions(host.PublicKey) 470 } 471 472 // get updated host from hostdb 473 host, ok := hdbt.hdb.Host(host.PublicKey) 474 if !ok { 475 t.Fatal("Modified host not found in hostdb") 476 } 477 478 // check that recent interactions are exactly 100 and historic interactions are 0 479 if host.RecentFailedInteractions != interactions || host.RecentSuccessfulInteractions != interactions { 480 t.Errorf("Interactions should be %v but were %v and %v", interactions, 481 host.RecentFailedInteractions, host.RecentSuccessfulInteractions) 482 } 483 if host.HistoricFailedInteractions != 0 || host.HistoricSuccessfulInteractions != 0 { 484 t.Errorf("Historic Interactions should be %v but were %v and %v", 0, 485 host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions) 486 } 487 488 // add single block to consensus 489 _, err = hdbt.miner.AddBlock() 490 if err != nil { 491 t.Fatal(err) 492 } 493 494 // increment interactions again by 100 495 for i := 0.0; i < interactions; i++ { 496 hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey) 497 hdbt.hdb.IncrementFailedInteractions(host.PublicKey) 498 } 499 500 // get updated host from hostdb 501 host, ok = hdbt.hdb.Host(host.PublicKey) 502 if !ok { 503 t.Fatal("Modified host not found in hostdb") 504 } 505 506 // historic actions should have incremented slightly, due to the clamp the 507 // full interactions should not have made it into the historic group. 508 if host.RecentFailedInteractions != interactions || host.RecentSuccessfulInteractions != interactions { 509 t.Errorf("Interactions should be %v but were %v and %v", interactions, 510 host.RecentFailedInteractions, host.RecentSuccessfulInteractions) 511 } 512 if host.HistoricFailedInteractions == 0 || host.HistoricSuccessfulInteractions == 0 { 513 t.Error("historic actions should have updated") 514 } 515 516 // add 200 blocks to consensus, adding large numbers of historic actions 517 // each time, so that the clamp does not need to be in effect anymore. 518 for i := 0; i < 200; i++ { 519 for j := uint64(0); j < 10; j++ { 520 hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey) 521 hdbt.hdb.IncrementFailedInteractions(host.PublicKey) 522 } 523 _, err = hdbt.miner.AddBlock() 524 if err != nil { 525 t.Fatal(err) 526 } 527 } 528 529 // Add five interactions 530 for i := 0; i < 5; i++ { 531 hdbt.hdb.IncrementSuccessfulInteractions(host.PublicKey) 532 hdbt.hdb.IncrementFailedInteractions(host.PublicKey) 533 } 534 535 // get updated host from hostdb 536 host, ok = hdbt.hdb.Host(host.PublicKey) 537 if !ok { 538 t.Fatal("Modified host not found in hostdb") 539 } 540 541 // check that recent interactions are exactly 5. Save the historic actions 542 // to check that decay is being handled correctly, and that the recent 543 // interactions are moved over correctly. 544 if host.RecentFailedInteractions != 5 || host.RecentSuccessfulInteractions != 5 { 545 t.Errorf("Interactions should be %v but were %v and %v", interactions, 546 host.RecentFailedInteractions, host.RecentSuccessfulInteractions) 547 } 548 historicFailed := host.HistoricFailedInteractions 549 if host.HistoricFailedInteractions != host.HistoricSuccessfulInteractions { 550 t.Error("historic failed and successful should have the same values") 551 } 552 553 // Add a single block to apply one round of decay. 554 _, err = hdbt.miner.AddBlock() 555 if err != nil { 556 t.Fatal(err) 557 } 558 host, ok = hdbt.hdb.Host(host.PublicKey) 559 if !ok { 560 t.Fatal("Modified host not found in hostdb") 561 } 562 563 // Get the historic successful and failed interactions, and see that they 564 // are decaying properly. 565 expected := historicFailed*math.Pow(historicInteractionDecay, 1) + 5 566 if host.HistoricFailedInteractions != expected || host.HistoricSuccessfulInteractions != expected { 567 t.Errorf("Historic Interactions should be %v but were %v and %v", expected, 568 host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions) 569 } 570 571 // Add 10 more blocks and check the decay again, make sure it's being 572 // applied correctly. 573 for i := 0; i < 10; i++ { 574 _, err := hdbt.miner.AddBlock() 575 if err != nil { 576 t.Fatal(err) 577 } 578 } 579 host, ok = hdbt.hdb.Host(host.PublicKey) 580 if !ok { 581 t.Fatal("Modified host not found in hostdb") 582 } 583 expected = expected * math.Pow(historicInteractionDecay, 10) 584 if host.HistoricFailedInteractions != expected || host.HistoricSuccessfulInteractions != expected { 585 t.Errorf("Historic Interactions should be %v but were %v and %v", expected, 586 host.HistoricFailedInteractions, host.HistoricSuccessfulInteractions) 587 } 588 } 589 590 // testCheckForIPViolationsResolver is a resolver for the TestTwoAddresses test. 591 type testCheckForIPViolationsResolver struct{} 592 593 func (testCheckForIPViolationsResolver) LookupIP(host string) ([]net.IP, error) { 594 switch host { 595 case "host1": 596 return []net.IP{{127, 0, 0, 1}}, nil 597 case "host2": 598 return []net.IP{{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}}, nil 599 case "host3": 600 return []net.IP{{127, 0, 0, 2}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2}}, nil 601 default: 602 panic("shouldn't happen") 603 } 604 } 605 606 // testCheckForIPViolationsDeps is a custom dependency that overrides the 607 // Resolver method to return a testCheckForIPViolationsResolver. 608 type testCheckForIPViolationsDeps struct { 609 disableScanLoopDeps 610 } 611 612 // Resolver returns a testCheckForIPViolationsResolver. 613 func (*testCheckForIPViolationsDeps) Resolver() modules.Resolver { 614 return &testCheckForIPViolationsResolver{} 615 } 616 617 // TestCheckForIPViolations tests the hostdb's CheckForIPViolations method. 618 func TestCheckForIPViolations(t *testing.T) { 619 if testing.Short() { 620 t.SkipNow() 621 } 622 623 // Prepare a few hosts for the test 624 entry1 := makeHostDBEntry() 625 entry1.NetAddress = "host1:1234" 626 entry2 := makeHostDBEntry() 627 entry2.NetAddress = "host2:1234" 628 entry3 := makeHostDBEntry() 629 entry3.NetAddress = "host3:1234" 630 631 // create a HostDB tester without scanloop to be able to manually increment 632 // the interactions without interference. 633 hdbt, err := newHDBTesterDeps(t.Name(), &testCheckForIPViolationsDeps{}) 634 if err != nil { 635 t.Fatal(err) 636 } 637 638 // Scan the entries. entry1 should be the 'oldest' and entry3 the 639 // 'youngest'. This also inserts the entries into the hosttree. 640 hdbt.hdb.managedScanHost(entry1) 641 entry1, _ = hdbt.hdb.Host(entry1.PublicKey) 642 time.Sleep(time.Millisecond) 643 644 hdbt.hdb.managedScanHost(entry2) 645 entry2, _ = hdbt.hdb.Host(entry2.PublicKey) 646 time.Sleep(time.Millisecond) 647 648 hdbt.hdb.managedScanHost(entry3) 649 entry3, _ = hdbt.hdb.Host(entry3.PublicKey) 650 time.Sleep(time.Millisecond) 651 652 // Make sure that the timestamps are not zero and that they entries have 653 // subnets associated with them. 654 if len(entry1.IPNets) == 0 || entry1.LastIPNetChange.IsZero() { 655 t.Fatal("entry1 wasn't updated correctly") 656 } 657 if len(entry2.IPNets) == 0 || entry2.LastIPNetChange.IsZero() { 658 t.Fatal("entry2 wasn't updated correctly") 659 } 660 if len(entry3.IPNets) == 0 || entry3.LastIPNetChange.IsZero() { 661 t.Fatal("entry3 wasn't updated correctly") 662 } 663 664 // Scan all the entries again in reversed order. This is a sanity check. If 665 // the code works as expected this shouldn't do anything since the 666 // hostnames didn't change. If it doesn't, it will update the timestamps 667 // and the following checks will fail. 668 time.Sleep(time.Millisecond) 669 hdbt.hdb.managedScanHost(entry3) 670 entry3, _ = hdbt.hdb.Host(entry3.PublicKey) 671 672 time.Sleep(time.Millisecond) 673 hdbt.hdb.managedScanHost(entry2) 674 entry2, _ = hdbt.hdb.Host(entry2.PublicKey) 675 676 time.Sleep(time.Millisecond) 677 hdbt.hdb.managedScanHost(entry1) 678 entry1, _ = hdbt.hdb.Host(entry1.PublicKey) 679 680 // Add entry1 and entry2. There should be no violation. 681 badHosts := hdbt.hdb.CheckForIPViolations([]types.SiaPublicKey{entry1.PublicKey, entry2.PublicKey}) 682 if len(badHosts) != 0 { 683 t.Errorf("Got %v violations, should be 0", len(badHosts)) 684 } 685 686 // Add entry3. It should cause a violation for entry 3. 687 badHosts = hdbt.hdb.CheckForIPViolations([]types.SiaPublicKey{entry1.PublicKey, entry2.PublicKey, entry3.PublicKey}) 688 if len(badHosts) != 1 { 689 t.Errorf("Got %v violations, should be 1", len(badHosts)) 690 } 691 if len(badHosts) > 0 && !bytes.Equal(badHosts[0].Key, entry3.PublicKey.Key) { 692 t.Error("Hdb returned violation for wrong host") 693 } 694 695 // Calling CheckForIPViolations with entry 2 as the first argument and 696 // entry1 as the second should result in entry3 being the bad host again. 697 badHosts = hdbt.hdb.CheckForIPViolations([]types.SiaPublicKey{entry2.PublicKey, entry1.PublicKey, entry3.PublicKey}) 698 if len(badHosts) != 1 { 699 t.Errorf("Got %v violations, should be 1", len(badHosts)) 700 } 701 if len(badHosts) > 0 && !bytes.Equal(badHosts[0].Key, entry3.PublicKey.Key) { 702 t.Error("Hdb returned violation for wrong host") 703 } 704 705 // Calling CheckForIPViolations with entry 3 as the first argument should 706 // result in 1 bad host, entry3. The reason being that entry3 is the 707 // 'youngest' entry. 708 badHosts = hdbt.hdb.CheckForIPViolations([]types.SiaPublicKey{entry3.PublicKey, entry1.PublicKey, entry2.PublicKey}) 709 if len(badHosts) != 1 { 710 t.Errorf("Got %v violations, should be 1", len(badHosts)) 711 } 712 if len(badHosts) > 1 || !bytes.Equal(badHosts[0].Key, entry3.PublicKey.Key) { 713 t.Error("Hdb returned violation for wrong host") 714 } 715 }