github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/node/api/hostdb_test.go (about) 1 package api 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io/ioutil" 8 "net/url" 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/host" 19 "SiaPrime/modules/miner" 20 "SiaPrime/modules/renter" 21 "SiaPrime/modules/transactionpool" 22 "SiaPrime/modules/wallet" 23 ) 24 25 // TestHostDBHostsActiveHandler checks the behavior of the call to 26 // /hostdb/active. 27 func TestHostDBHostsActiveHandler(t *testing.T) { 28 if testing.Short() { 29 t.SkipNow() 30 } 31 st, err := createServerTester(t.Name()) 32 if err != nil { 33 t.Fatal(err) 34 } 35 defer st.server.panicClose() 36 37 // Try the call with numhosts unset, and set to -1, 0, and 1. 38 var ah HostdbActiveGET 39 err = st.getAPI("/hostdb/active", &ah) 40 if err != nil { 41 t.Fatal(err) 42 } 43 if len(ah.Hosts) != 0 { 44 t.Fatal(len(ah.Hosts)) 45 } 46 err = st.getAPI("/hostdb/active?numhosts=-1", &ah) 47 if err == nil { 48 t.Fatal("expecting an error, got:", err) 49 } 50 err = st.getAPI("/hostdb/active?numhosts=0", &ah) 51 if err != nil { 52 t.Fatal(err) 53 } 54 if len(ah.Hosts) != 0 { 55 t.Fatal(len(ah.Hosts)) 56 } 57 err = st.getAPI("/hostdb/active?numhosts=1", &ah) 58 if err != nil { 59 t.Fatal(err) 60 } 61 if len(ah.Hosts) != 0 { 62 t.Fatal(len(ah.Hosts)) 63 } 64 65 // announce the host and start accepting contracts 66 err = st.announceHost() 67 if err != nil { 68 t.Fatal(err) 69 } 70 err = st.acceptContracts() 71 if err != nil { 72 t.Fatal(err) 73 } 74 err = st.setHostStorage() 75 if err != nil { 76 t.Fatal(err) 77 } 78 79 // Try the call with with numhosts unset, and set to -1, 0, 1, and 2. 80 err = st.getAPI("/hostdb/active", &ah) 81 if err != nil { 82 t.Fatal(err) 83 } 84 if len(ah.Hosts) != 1 { 85 t.Fatal(len(ah.Hosts)) 86 } 87 err = st.getAPI("/hostdb/active?numhosts=-1", &ah) 88 if err == nil { 89 t.Fatal("expecting an error, got:", err) 90 } 91 err = st.getAPI("/hostdb/active?numhosts=0", &ah) 92 if err != nil { 93 t.Fatal(err) 94 } 95 if len(ah.Hosts) != 0 { 96 t.Fatal(len(ah.Hosts)) 97 } 98 err = st.getAPI("/hostdb/active?numhosts=1", &ah) 99 if err != nil { 100 t.Fatal(err) 101 } 102 if len(ah.Hosts) != 1 { 103 t.Fatal(len(ah.Hosts)) 104 } 105 err = st.getAPI("/hostdb/active?numhosts=2", &ah) 106 if err != nil { 107 t.Fatal(err) 108 } 109 if len(ah.Hosts) != 1 { 110 t.Fatal(len(ah.Hosts)) 111 } 112 } 113 114 // TestHostDBHostsAllHandler checks that announcing a host adds it to the list 115 // of all hosts. 116 func TestHostDBHostsAllHandler(t *testing.T) { 117 if testing.Short() { 118 t.SkipNow() 119 } 120 st, err := createServerTester(t.Name()) 121 if err != nil { 122 t.Fatal(err) 123 } 124 defer st.server.panicClose() 125 126 // Try the call before any hosts have been declared. 127 var ah HostdbAllGET 128 if err = st.getAPI("/hostdb/all", &ah); err != nil { 129 t.Fatal(err) 130 } 131 if len(ah.Hosts) != 0 { 132 t.Fatalf("expected 0 hosts, got %v", len(ah.Hosts)) 133 } 134 // Announce the host and try the call again. 135 if err = st.announceHost(); err != nil { 136 t.Fatal(err) 137 } 138 if err = st.getAPI("/hostdb/all", &ah); err != nil { 139 t.Fatal(err) 140 } 141 if len(ah.Hosts) != 1 { 142 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 143 } 144 } 145 146 // TestHostDBHostsHandler checks that the hosts handler is easily able to return 147 func TestHostDBHostsHandler(t *testing.T) { 148 if testing.Short() { 149 t.SkipNow() 150 } 151 st, err := createServerTester(t.Name()) 152 if err != nil { 153 t.Fatal(err) 154 } 155 defer st.server.panicClose() 156 157 // Announce the host and then get the list of hosts. 158 var ah HostdbActiveGET 159 if err = st.announceHost(); err != nil { 160 t.Fatal(err) 161 } 162 if err = st.getAPI("/hostdb/active", &ah); err != nil { 163 t.Fatal(err) 164 } 165 if len(ah.Hosts) != 1 { 166 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 167 } 168 169 // Parse the pubkey from the returned list of hosts and use it to form a 170 // request regarding the specific host. 171 keyString := ah.Hosts[0].PublicKey.String() 172 if keyString != ah.Hosts[0].PublicKeyString { 173 t.Error("actual key string and provided string do not match") 174 } 175 query := fmt.Sprintf("/hostdb/hosts/%s", ah.Hosts[0].PublicKeyString) 176 177 // Get the detailed info for the host. 178 var hh HostdbHostsGET 179 if err = st.getAPI(query, &hh); err != nil { 180 t.Fatal(err) 181 } 182 183 // Check that none of the values equal zero. A value of zero indicates that 184 // the field is no longer being tracked/reported, which could break 185 // compatibility for some apps. The default needs to be '1', not zero. 186 if hh.ScoreBreakdown.Score.IsZero() { 187 t.Error("Zero vaue score in score breakdown") 188 } 189 if hh.ScoreBreakdown.AgeAdjustment == 0 { 190 t.Error("Zero value in host score breakdown") 191 } 192 if hh.ScoreBreakdown.BurnAdjustment == 0 { 193 t.Error("Zero value in host score breakdown") 194 } 195 if hh.ScoreBreakdown.CollateralAdjustment == 0 { 196 t.Error("Zero value in host score breakdown") 197 } 198 if hh.ScoreBreakdown.PriceAdjustment == 0 { 199 t.Error("Zero value in host score breakdown") 200 } 201 if hh.ScoreBreakdown.StorageRemainingAdjustment == 0 { 202 t.Error("Zero value in host score breakdown") 203 } 204 if hh.ScoreBreakdown.UptimeAdjustment == 0 { 205 t.Error("Zero value in host score breakdown") 206 } 207 if hh.ScoreBreakdown.VersionAdjustment == 0 { 208 t.Error("Zero value in host score breakdown") 209 } 210 211 // Check that none of the supported values equals 1. A value of 1 indicates 212 // that the hostdb is not performing any penalties or rewards for that 213 // field, meaning that the calibration for that field is probably incorrect. 214 if hh.ScoreBreakdown.AgeAdjustment == 1 { 215 t.Error("One value in host score breakdown") 216 } 217 // Burn adjustment is not yet supported. 218 // 219 // if hh.ScoreBreakdown.BurnAdjustment == 1 { 220 // t.Error("One value in host score breakdown") 221 // } 222 if hh.ScoreBreakdown.CollateralAdjustment == 1 { 223 t.Error("One value in host score breakdown") 224 } 225 if hh.ScoreBreakdown.PriceAdjustment == 1 { 226 t.Error("One value in host score breakdown") 227 } 228 if hh.ScoreBreakdown.StorageRemainingAdjustment == 1 { 229 t.Error("One value in host score breakdown") 230 } 231 if hh.ScoreBreakdown.UptimeAdjustment == 1 { 232 t.Error("One value in host score breakdown") 233 } 234 if hh.ScoreBreakdown.VersionAdjustment == 1 { 235 t.Error("One value in host score breakdown") 236 } 237 } 238 239 // assembleHostHostname is assembleServerTester but you can specify which 240 // hostname the host should use. 241 func assembleHostPort(key crypto.TwofishKey, hostHostname string, testdir string) (*serverTester, error) { 242 // assembleServerTester should not get called during short tests, as it 243 // takes a long time to run. 244 if testing.Short() { 245 panic("assembleServerTester called during short tests") 246 } 247 248 // Create the modules. 249 g, err := gateway.New("localhost:0", false, filepath.Join(testdir, modules.GatewayDir)) 250 if err != nil { 251 return nil, err 252 } 253 cs, err := consensus.New(g, false, filepath.Join(testdir, modules.ConsensusDir)) 254 if err != nil { 255 return nil, err 256 } 257 tp, err := transactionpool.New(cs, g, filepath.Join(testdir, modules.TransactionPoolDir)) 258 if err != nil { 259 return nil, err 260 } 261 w, err := wallet.New(cs, tp, filepath.Join(testdir, modules.WalletDir)) 262 if err != nil { 263 return nil, err 264 } 265 encrypted, err := w.Encrypted() 266 if err != nil { 267 return nil, err 268 } 269 if !encrypted { 270 _, err = w.Encrypt(key) 271 if err != nil { 272 return nil, err 273 } 274 } 275 err = w.Unlock(key) 276 if err != nil { 277 return nil, err 278 } 279 m, err := miner.New(cs, tp, w, filepath.Join(testdir, modules.MinerDir)) 280 if err != nil { 281 return nil, err 282 } 283 h, err := host.New(cs, g, tp, w, hostHostname, filepath.Join(testdir, modules.HostDir)) 284 if err != nil { 285 return nil, err 286 } 287 r, err := renter.New(g, cs, w, tp, filepath.Join(testdir, modules.RenterDir)) 288 if err != nil { 289 return nil, err 290 } 291 srv, err := NewServer("localhost:0", "Sia-PrimeAgent", "", cs, nil, g, h, m, r, tp, w, nil, nil, nil) 292 if err != nil { 293 return nil, err 294 } 295 296 // Assemble the serverTester. 297 st := &serverTester{ 298 cs: cs, 299 gateway: g, 300 host: h, 301 miner: m, 302 renter: r, 303 tpool: tp, 304 wallet: w, 305 walletKey: key, 306 307 server: srv, 308 309 dir: testdir, 310 } 311 312 // TODO: A more reasonable way of listening for server errors. 313 go func() { 314 listenErr := srv.Serve() 315 if listenErr != nil { 316 panic(listenErr) 317 } 318 }() 319 return st, nil 320 } 321 322 // TestHostDBScanOnlineOffline checks that both online and offline hosts get 323 // scanned in the hostdb. 324 func TestHostDBScanOnlineOffline(t *testing.T) { 325 if testing.Short() || !build.VLONG { 326 t.SkipNow() 327 } 328 t.Parallel() 329 st, err := createServerTester(t.Name()) 330 if err != nil { 331 t.Fatal(err) 332 } 333 defer st.panicClose() 334 stHost, err := blankServerTester(t.Name() + "-Host") 335 if err != nil { 336 t.Fatal(err) 337 } 338 sts := []*serverTester{st, stHost} 339 err = fullyConnectNodes(sts) 340 if err != nil { 341 t.Fatal(err) 342 } 343 err = fundAllNodes(sts) 344 if err != nil { 345 t.Fatal(err) 346 } 347 348 // Announce the host. 349 err = stHost.acceptContracts() 350 if err != nil { 351 t.Fatal(err) 352 } 353 err = stHost.setHostStorage() 354 if err != nil { 355 t.Fatal(err) 356 } 357 err = stHost.announceHost() 358 if err != nil { 359 t.Fatal(err) 360 } 361 362 // Verify the host is visible. 363 var ah HostdbActiveGET 364 for i := 0; i < 50; i++ { 365 if err = st.getAPI("/hostdb/active", &ah); err != nil { 366 t.Fatal(err) 367 } 368 if len(ah.Hosts) == 1 { 369 break 370 } 371 time.Sleep(time.Millisecond * 100) 372 } 373 if len(ah.Hosts) != 1 { 374 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 375 } 376 hostAddr := ah.Hosts[0].NetAddress 377 378 // Close the host and wait for a scan to knock the host out of the hostdb. 379 err = stHost.server.Close() 380 if err != nil { 381 t.Fatal(err) 382 } 383 err = build.Retry(60, time.Second, func() error { 384 if err := st.getAPI("/hostdb/active", &ah); err != nil { 385 return err 386 } 387 if len(ah.Hosts) == 0 { 388 return nil 389 } 390 return errors.New("host still in hostdb") 391 }) 392 if err != nil { 393 t.Fatal(err) 394 } 395 396 // Reopen the host and wait for a scan to bring the host back into the 397 // hostdb. 398 stHost, err = assembleHostPort(stHost.walletKey, string(hostAddr), stHost.dir) 399 if err != nil { 400 t.Fatal(err) 401 } 402 defer stHost.panicClose() 403 sts[1] = stHost 404 err = fullyConnectNodes(sts) 405 if err != nil { 406 t.Fatal(err) 407 } 408 err = build.Retry(60, time.Second, func() error { 409 // Get the hostdb internals. 410 if err = st.getAPI("/hostdb/active", &ah); err != nil { 411 return err 412 } 413 if len(ah.Hosts) != 1 { 414 return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts)) 415 } 416 return nil 417 }) 418 if err != nil { 419 t.Fatal(err) 420 } 421 } 422 423 // TestHostDBAndRenterDownloadDynamicIPs checks that the hostdb and the renter are 424 // successfully able to follow a host that has changed IP addresses and then 425 // re-announced. 426 func TestHostDBAndRenterDownloadDynamicIPs(t *testing.T) { 427 if testing.Short() || !build.VLONG { 428 t.SkipNow() 429 } 430 t.Parallel() 431 st, err := createServerTester(t.Name()) 432 if err != nil { 433 t.Fatal(err) 434 } 435 defer st.panicClose() 436 stHost, err := blankServerTester(t.Name() + "-Host") 437 if err != nil { 438 t.Fatal(err) 439 } 440 sts := []*serverTester{st, stHost} 441 err = fullyConnectNodes(sts) 442 if err != nil { 443 t.Fatal(err) 444 } 445 err = fundAllNodes(sts) 446 if err != nil { 447 t.Fatal(err) 448 } 449 450 // Announce the host. 451 err = stHost.acceptContracts() 452 if err != nil { 453 t.Fatal(err) 454 } 455 err = stHost.setHostStorage() 456 if err != nil { 457 t.Fatal(err) 458 } 459 err = stHost.announceHost() 460 if err != nil { 461 t.Fatal(err) 462 } 463 464 // Pull the host's net address and pubkey from the hostdb. 465 var ah HostdbActiveGET 466 for i := 0; i < 50; i++ { 467 if err = st.getAPI("/hostdb/active", &ah); err != nil { 468 t.Fatal(err) 469 } 470 if len(ah.Hosts) == 1 { 471 break 472 } 473 time.Sleep(time.Millisecond * 100) 474 } 475 if len(ah.Hosts) != 1 { 476 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 477 } 478 addr := ah.Hosts[0].NetAddress 479 pks := ah.Hosts[0].PublicKeyString 480 481 // Upload a file to the host. 482 allowanceValues := url.Values{} 483 testFunds := "10000000000000000000000000000" // 10k SC 484 testPeriod := "10" 485 testPeriodInt := 10 486 allowanceValues.Set("funds", testFunds) 487 allowanceValues.Set("period", testPeriod) 488 err = st.stdPostAPI("/renter", allowanceValues) 489 if err != nil { 490 t.Fatal(err) 491 } 492 // Create a file. 493 path := filepath.Join(st.dir, "test.dat") 494 err = createRandFile(path, 1024) 495 if err != nil { 496 t.Fatal(err) 497 } 498 // Upload the file to the renter. 499 uploadValues := url.Values{} 500 uploadValues.Set("source", path) 501 err = st.stdPostAPI("/renter/upload/test", uploadValues) 502 if err != nil { 503 t.Fatal(err) 504 } 505 // Only one piece will be uploaded (10% at current redundancy). 506 var rf RenterFiles 507 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 508 st.getAPI("/renter/files", &rf) 509 time.Sleep(100 * time.Millisecond) 510 } 511 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 512 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 513 } 514 515 // Try downloading the file. 516 downpath := filepath.Join(st.dir, "testdown.dat") 517 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 518 if err != nil { 519 t.Fatal(err) 520 } 521 // Check that the download has the right contents. 522 orig, err := ioutil.ReadFile(path) 523 if err != nil { 524 t.Fatal(err) 525 } 526 download, err := ioutil.ReadFile(downpath) 527 if err != nil { 528 t.Fatal(err) 529 } 530 if !bytes.Equal(orig, download) { 531 t.Fatal("data mismatch when downloading a file") 532 } 533 534 // Mine a block before resetting the host, so that the host doesn't lose 535 // it's contracts when the transaction pool resets. 536 _, err = st.miner.AddBlock() 537 if err != nil { 538 t.Fatal(err) 539 } 540 _, err = synchronizationCheck(sts) 541 if err != nil { 542 t.Fatal(err) 543 } 544 // Give time for the upgrade to happen. 545 time.Sleep(time.Second * 3) 546 547 // Close and re-open the host. This should reset the host's address, as the 548 // host should now be on a new port. 549 err = stHost.server.Close() 550 if err != nil { 551 t.Fatal(err) 552 } 553 stHost, err = assembleServerTester(stHost.walletKey, stHost.dir) 554 if err != nil { 555 t.Fatal(err) 556 } 557 defer stHost.panicClose() 558 sts[1] = stHost 559 err = fullyConnectNodes(sts) 560 if err != nil { 561 t.Fatal(err) 562 } 563 err = stHost.announceHost() 564 if err != nil { 565 t.Fatal(err) 566 } 567 // Pull the host's net address and pubkey from the hostdb. 568 err = build.Retry(100, time.Millisecond*200, func() error { 569 // Get the hostdb internals. 570 if err = st.getAPI("/hostdb/active", &ah); err != nil { 571 return err 572 } 573 574 // Get the host's internals. 575 var hg HostGET 576 if err = stHost.getAPI("/host", &hg); err != nil { 577 return err 578 } 579 580 if len(ah.Hosts) != 1 { 581 return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts)) 582 } 583 if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress { 584 return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress) 585 } 586 return nil 587 }) 588 if err != nil { 589 t.Fatal(err) 590 } 591 if ah.Hosts[0].PublicKeyString != pks { 592 t.Error("public key appears to have changed for host") 593 } 594 if ah.Hosts[0].NetAddress == addr { 595 t.Log("NetAddress did not change for the new host") 596 } 597 598 // Try downloading the file. 599 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 600 if err != nil { 601 t.Fatal(err) 602 } 603 // Check that the download has the right contents. 604 download, err = ioutil.ReadFile(downpath) 605 if err != nil { 606 t.Fatal(err) 607 } 608 if !bytes.Equal(orig, download) { 609 t.Fatal("data mismatch when downloading a file") 610 } 611 612 // Mine enough blocks that multiple renew cylces happen. After the renewing 613 // happens, the file should still be downloadable. This is to check that the 614 // renewal doesn't throw things off. 615 for i := 0; i < testPeriodInt; i++ { 616 _, err = st.miner.AddBlock() 617 if err != nil { 618 t.Fatal(err) 619 } 620 _, err = synchronizationCheck(sts) 621 if err != nil { 622 t.Fatal(err) 623 } 624 } 625 err = build.Retry(100, time.Millisecond*100, func() error { 626 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 627 if err != nil { 628 return err 629 } 630 // Try downloading the file. 631 // Check that the download has the right contents. 632 download, err = ioutil.ReadFile(downpath) 633 if err != nil { 634 return err 635 } 636 if !bytes.Equal(orig, download) { 637 return errors.New("downloaded file does not equal the original") 638 } 639 return nil 640 }) 641 if err != nil { 642 t.Fatal(err) 643 } 644 } 645 646 // TestHostDBAndRenterUploadDynamicIPs checks that the hostdb and the renter are 647 // successfully able to follow a host that has changed IP addresses and then 648 // re-announced. 649 func TestHostDBAndRenterUploadDynamicIPs(t *testing.T) { 650 if testing.Short() || !build.VLONG { 651 t.SkipNow() 652 } 653 t.Parallel() 654 st, err := createServerTester(t.Name()) 655 if err != nil { 656 t.Fatal(err) 657 } 658 defer st.panicClose() 659 stHost, err := blankServerTester(t.Name() + "-Host") 660 if err != nil { 661 t.Fatal(err) 662 } 663 sts := []*serverTester{st, stHost} 664 err = fullyConnectNodes(sts) 665 if err != nil { 666 t.Fatal(err) 667 } 668 err = fundAllNodes(sts) 669 if err != nil { 670 t.Fatal(err) 671 } 672 673 // Announce the host. 674 err = stHost.acceptContracts() 675 if err != nil { 676 t.Fatal(err) 677 } 678 err = stHost.setHostStorage() 679 if err != nil { 680 t.Fatal(err) 681 } 682 err = stHost.announceHost() 683 if err != nil { 684 t.Fatal(err) 685 } 686 687 // Pull the host's net address and pubkey from the hostdb. 688 var ah HostdbActiveGET 689 for i := 0; i < 50; i++ { 690 if err = st.getAPI("/hostdb/active", &ah); err != nil { 691 t.Fatal(err) 692 } 693 if len(ah.Hosts) == 1 { 694 break 695 } 696 time.Sleep(time.Millisecond * 100) 697 } 698 if len(ah.Hosts) != 1 { 699 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 700 } 701 addr := ah.Hosts[0].NetAddress 702 pks := ah.Hosts[0].PublicKeyString 703 704 // Upload a file to the host. 705 allowanceValues := url.Values{} 706 testFunds := "10000000000000000000000000000" // 10k SC 707 testPeriod := "10" 708 testPeriodInt := 10 709 allowanceValues.Set("funds", testFunds) 710 allowanceValues.Set("period", testPeriod) 711 err = st.stdPostAPI("/renter", allowanceValues) 712 if err != nil { 713 t.Fatal(err) 714 } 715 // Create a file. 716 path := filepath.Join(st.dir, "test.dat") 717 err = createRandFile(path, 1024) 718 if err != nil { 719 t.Fatal(err) 720 } 721 // Upload the file to the renter. 722 uploadValues := url.Values{} 723 uploadValues.Set("source", path) 724 err = st.stdPostAPI("/renter/upload/test", uploadValues) 725 if err != nil { 726 t.Fatal(err) 727 } 728 // Only one piece will be uploaded (10% at current redundancy). 729 var rf RenterFiles 730 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 731 st.getAPI("/renter/files", &rf) 732 time.Sleep(100 * time.Millisecond) 733 } 734 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 735 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 736 } 737 738 // Mine a block before resetting the host, so that the host doesn't lose 739 // it's contracts when the transaction pool resets. 740 _, err = st.miner.AddBlock() 741 if err != nil { 742 t.Fatal(err) 743 } 744 _, err = synchronizationCheck(sts) 745 if err != nil { 746 t.Fatal(err) 747 } 748 // Give time for the upgrade to happen. 749 time.Sleep(time.Second * 3) 750 751 // Close and re-open the host. This should reset the host's address, as the 752 // host should now be on a new port. 753 err = stHost.server.Close() 754 if err != nil { 755 t.Fatal(err) 756 } 757 stHost, err = assembleServerTester(stHost.walletKey, stHost.dir) 758 if err != nil { 759 t.Fatal(err) 760 } 761 defer stHost.panicClose() 762 sts[1] = stHost 763 err = fullyConnectNodes(sts) 764 if err != nil { 765 t.Fatal(err) 766 } 767 err = stHost.announceHost() 768 if err != nil { 769 t.Fatal(err) 770 } 771 // Pull the host's net address and pubkey from the hostdb. 772 err = build.Retry(50, time.Millisecond*100, func() error { 773 // Get the hostdb internals. 774 if err = st.getAPI("/hostdb/active", &ah); err != nil { 775 return err 776 } 777 778 // Get the host's internals. 779 var hg HostGET 780 if err = stHost.getAPI("/host", &hg); err != nil { 781 return err 782 } 783 784 if len(ah.Hosts) != 1 { 785 return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts)) 786 } 787 if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress { 788 return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress) 789 } 790 return nil 791 }) 792 if err != nil { 793 t.Fatal(err) 794 } 795 if ah.Hosts[0].PublicKeyString != pks { 796 t.Error("public key appears to have changed for host") 797 } 798 if ah.Hosts[0].NetAddress == addr { 799 t.Log("NetAddress did not change for the new host") 800 } 801 802 // Try uploading a second file. 803 path2 := filepath.Join(st.dir, "test2.dat") 804 test2Size := modules.SectorSize*2 + 1 805 err = createRandFile(path2, int(test2Size)) 806 if err != nil { 807 t.Fatal(err) 808 } 809 uploadValues = url.Values{} 810 uploadValues.Set("source", path2) 811 err = st.stdPostAPI("/renter/upload/test2", uploadValues) 812 if err != nil { 813 t.Fatal(err) 814 } 815 // Only one piece will be uploaded (10% at current redundancy). 816 for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ { 817 st.getAPI("/renter/files", &rf) 818 time.Sleep(100 * time.Millisecond) 819 } 820 if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 { 821 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1]) 822 } 823 824 // Try downloading the second file. 825 downpath2 := filepath.Join(st.dir, "testdown2.dat") 826 err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2) 827 if err != nil { 828 t.Fatal(err) 829 } 830 // Check that the download has the right contents. 831 orig2, err := ioutil.ReadFile(path2) 832 if err != nil { 833 t.Fatal(err) 834 } 835 download2, err := ioutil.ReadFile(downpath2) 836 if err != nil { 837 t.Fatal(err) 838 } 839 if !bytes.Equal(orig2, download2) { 840 t.Fatal("data mismatch when downloading a file") 841 } 842 843 // Mine enough blocks that multiple renew cylces happen. After the renewing 844 // happens, the file should still be downloadable. This is to check that the 845 // renewal doesn't throw things off. 846 for i := 0; i < testPeriodInt; i++ { 847 _, err = st.miner.AddBlock() 848 if err != nil { 849 t.Fatal(err) 850 } 851 _, err = synchronizationCheck(sts) 852 if err != nil { 853 t.Fatal(err) 854 } 855 // Give time for the upgrade to happen. 856 time.Sleep(time.Second * 3) 857 } 858 859 // Try downloading the file. 860 downpath := filepath.Join(st.dir, "testdown.dat") 861 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 862 if err != nil { 863 t.Fatal(err) 864 } 865 // Check that the download has the right contents. 866 download, err := ioutil.ReadFile(downpath) 867 if err != nil { 868 t.Fatal(err) 869 } 870 orig, err := ioutil.ReadFile(path) 871 if err != nil { 872 t.Fatal(err) 873 } 874 if !bytes.Equal(orig, download) { 875 t.Fatal("data mismatch when downloading a file") 876 } 877 878 // Try downloading the second file. 879 err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2) 880 if err != nil { 881 t.Fatal(err) 882 } 883 // Check that the download has the right contents. 884 orig2, err = ioutil.ReadFile(path2) 885 if err != nil { 886 t.Fatal(err) 887 } 888 download2, err = ioutil.ReadFile(downpath2) 889 if err != nil { 890 t.Fatal(err) 891 } 892 if !bytes.Equal(orig2, download2) { 893 t.Fatal("data mismatch when downloading a file") 894 } 895 } 896 897 // TestHostDBAndRenterFormDynamicIPs checks that the hostdb and the renter are 898 // successfully able to follow a host that has changed IP addresses and then 899 // re-announced. 900 func TestHostDBAndRenterFormDynamicIPs(t *testing.T) { 901 if testing.Short() || !build.VLONG { 902 t.SkipNow() 903 } 904 t.Parallel() 905 st, err := createServerTester(t.Name()) 906 if err != nil { 907 t.Fatal(err) 908 } 909 defer st.panicClose() 910 stHost, err := blankServerTester(t.Name() + "-Host") 911 if err != nil { 912 t.Fatal(err) 913 } 914 sts := []*serverTester{st, stHost} 915 err = fullyConnectNodes(sts) 916 if err != nil { 917 t.Fatal(err) 918 } 919 err = fundAllNodes(sts) 920 if err != nil { 921 t.Fatal(err) 922 } 923 924 // Announce the host. 925 err = stHost.acceptContracts() 926 if err != nil { 927 t.Fatal(err) 928 } 929 err = stHost.setHostStorage() 930 if err != nil { 931 t.Fatal(err) 932 } 933 err = stHost.announceHost() 934 if err != nil { 935 t.Fatal(err) 936 } 937 938 // Pull the host's net address and pubkey from the hostdb. 939 var ah HostdbActiveGET 940 for i := 0; i < 50; i++ { 941 if err = st.getAPI("/hostdb/active", &ah); err != nil { 942 t.Fatal(err) 943 } 944 if len(ah.Hosts) == 1 { 945 break 946 } 947 time.Sleep(time.Millisecond * 100) 948 } 949 if len(ah.Hosts) != 1 { 950 t.Fatalf("expected 1 host, got %v", len(ah.Hosts)) 951 } 952 addr := ah.Hosts[0].NetAddress 953 pks := ah.Hosts[0].PublicKeyString 954 955 // Mine a block before resetting the host, so that the host doesn't lose 956 // it's contracts when the transaction pool resets. 957 _, err = st.miner.AddBlock() 958 if err != nil { 959 t.Fatal(err) 960 } 961 _, err = synchronizationCheck(sts) 962 if err != nil { 963 t.Fatal(err) 964 } 965 // Give time for the upgrade to happen. 966 time.Sleep(time.Second * 3) 967 968 // Close and re-open the host. This should reset the host's address, as the 969 // host should now be on a new port. 970 err = stHost.server.Close() 971 if err != nil { 972 t.Fatal(err) 973 } 974 stHost, err = assembleServerTester(stHost.walletKey, stHost.dir) 975 if err != nil { 976 t.Fatal(err) 977 } 978 defer stHost.panicClose() 979 sts[1] = stHost 980 err = fullyConnectNodes(sts) 981 if err != nil { 982 t.Fatal(err) 983 } 984 err = stHost.announceHost() 985 if err != nil { 986 t.Fatal(err) 987 } 988 // Pull the host's net address and pubkey from the hostdb. 989 err = build.Retry(50, time.Millisecond*100, func() error { 990 // Get the hostdb internals. 991 if err = st.getAPI("/hostdb/active", &ah); err != nil { 992 return err 993 } 994 995 // Get the host's internals. 996 var hg HostGET 997 if err = stHost.getAPI("/host", &hg); err != nil { 998 return err 999 } 1000 1001 if len(ah.Hosts) != 1 { 1002 return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts)) 1003 } 1004 if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress { 1005 return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress) 1006 } 1007 return nil 1008 }) 1009 if err != nil { 1010 t.Fatal(err) 1011 } 1012 if ah.Hosts[0].PublicKeyString != pks { 1013 t.Error("public key appears to have changed for host") 1014 } 1015 if ah.Hosts[0].NetAddress == addr { 1016 t.Log("NetAddress did not change for the new host") 1017 } 1018 1019 // Upload a file to the host. 1020 allowanceValues := url.Values{} 1021 testFunds := "10000000000000000000000000000" // 10k SC 1022 testPeriod := "10" 1023 testPeriodInt := 10 1024 allowanceValues.Set("funds", testFunds) 1025 allowanceValues.Set("period", testPeriod) 1026 err = st.stdPostAPI("/renter", allowanceValues) 1027 if err != nil { 1028 t.Fatal(err) 1029 } 1030 // Create a file. 1031 path := filepath.Join(st.dir, "test.dat") 1032 err = createRandFile(path, 1024) 1033 if err != nil { 1034 t.Fatal(err) 1035 } 1036 // Upload the file to the renter. 1037 uploadValues := url.Values{} 1038 uploadValues.Set("source", path) 1039 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1040 if err != nil { 1041 t.Fatal(err) 1042 } 1043 // Only one piece will be uploaded (10% at current redundancy). 1044 var rf RenterFiles 1045 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1046 st.getAPI("/renter/files", &rf) 1047 time.Sleep(100 * time.Millisecond) 1048 } 1049 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1050 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1051 } 1052 1053 // Try downloading the file. 1054 downpath := filepath.Join(st.dir, "testdown.dat") 1055 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1056 if err != nil { 1057 t.Fatal(err) 1058 } 1059 // Check that the download has the right contents. 1060 orig, err := ioutil.ReadFile(path) 1061 if err != nil { 1062 t.Fatal(err) 1063 } 1064 download, err := ioutil.ReadFile(downpath) 1065 if err != nil { 1066 t.Fatal(err) 1067 } 1068 if !bytes.Equal(orig, download) { 1069 t.Fatal("data mismatch when downloading a file") 1070 } 1071 1072 // Mine enough blocks that multiple renew cylces happen. After the renewing 1073 // happens, the file should still be downloadable. This is to check that the 1074 // renewal doesn't throw things off. 1075 for i := 0; i < testPeriodInt; i++ { 1076 _, err = st.miner.AddBlock() 1077 if err != nil { 1078 t.Fatal(err) 1079 } 1080 _, err = synchronizationCheck(sts) 1081 if err != nil { 1082 t.Fatal(err) 1083 } 1084 // Give time for the upgrade to happen. 1085 time.Sleep(time.Second * 3) 1086 } 1087 1088 // Try downloading the file. 1089 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1090 if err != nil { 1091 t.Fatal(err) 1092 } 1093 // Check that the download has the right contents. 1094 download, err = ioutil.ReadFile(downpath) 1095 if err != nil { 1096 t.Fatal(err) 1097 } 1098 if !bytes.Equal(orig, download) { 1099 t.Fatal("data mismatch when downloading a file") 1100 } 1101 } 1102 1103 // TestHostDBAndRenterRenewDynamicIPs checks that the hostdb and the renter are 1104 // successfully able to follow a host that has changed IP addresses and then 1105 // re-announced. 1106 func TestHostDBAndRenterRenewDynamicIPs(t *testing.T) { 1107 if testing.Short() || !build.VLONG { 1108 t.SkipNow() 1109 } 1110 t.Parallel() 1111 st, err := createServerTester(t.Name()) 1112 if err != nil { 1113 t.Fatal(err) 1114 } 1115 defer st.panicClose() 1116 stHost, err := blankServerTester(t.Name() + "-Host") 1117 if err != nil { 1118 t.Fatal(err) 1119 } 1120 sts := []*serverTester{st, stHost} 1121 err = fullyConnectNodes(sts) 1122 if err != nil { 1123 t.Fatal(err) 1124 } 1125 err = fundAllNodes(sts) 1126 if err != nil { 1127 t.Fatal(err) 1128 } 1129 1130 // Announce the host. 1131 err = stHost.acceptContracts() 1132 if err != nil { 1133 t.Fatal(err) 1134 } 1135 err = stHost.setHostStorage() 1136 if err != nil { 1137 t.Fatal(err) 1138 } 1139 err = stHost.announceHost() 1140 if err != nil { 1141 t.Fatal(err) 1142 } 1143 var ah HostdbActiveGET 1144 err = build.Retry(50, 100*time.Millisecond, func() error { 1145 if err := st.getAPI("/hostdb/active", &ah); err != nil { 1146 return err 1147 } 1148 if len(ah.Hosts) != 1 { 1149 return errors.New("host not found in hostdb") 1150 } 1151 return nil 1152 }) 1153 1154 // Upload a file to the host. 1155 allowanceValues := url.Values{} 1156 testFunds := "10000000000000000000000000000" // 10k SC 1157 testPeriod := "10" 1158 testPeriodInt := 10 1159 allowanceValues.Set("funds", testFunds) 1160 allowanceValues.Set("period", testPeriod) 1161 err = st.stdPostAPI("/renter", allowanceValues) 1162 if err != nil { 1163 t.Fatal(err) 1164 } 1165 // Create a file. 1166 path := filepath.Join(st.dir, "test.dat") 1167 err = createRandFile(path, 1024) 1168 if err != nil { 1169 t.Fatal(err) 1170 } 1171 // Upload the file to the renter. 1172 uploadValues := url.Values{} 1173 uploadValues.Set("source", path) 1174 err = st.stdPostAPI("/renter/upload/test", uploadValues) 1175 if err != nil { 1176 t.Fatal(err) 1177 } 1178 // Only one piece will be uploaded (10% at current redundancy). 1179 var rf RenterFiles 1180 for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ { 1181 st.getAPI("/renter/files", &rf) 1182 time.Sleep(100 * time.Millisecond) 1183 } 1184 if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 { 1185 t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0]) 1186 } 1187 1188 // Try downloading the file. 1189 downpath := filepath.Join(st.dir, "testdown.dat") 1190 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1191 if err != nil { 1192 t.Fatal(err) 1193 } 1194 // Check that the download has the right contents. 1195 orig, err := ioutil.ReadFile(path) 1196 if err != nil { 1197 t.Fatal(err) 1198 } 1199 download, err := ioutil.ReadFile(downpath) 1200 if err != nil { 1201 t.Fatal(err) 1202 } 1203 if !bytes.Equal(orig, download) { 1204 t.Fatal("data mismatch when downloading a file") 1205 } 1206 1207 // Mine a block before resetting the host, so that the host doesn't lose 1208 // it's contracts when the transaction pool resets. 1209 _, err = st.miner.AddBlock() 1210 if err != nil { 1211 t.Fatal(err) 1212 } 1213 _, err = synchronizationCheck(sts) 1214 if err != nil { 1215 t.Fatal(err) 1216 } 1217 // Give time for the upgrade to happen. 1218 time.Sleep(time.Second * 3) 1219 1220 // Close and re-open the host. This should reset the host's address, as the 1221 // host should now be on a new port. 1222 err = stHost.server.Close() 1223 if err != nil { 1224 t.Fatal(err) 1225 } 1226 stHost, err = assembleServerTester(stHost.walletKey, stHost.dir) 1227 if err != nil { 1228 t.Fatal(err) 1229 } 1230 defer stHost.panicClose() 1231 sts[1] = stHost 1232 err = fullyConnectNodes(sts) 1233 if err != nil { 1234 t.Fatal(err) 1235 } 1236 err = stHost.announceHost() 1237 if err != nil { 1238 t.Fatal(err) 1239 } 1240 err = waitForBlock(stHost.cs.CurrentBlock().ID(), st) 1241 if err != nil { 1242 t.Fatal() 1243 } 1244 // Pull the host's net address and pubkey from the hostdb. 1245 err = build.Retry(50, time.Millisecond*100, func() error { 1246 // Get the hostdb internals. 1247 if err = st.getAPI("/hostdb/active", &ah); err != nil { 1248 return err 1249 } 1250 1251 // Get the host's internals. 1252 var hg HostGET 1253 if err = stHost.getAPI("/host", &hg); err != nil { 1254 return err 1255 } 1256 1257 if len(ah.Hosts) != 1 { 1258 return fmt.Errorf("expected 1 host, got %v", len(ah.Hosts)) 1259 } 1260 if ah.Hosts[0].NetAddress != hg.ExternalSettings.NetAddress { 1261 return fmt.Errorf("hostdb net address doesn't match host net address: %v : %v", ah.Hosts[0].NetAddress, hg.ExternalSettings.NetAddress) 1262 } 1263 return nil 1264 }) 1265 if err != nil { 1266 t.Fatal(err) 1267 } 1268 1269 // Mine enough blocks that multiple renew cylces happen. After the renewing 1270 // happens, the file should still be downloadable. 1271 for i := 0; i < testPeriodInt; i++ { 1272 _, err = st.miner.AddBlock() 1273 if err != nil { 1274 t.Fatal(err) 1275 } 1276 _, err = synchronizationCheck(sts) 1277 if err != nil { 1278 t.Fatal(err) 1279 } 1280 // Give time for the upgrade to happen. 1281 time.Sleep(time.Second * 3) 1282 } 1283 1284 // Try downloading the file. 1285 err = st.stdGetAPI("/renter/download/test?destination=" + downpath) 1286 if err != nil { 1287 t.Fatal(err) 1288 } 1289 // Check that the download has the right contents. 1290 download, err = ioutil.ReadFile(downpath) 1291 if err != nil { 1292 t.Fatal(err) 1293 } 1294 if !bytes.Equal(orig, download) { 1295 t.Fatal("data mismatch when downloading a file") 1296 } 1297 }