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