github.com/ZuluSpl0it/Sia@v1.3.7/node/api/renterhost_test.go (about)

     1  package api
     2  
     3  // renterhost_test.go sets up larger integration tests between renters and
     4  // hosts, checking that the whole storage ecosystem is functioning cohesively.
     5  
     6  import (
     7  	"bytes"
     8  	"errors"
     9  	"fmt"
    10  	"io/ioutil"
    11  	"net/url"
    12  	"os"
    13  	"path/filepath"
    14  	"strconv"
    15  	"sync"
    16  	"testing"
    17  	"time"
    18  
    19  	"github.com/NebulousLabs/Sia/build"
    20  	"github.com/NebulousLabs/Sia/crypto"
    21  	"github.com/NebulousLabs/Sia/modules"
    22  	"github.com/NebulousLabs/Sia/types"
    23  )
    24  
    25  // TestHostObligationAcceptingContracts verifies that the host will complete
    26  // storage proofs and the renter will successfully download even if the host
    27  // has set accepting contracts to false.
    28  func TestHostObligationAcceptingContracts(t *testing.T) {
    29  	if testing.Short() {
    30  		t.SkipNow()
    31  	}
    32  	st, err := createServerTester(t.Name())
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  	defer st.server.Close()
    37  	err = st.setHostStorage()
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	err = st.acceptContracts()
    42  	if err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	err = st.announceHost()
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	allowanceValues := url.Values{}
    50  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
    51  	allowanceValues.Set("hosts", "1")
    52  	allowanceValues.Set("period", "10")
    53  	allowanceValues.Set("renewwindow", "5")
    54  	err = st.stdPostAPI("/renter", allowanceValues)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	// Block until the allowance has finished forming contracts.
    60  	err = build.Retry(50, time.Millisecond*250, func() error {
    61  		var rc RenterContracts
    62  		err = st.getAPI("/renter/contracts", &rc)
    63  		if err != nil {
    64  			return errors.New("couldn't get renter stats")
    65  		}
    66  		if len(rc.Contracts) != 1 {
    67  			return errors.New("no contracts")
    68  		}
    69  		return nil
    70  	})
    71  	if err != nil {
    72  		t.Fatal("allowance setting failed")
    73  	}
    74  
    75  	filesize := int(1024)
    76  	path := filepath.Join(st.dir, "test.dat")
    77  	err = createRandFile(path, filesize)
    78  	if err != nil {
    79  		t.Fatal(err)
    80  	}
    81  
    82  	// upload the file
    83  	uploadValues := url.Values{}
    84  	uploadValues.Set("source", path)
    85  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
    86  	if err != nil {
    87  		t.Fatal(err)
    88  	}
    89  
    90  	// redundancy should reach 1
    91  	var rf RenterFiles
    92  	err = build.Retry(120, time.Millisecond*250, func() error {
    93  		st.getAPI("/renter/files", &rf)
    94  		if len(rf.Files) >= 1 && rf.Files[0].Available {
    95  			return nil
    96  		}
    97  		return errors.New("file not uploaded")
    98  	})
    99  	if err != nil {
   100  		t.Fatal(err)
   101  	}
   102  
   103  	// Get contracts via API call
   104  	var cts ContractInfoGET
   105  	err = st.getAPI("/host/contracts", &cts)
   106  	if err != nil {
   107  		t.Fatal(err)
   108  	}
   109  
   110  	// There should be some contracts returned
   111  	if len(cts.Contracts) == 0 {
   112  		t.Fatal("No contracts returned from /host/contracts API call.")
   113  	}
   114  
   115  	// Check if the number of contracts are equal to the number of storage obligations
   116  	if len(cts.Contracts) != len(st.host.StorageObligations()) {
   117  		t.Fatal("Number of contracts returned by API call and host method don't match.")
   118  	}
   119  
   120  	// set acceptingcontracts = false, mine some blocks, verify we can download
   121  	settings := st.host.InternalSettings()
   122  	settings.AcceptingContracts = false
   123  	st.host.SetInternalSettings(settings)
   124  	for i := 0; i < 3; i++ {
   125  		_, err := st.miner.AddBlock()
   126  		if err != nil {
   127  			t.Fatal(err)
   128  		}
   129  		time.Sleep(time.Millisecond * 100)
   130  	}
   131  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
   132  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
   133  	if err != nil {
   134  		t.Fatal(err)
   135  	}
   136  
   137  	// mine blocks to cause the host to submit storage proofs to the blockchain.
   138  	for i := 0; i < 15; i++ {
   139  		_, err := st.miner.AddBlock()
   140  		if err != nil {
   141  			t.Fatal(err)
   142  		}
   143  		time.Sleep(time.Millisecond * 100)
   144  	}
   145  
   146  	// should have successful proofs
   147  	success := false
   148  	for _, so := range st.host.StorageObligations() {
   149  		if so.ProofConfirmed {
   150  			success = true
   151  			break
   152  		}
   153  	}
   154  	if !success {
   155  		t.Fatal("no successful storage proofs")
   156  	}
   157  }
   158  
   159  // TestHostAndRentVanilla sets up an integration test where a host and renter
   160  // do basic uploads and downloads.
   161  func TestHostAndRentVanilla(t *testing.T) {
   162  	if testing.Short() {
   163  		t.SkipNow()
   164  	}
   165  	t.Parallel()
   166  	st, err := createServerTester(t.Name())
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  	defer st.server.panicClose()
   171  
   172  	// Announce the host and start accepting contracts.
   173  	err = st.announceHost()
   174  	if err != nil {
   175  		t.Fatal(err)
   176  	}
   177  	err = st.setHostStorage()
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	err = st.acceptContracts()
   182  	if err != nil {
   183  		t.Fatal(err)
   184  	}
   185  
   186  	// Set an allowance for the renter, allowing a contract to be formed.
   187  	allowanceValues := url.Values{}
   188  	testFunds := "10000000000000000000000000000" // 10k SC
   189  	testPeriod := "20"
   190  	renewWindow := "10"
   191  	testPeriodInt := 20
   192  	allowanceValues.Set("funds", testFunds)
   193  	allowanceValues.Set("period", testPeriod)
   194  	allowanceValues.Set("renewwindow", renewWindow)
   195  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   196  	err = st.stdPostAPI("/renter", allowanceValues)
   197  	if err != nil {
   198  		t.Fatal(err)
   199  	}
   200  
   201  	// Block until the allowance has finished forming contracts.
   202  	err = build.Retry(50, time.Millisecond*250, func() error {
   203  		var rc RenterContracts
   204  		err = st.getAPI("/renter/contracts", &rc)
   205  		if err != nil {
   206  			return errors.New("couldn't get renter stats")
   207  		}
   208  		if len(rc.Contracts) != 1 {
   209  			return errors.New("no contracts")
   210  		}
   211  		return nil
   212  	})
   213  	if err != nil {
   214  		t.Fatal("allowance setting failed")
   215  	}
   216  
   217  	// Check the host, who should now be reporting file contracts.
   218  	var cts ContractInfoGET
   219  	err = st.getAPI("/host/contracts", &cts)
   220  	if err != nil {
   221  		t.Fatal(err)
   222  	}
   223  
   224  	if len(cts.Contracts) != 1 {
   225  		t.Error("Host has wrong number of obligations:", len(cts.Contracts))
   226  	}
   227  	// Check if the obligation status is unresolved
   228  	if cts.Contracts[0].ObligationStatus != "obligationUnresolved" {
   229  		t.Error("Wrong obligation status for new contract:", cts.Contracts[0].ObligationStatus)
   230  	}
   231  	// Check if there are no sector roots on a new contract
   232  	if cts.Contracts[0].SectorRootsCount != 0 {
   233  		t.Error("Wrong number of sector roots for new contract:", cts.Contracts[0].SectorRootsCount)
   234  	}
   235  	// Check if there is locked collateral
   236  	if cts.Contracts[0].LockedCollateral.IsZero() {
   237  		t.Error("No locked collateral in contract.")
   238  	}
   239  	// Check if risked collateral is not equal to zero
   240  	if !cts.Contracts[0].RiskedCollateral.IsZero() {
   241  		t.Error("Risked collateral not zero in new contract.")
   242  	}
   243  	// Check if all potential revenues are zero
   244  	if !(cts.Contracts[0].PotentialDownloadRevenue.IsZero() && cts.Contracts[0].PotentialUploadRevenue.IsZero() && cts.Contracts[0].PotentialStorageRevenue.IsZero()) {
   245  		t.Error("Potential values not zero in new contract.")
   246  	}
   247  
   248  	// Create a file.
   249  	path := filepath.Join(st.dir, "test.dat")
   250  	err = createRandFile(path, 1024)
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  
   255  	// Upload the file to the renter.
   256  	uploadValues := url.Values{}
   257  	uploadValues.Set("source", path)
   258  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	// Only one piece will be uploaded (10% at current redundancy).
   263  	var rf RenterFiles
   264  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   265  		st.getAPI("/renter/files", &rf)
   266  		time.Sleep(100 * time.Millisecond)
   267  	}
   268  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   269  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   270  	}
   271  
   272  	// On a second connection, upload another file.
   273  	path2 := filepath.Join(st.dir, "test2.dat")
   274  	test2Size := modules.SectorSize*2 + 1
   275  	err = createRandFile(path2, int(test2Size))
   276  	if err != nil {
   277  		t.Fatal(err)
   278  	}
   279  	uploadValues = url.Values{}
   280  	uploadValues.Set("source", path2)
   281  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
   282  	if err != nil {
   283  		t.Fatal(err)
   284  	}
   285  	// Only one piece will be uploaded (10% at current redundancy).
   286  	for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ {
   287  		st.getAPI("/renter/files", &rf)
   288  		time.Sleep(100 * time.Millisecond)
   289  	}
   290  	if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 {
   291  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1])
   292  	}
   293  
   294  	// Try downloading the first file.
   295  	downpath := filepath.Join(st.dir, "testdown.dat")
   296  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   297  	if err != nil {
   298  		t.Fatal(err)
   299  	}
   300  	// Check that the download has the right contents.
   301  	orig, err := ioutil.ReadFile(path)
   302  	if err != nil {
   303  		t.Fatal(err)
   304  	}
   305  	download, err := ioutil.ReadFile(downpath)
   306  	if err != nil {
   307  		t.Fatal(err)
   308  	}
   309  	if bytes.Compare(orig, download) != 0 {
   310  		t.Fatal("data mismatch when downloading a file")
   311  	}
   312  
   313  	// The renter's downloads queue should have 1 entry now.
   314  	var queue RenterDownloadQueue
   315  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   316  		t.Fatal(err)
   317  	}
   318  	if len(queue.Downloads) != 1 {
   319  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   320  	}
   321  
   322  	// Try downloading the second file.
   323  	downpath2 := filepath.Join(st.dir, "testdown2.dat")
   324  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2)
   325  	if err != nil {
   326  		t.Fatal(err)
   327  	}
   328  	// Check that the download has the right contents.
   329  	orig2, err := ioutil.ReadFile(path2)
   330  	if err != nil {
   331  		t.Fatal(err)
   332  	}
   333  	download2, err := ioutil.ReadFile(downpath2)
   334  	if err != nil {
   335  		t.Fatal(err)
   336  	}
   337  	if bytes.Compare(orig2, download2) != 0 {
   338  		t.Fatal("data mismatch when downloading a file")
   339  	}
   340  
   341  	// The renter's downloads queue should have 2 entries now.
   342  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   343  		t.Fatal(err)
   344  	}
   345  	if len(queue.Downloads) != 2 {
   346  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   347  	}
   348  
   349  	// Mine two blocks, which should cause the host to submit the storage
   350  	// obligation to the blockchain.
   351  	for i := 0; i < 2; i++ {
   352  		_, err := st.miner.AddBlock()
   353  		if err != nil {
   354  			t.Fatal(err)
   355  		}
   356  		time.Sleep(time.Millisecond * 200)
   357  	}
   358  
   359  	// Check that the host was able to get the file contract confirmed on the
   360  	// blockchain.
   361  	cts = ContractInfoGET{}
   362  	err = st.getAPI("/host/contracts", &cts)
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  
   367  	if len(cts.Contracts) != 1 {
   368  		t.Error("Host has wrong number of obligations:", len(cts.Contracts))
   369  	}
   370  	if !cts.Contracts[0].OriginConfirmed {
   371  		t.Error("Host has not seen the file contract on the blockchain.")
   372  	}
   373  	// Check if there are sector roots
   374  	if cts.Contracts[0].SectorRootsCount == 0 {
   375  		t.Error("Sector roots count is zero for used obligation.")
   376  	}
   377  	// Check if risked collateral is not equal to zero
   378  	if cts.Contracts[0].RiskedCollateral.IsZero() {
   379  		t.Error("Risked collateral is zero for used obligation.")
   380  	}
   381  	// There should be some potential revenues in this contract
   382  	if cts.Contracts[0].PotentialDownloadRevenue.IsZero() || cts.Contracts[0].PotentialUploadRevenue.IsZero() || cts.Contracts[0].PotentialStorageRevenue.IsZero() {
   383  		t.Error("Potential revenue value is zero for used obligation.")
   384  	}
   385  
   386  	// Mine blocks until the host should have submitted a storage proof.
   387  	for i := 0; i <= testPeriodInt+5; i++ {
   388  		_, err := st.miner.AddBlock()
   389  		if err != nil {
   390  			t.Fatal(err)
   391  		}
   392  		time.Sleep(time.Millisecond * 200)
   393  	}
   394  
   395  	cts = ContractInfoGET{}
   396  	err = st.getAPI("/host/contracts", &cts)
   397  	if err != nil {
   398  		t.Fatal(err)
   399  	}
   400  
   401  	success := false
   402  	for _, contract := range cts.Contracts {
   403  		if contract.ProofConfirmed {
   404  			// Sector roots should be removed from storage obligation
   405  			if contract.SectorRootsCount > 0 {
   406  				t.Error("There are sector roots on completed storage obligation.")
   407  			}
   408  			success = true
   409  			break
   410  		}
   411  	}
   412  	if !success {
   413  		t.Error("does not seem like the host has submitted a storage proof successfully to the network")
   414  	}
   415  }
   416  
   417  // TestHostAndRentMultiHost sets up an integration test where three hosts and a
   418  // renter do basic (parallel) uploads and downloads.
   419  func TestHostAndRentMultiHost(t *testing.T) {
   420  	if testing.Short() || !build.VLONG {
   421  		t.SkipNow()
   422  	}
   423  	t.Parallel()
   424  	st, err := createServerTester(t.Name())
   425  	if err != nil {
   426  		t.Fatal(err)
   427  	}
   428  	defer st.server.panicClose()
   429  	stH1, err := blankServerTester(t.Name() + " - Host 2")
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  	defer stH1.server.panicClose()
   434  	stH2, err := blankServerTester(t.Name() + " - Host 3")
   435  	if err != nil {
   436  		t.Fatal(err)
   437  	}
   438  	defer stH2.server.panicClose()
   439  	testGroup := []*serverTester{st, stH1, stH2}
   440  
   441  	// Connect the testers to eachother so that they are all on the same
   442  	// blockchain.
   443  	err = fullyConnectNodes(testGroup)
   444  	if err != nil {
   445  		t.Fatal(err)
   446  	}
   447  
   448  	// Make sure that every wallet has money in it.
   449  	err = fundAllNodes(testGroup)
   450  	if err != nil {
   451  		t.Fatal(err)
   452  	}
   453  
   454  	// Add storage to every host.
   455  	err = addStorageToAllHosts(testGroup)
   456  	if err != nil {
   457  		t.Fatal(err)
   458  	}
   459  
   460  	// Announce every host.
   461  	err = announceAllHosts(testGroup)
   462  	if err != nil {
   463  		t.Fatal(err)
   464  	}
   465  
   466  	// Set an allowance with three hosts.
   467  	allowanceValues := url.Values{}
   468  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
   469  	allowanceValues.Set("hosts", "3")
   470  	allowanceValues.Set("period", "10")
   471  	allowanceValues.Set("renewwindow", "2")
   472  	err = st.stdPostAPI("/renter", allowanceValues)
   473  	if err != nil {
   474  		t.Fatal(err)
   475  	}
   476  
   477  	// Create a file to upload.
   478  	filesize := int(45678)
   479  	path := filepath.Join(st.dir, "test.dat")
   480  	err = createRandFile(path, filesize)
   481  	if err != nil {
   482  		t.Fatal(err)
   483  	}
   484  
   485  	// Upload a file with 2-of-6 redundancy.
   486  	uploadValues := url.Values{}
   487  	uploadValues.Set("source", path)
   488  	uploadValues.Set("datapieces", "2")
   489  	uploadValues.Set("paritypieces", "4")
   490  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  	// Three pieces should get uploaded.
   495  	var rf RenterFiles
   496  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50); i++ {
   497  		st.getAPI("/renter/files", &rf)
   498  		time.Sleep(100 * time.Millisecond)
   499  	}
   500  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50 {
   501  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   502  	}
   503  
   504  	// Try downloading the file.
   505  	downpath := filepath.Join(st.dir, "testdown.dat")
   506  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  	// Check that the download has the right contents.
   511  	orig, err := ioutil.ReadFile(path)
   512  	if err != nil {
   513  		t.Fatal(err)
   514  	}
   515  	download, err := ioutil.ReadFile(downpath)
   516  	if err != nil {
   517  		t.Fatal(err)
   518  	}
   519  	if bytes.Compare(orig, download) != 0 {
   520  		t.Fatal("data mismatch when downloading a file")
   521  	}
   522  
   523  	// The renter's downloads queue should have 1 entry now.
   524  	var queue RenterDownloadQueue
   525  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   526  		t.Fatal(err)
   527  	}
   528  	if len(queue.Downloads) != 1 {
   529  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   530  	}
   531  }
   532  
   533  // TestHostAndRentManyFiles sets up an integration test where a single renter
   534  // is uploading many files to the network.
   535  func TestHostAndRentManyFiles(t *testing.T) {
   536  	if testing.Short() || !build.VLONG {
   537  		t.SkipNow()
   538  	}
   539  	t.Parallel()
   540  	st, err := createServerTester(t.Name())
   541  	if err != nil {
   542  		t.Fatal(err)
   543  	}
   544  	defer st.server.panicClose()
   545  	stH1, err := blankServerTester(t.Name() + " - Host 2")
   546  	if err != nil {
   547  		t.Fatal(err)
   548  	}
   549  	defer stH1.server.panicClose()
   550  	stH2, err := blankServerTester(t.Name() + " - Host 3")
   551  	if err != nil {
   552  		t.Fatal(err)
   553  	}
   554  	defer stH2.server.panicClose()
   555  	stH3, err := blankServerTester(t.Name() + " - Host 4")
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  	defer stH3.server.panicClose()
   560  	testGroup := []*serverTester{st, stH1, stH2, stH3}
   561  
   562  	// Connect the testers to eachother so that they are all on the same
   563  	// blockchain.
   564  	err = fullyConnectNodes(testGroup)
   565  	if err != nil {
   566  		t.Fatal(err)
   567  	}
   568  
   569  	// Make sure that every wallet has money in it.
   570  	err = fundAllNodes(testGroup)
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  
   575  	// Add storage to every host.
   576  	err = addStorageToAllHosts(testGroup)
   577  	if err != nil {
   578  		t.Fatal(err)
   579  	}
   580  
   581  	// Announce every host.
   582  	err = announceAllHosts(testGroup)
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  
   587  	// Set an allowance with four hosts.
   588  	allowanceValues := url.Values{}
   589  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
   590  	allowanceValues.Set("hosts", "4")
   591  	allowanceValues.Set("period", "5")
   592  	allowanceValues.Set("renewwindow", "2")
   593  	err = st.stdPostAPI("/renter", allowanceValues)
   594  	if err != nil {
   595  		t.Fatal(err)
   596  	}
   597  
   598  	// Create 3 files to upload at the same time.
   599  	filesize1 := int(12347)
   600  	filesize2 := int(22343)
   601  	filesize3 := int(32349)
   602  	path1 := filepath.Join(st.dir, "test1.dat")
   603  	path2 := filepath.Join(st.dir, "test2.dat")
   604  	path3 := filepath.Join(st.dir, "test3.dat")
   605  	err = createRandFile(path1, filesize1)
   606  	if err != nil {
   607  		t.Fatal(err)
   608  	}
   609  	err = createRandFile(path2, filesize2)
   610  	if err != nil {
   611  		t.Fatal(err)
   612  	}
   613  	err = createRandFile(path3, filesize3)
   614  	if err != nil {
   615  		t.Fatal(err)
   616  	}
   617  
   618  	// Concurrently upload a file with 1-of-4 redundancy, 2-of-4 redundancy,
   619  	// and 3-of-4 redundancy.
   620  	var wg sync.WaitGroup
   621  	wg.Add(3)
   622  	go func() {
   623  		defer wg.Done()
   624  		uploadValues := url.Values{}
   625  		uploadValues.Set("source", path1)
   626  		uploadValues.Set("datapieces", "1")
   627  		uploadValues.Set("paritypieces", "3")
   628  		err := st.stdPostAPI("/renter/upload/test1", uploadValues)
   629  		if err != nil {
   630  			t.Error(err)
   631  		}
   632  	}()
   633  	go func() {
   634  		defer wg.Done()
   635  		uploadValues := url.Values{}
   636  		uploadValues.Set("source", path2)
   637  		uploadValues.Set("datapieces", "2")
   638  		uploadValues.Set("paritypieces", "2")
   639  		err := st.stdPostAPI("/renter/upload/test2", uploadValues)
   640  		if err != nil {
   641  			t.Error(err)
   642  		}
   643  	}()
   644  	go func() {
   645  		defer wg.Done()
   646  		uploadValues := url.Values{}
   647  		uploadValues.Set("source", path3)
   648  		uploadValues.Set("datapieces", "3")
   649  		uploadValues.Set("paritypieces", "1")
   650  		err := st.stdPostAPI("/renter/upload/test3", uploadValues)
   651  		if err != nil {
   652  			t.Error(err)
   653  		}
   654  	}()
   655  
   656  	// Block until the upload call is complete for all three files.
   657  	wg.Wait()
   658  
   659  	// Block until all files hit 100% uploaded.
   660  	var rf RenterFiles
   661  	for i := 0; i < 200 && (len(rf.Files) != 3 || rf.Files[0].UploadProgress < 100 || rf.Files[1].UploadProgress < 100 || rf.Files[2].UploadProgress < 100); i++ {
   662  		st.getAPI("/renter/files", &rf)
   663  		time.Sleep(500 * time.Millisecond)
   664  	}
   665  	if len(rf.Files) != 3 || rf.Files[0].UploadProgress < 100 || rf.Files[1].UploadProgress < 100 || rf.Files[2].UploadProgress < 100 {
   666  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1], rf.Files[2])
   667  	}
   668  
   669  	// Download all three files in parallel.
   670  	wg.Add(3)
   671  	go func() {
   672  		defer wg.Done()
   673  		downpath := filepath.Join(st.dir, "testdown1.dat")
   674  		err := st.stdGetAPI("/renter/download/test1?destination=" + downpath)
   675  		if err != nil {
   676  			t.Error(err)
   677  		}
   678  		// Check that the download has the right contents.
   679  		orig, err := ioutil.ReadFile(path1)
   680  		if err != nil {
   681  			t.Error(err)
   682  		}
   683  		download, err := ioutil.ReadFile(downpath)
   684  		if err != nil {
   685  			t.Error(err)
   686  		}
   687  		if bytes.Compare(orig, download) != 0 {
   688  			t.Error("data mismatch when downloading a file")
   689  		}
   690  	}()
   691  	go func() {
   692  		defer wg.Done()
   693  		downpath := filepath.Join(st.dir, "testdown2.dat")
   694  		err := st.stdGetAPI("/renter/download/test2?destination=" + downpath)
   695  		if err != nil {
   696  			t.Error(err)
   697  		}
   698  		// Check that the download has the right contents.
   699  		orig, err := ioutil.ReadFile(path2)
   700  		if err != nil {
   701  			t.Error(err)
   702  		}
   703  		download, err := ioutil.ReadFile(downpath)
   704  		if err != nil {
   705  			t.Error(err)
   706  		}
   707  		if bytes.Compare(orig, download) != 0 {
   708  			t.Error("data mismatch when downloading a file")
   709  		}
   710  	}()
   711  	go func() {
   712  		defer wg.Done()
   713  		downpath := filepath.Join(st.dir, "testdown3.dat")
   714  		err := st.stdGetAPI("/renter/download/test3?destination=" + downpath)
   715  		if err != nil {
   716  			t.Error(err)
   717  		}
   718  		// Check that the download has the right contents.
   719  		orig, err := ioutil.ReadFile(path3)
   720  		if err != nil {
   721  			t.Error(err)
   722  		}
   723  		download, err := ioutil.ReadFile(downpath)
   724  		if err != nil {
   725  			t.Error(err)
   726  		}
   727  		if bytes.Compare(orig, download) != 0 {
   728  			t.Error("data mismatch when downloading a file")
   729  		}
   730  	}()
   731  	wg.Wait()
   732  
   733  	// The renter's downloads queue should have 3 entries now.
   734  	var queue RenterDownloadQueue
   735  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   736  		t.Fatal(err)
   737  	}
   738  	if len(queue.Downloads) != 3 {
   739  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   740  	}
   741  }
   742  
   743  // TestRenterUploadDownload tests that downloading and uploading in parallel
   744  // does not result in failures or stalling.
   745  func TestRenterUploadDownload(t *testing.T) {
   746  	if testing.Short() {
   747  		t.SkipNow()
   748  	}
   749  	st, err := createServerTester(t.Name())
   750  	if err != nil {
   751  		t.Fatal(err)
   752  	}
   753  	defer st.server.panicClose()
   754  
   755  	// Announce the host and start accepting contracts.
   756  	err = st.announceHost()
   757  	if err != nil {
   758  		t.Fatal(err)
   759  	}
   760  	err = st.acceptContracts()
   761  	if err != nil {
   762  		t.Fatal(err)
   763  	}
   764  	err = st.setHostStorage()
   765  	if err != nil {
   766  		t.Fatal(err)
   767  	}
   768  
   769  	// Set an allowance for the renter, allowing a contract to be formed.
   770  	allowanceValues := url.Values{}
   771  	testFunds := "10000000000000000000000000000" // 10k SC
   772  	testPeriod := "10"
   773  	allowanceValues.Set("funds", testFunds)
   774  	allowanceValues.Set("period", testPeriod)
   775  	allowanceValues.Set("renewwindow", testRenewWindow)
   776  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   777  	err = st.stdPostAPI("/renter", allowanceValues)
   778  	if err != nil {
   779  		t.Fatal(err)
   780  	}
   781  
   782  	// Block until the allowance has finished forming contracts.
   783  	err = build.Retry(50, time.Millisecond*250, func() error {
   784  		var rc RenterContracts
   785  		err = st.getAPI("/renter/contracts", &rc)
   786  		if err != nil {
   787  			return errors.New("couldn't get renter stats")
   788  		}
   789  		if len(rc.Contracts) != 1 {
   790  			return errors.New("no contracts")
   791  		}
   792  		return nil
   793  	})
   794  	if err != nil {
   795  		t.Fatal("allowance setting failed")
   796  	}
   797  
   798  	// Check financial metrics; coins should have been spent on contracts
   799  	var rg RenterGET
   800  	err = st.getAPI("/renter", &rg)
   801  	if err != nil {
   802  		t.Fatal(err)
   803  	}
   804  	spent := rg.Settings.Allowance.Funds.Sub(rg.FinancialMetrics.Unspent)
   805  	if spent.IsZero() {
   806  		t.Fatal("financial metrics do not reflect contract spending")
   807  	}
   808  
   809  	// Create a file.
   810  	path := filepath.Join(st.dir, "test.dat")
   811  	err = createRandFile(path, 1024)
   812  	if err != nil {
   813  		t.Fatal(err)
   814  	}
   815  
   816  	// Upload to host.
   817  	uploadValues := url.Values{}
   818  	uploadValues.Set("source", path)
   819  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   820  	if err != nil {
   821  		t.Fatal(err)
   822  	}
   823  	// Only one piece will be uploaded (10% at current redundancy).
   824  	var rf RenterFiles
   825  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   826  		st.getAPI("/renter/files", &rf)
   827  		time.Sleep(100 * time.Millisecond)
   828  	}
   829  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   830  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   831  	}
   832  
   833  	// In parallel, upload another file and download the first file.
   834  	path2 := filepath.Join(st.dir, "test2.dat")
   835  	test2Size := modules.SectorSize*2 + 1
   836  	err = createRandFile(path2, int(test2Size))
   837  	if err != nil {
   838  		t.Fatal(err)
   839  	}
   840  	uploadValues = url.Values{}
   841  	uploadValues.Set("source", path2)
   842  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
   843  	if err != nil {
   844  		t.Fatal(err)
   845  	}
   846  	downpath := filepath.Join(st.dir, "testdown.dat")
   847  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   848  	if err != nil {
   849  		t.Fatal(err)
   850  	}
   851  	// Check that the download has the right contents.
   852  	orig, err := ioutil.ReadFile(path)
   853  	if err != nil {
   854  		t.Fatal(err)
   855  	}
   856  	download, err := ioutil.ReadFile(downpath)
   857  	if err != nil {
   858  		t.Fatal(err)
   859  	}
   860  	if bytes.Compare(orig, download) != 0 {
   861  		t.Fatal("data mismatch when downloading a file")
   862  	}
   863  
   864  	// Wait for upload to complete.
   865  	for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ {
   866  		st.getAPI("/renter/files", &rf)
   867  		time.Sleep(100 * time.Millisecond)
   868  	}
   869  	if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 {
   870  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1])
   871  	}
   872  
   873  	// Check financial metrics; funds should have been spent on uploads/downloads
   874  	err = st.getAPI("/renter", &rg)
   875  	if err != nil {
   876  		t.Fatal(err)
   877  	}
   878  	fm := rg.FinancialMetrics
   879  	newSpent := rg.Settings.Allowance.Funds.Sub(fm.Unspent)
   880  	// all new spending should be reflected in upload/download/storage spending
   881  	diff := fm.UploadSpending.Add(fm.DownloadSpending).Add(fm.StorageSpending)
   882  	if !diff.Equals(newSpent.Sub(spent)) {
   883  		t.Fatal("all new spending should be reflected in metrics:", diff, newSpent.Sub(spent))
   884  	}
   885  }
   886  
   887  // TestRenterParallelDelete tests that uploading and deleting parallel does not
   888  // result in failures or stalling.
   889  func TestRenterParallelDelete(t *testing.T) {
   890  	if testing.Short() {
   891  		t.SkipNow()
   892  	}
   893  	st, err := createServerTester(t.Name())
   894  	if err != nil {
   895  		t.Fatal(err)
   896  	}
   897  	defer st.server.panicClose()
   898  
   899  	// Announce the host and start accepting contracts.
   900  	err = st.announceHost()
   901  	if err != nil {
   902  		t.Fatal(err)
   903  	}
   904  	err = st.acceptContracts()
   905  	if err != nil {
   906  		t.Fatal(err)
   907  	}
   908  	err = st.setHostStorage()
   909  	if err != nil {
   910  		t.Fatal(err)
   911  	}
   912  
   913  	// Set an allowance for the renter, allowing a contract to be formed.
   914  	allowanceValues := url.Values{}
   915  	testFunds := "10000000000000000000000000000" // 10k SC
   916  	testPeriod := "10"
   917  	allowanceValues.Set("funds", testFunds)
   918  	allowanceValues.Set("period", testPeriod)
   919  	allowanceValues.Set("renewwindow", testRenewWindow)
   920  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   921  	err = st.stdPostAPI("/renter", allowanceValues)
   922  	if err != nil {
   923  		t.Fatal(err)
   924  	}
   925  
   926  	// Create two files.
   927  	path := filepath.Join(st.dir, "test.dat")
   928  	err = createRandFile(path, 1024)
   929  	if err != nil {
   930  		t.Fatal(err)
   931  	}
   932  	path2 := filepath.Join(st.dir, "test2.dat")
   933  	err = createRandFile(path2, 1024)
   934  	if err != nil {
   935  		t.Fatal(err)
   936  	}
   937  
   938  	// Upload the first file to host.
   939  	uploadValues := url.Values{}
   940  	uploadValues.Set("source", path)
   941  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   942  	if err != nil {
   943  		t.Fatal(err)
   944  	}
   945  	// Wait for the first file to be registered in the renter.
   946  	var rf RenterFiles
   947  	for i := 0; i < 200 && len(rf.Files) != 1; i++ {
   948  		st.getAPI("/renter/files", &rf)
   949  		time.Sleep(100 * time.Millisecond)
   950  	}
   951  	if len(rf.Files) != 1 {
   952  		t.Fatal("file is not being registered:", rf.Files)
   953  	}
   954  
   955  	// In parallel, start uploading the other file, and delete the first file.
   956  	uploadValues = url.Values{}
   957  	uploadValues.Set("source", path2)
   958  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
   959  	if err != nil {
   960  		t.Fatal(err)
   961  	}
   962  
   963  	err = st.stdPostAPI("/renter/delete/test", url.Values{})
   964  	if err != nil {
   965  		t.Fatal(err)
   966  	}
   967  	// Only the second file should be present
   968  	st.getAPI("/renter/files", &rf)
   969  	if len(rf.Files) != 1 || rf.Files[0].SiaPath != "test2" {
   970  		t.Fatal("file was not deleted properly:", rf.Files)
   971  	}
   972  
   973  	// Wait for the second upload to complete.
   974  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   975  		st.getAPI("/renter/files", &rf)
   976  		time.Sleep(100 * time.Millisecond)
   977  	}
   978  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   979  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files)
   980  	}
   981  
   982  	// In parallel, download and delete the second file.
   983  	go st.stdPostAPI("/renter/delete/test2", url.Values{})
   984  	time.Sleep(100 * time.Millisecond)
   985  	downpath := filepath.Join(st.dir, "testdown.dat")
   986  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath)
   987  	if err == nil {
   988  		t.Fatal("download should fail after delete")
   989  	}
   990  
   991  	// No files should be present
   992  	st.getAPI("/renter/files", &rf)
   993  	if len(rf.Files) != 0 {
   994  		t.Fatal("file was not deleted properly:", rf.Files)
   995  	}
   996  }
   997  
   998  // TestRenterRenew sets up an integration test where a renter renews a
   999  // contract with a host.
  1000  func TestRenterRenew(t *testing.T) {
  1001  	if testing.Short() {
  1002  		t.SkipNow()
  1003  	}
  1004  	st, err := createServerTester(t.Name())
  1005  	if err != nil {
  1006  		t.Fatal(err)
  1007  	}
  1008  	defer st.server.panicClose()
  1009  
  1010  	// Announce the host and start accepting contracts.
  1011  	err = st.announceHost()
  1012  	if err != nil {
  1013  		t.Fatal(err)
  1014  	}
  1015  	err = st.acceptContracts()
  1016  	if err != nil {
  1017  		t.Fatal(err)
  1018  	}
  1019  	err = st.setHostStorage()
  1020  	if err != nil {
  1021  		t.Fatal(err)
  1022  	}
  1023  	var ah HostdbActiveGET
  1024  	for i := 0; i < 50; i++ {
  1025  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  1026  			t.Fatal(err)
  1027  		}
  1028  		if len(ah.Hosts) == 1 {
  1029  			break
  1030  		}
  1031  		time.Sleep(time.Millisecond * 100)
  1032  	}
  1033  	if len(ah.Hosts) != 1 {
  1034  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
  1035  	}
  1036  
  1037  	// Set an allowance for the renter, allowing a contract to be formed.
  1038  	allowanceValues := url.Values{}
  1039  	testFunds := "10000000000000000000000000000" // 10k SC
  1040  	testPeriod := 10
  1041  	allowanceValues.Set("funds", testFunds)
  1042  	allowanceValues.Set("period", strconv.Itoa(testPeriod))
  1043  	allowanceValues.Set("renewwindow", strconv.Itoa(testPeriod/2))
  1044  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1045  	err = st.stdPostAPI("/renter", allowanceValues)
  1046  	if err != nil {
  1047  		t.Fatal(err)
  1048  	}
  1049  
  1050  	// Block until the allowance has finished forming contracts.
  1051  	err = build.Retry(50, time.Millisecond*250, func() error {
  1052  		var rc RenterContracts
  1053  		err = st.getAPI("/renter/contracts", &rc)
  1054  		if err != nil {
  1055  			return errors.New("couldn't get renter stats")
  1056  		}
  1057  		if len(rc.Contracts) != 1 {
  1058  			return errors.New("no contracts")
  1059  		}
  1060  		return nil
  1061  	})
  1062  	if err != nil {
  1063  		t.Fatal("allowance setting failed")
  1064  	}
  1065  
  1066  	// Create a file.
  1067  	path := filepath.Join(st.dir, "test.dat")
  1068  	err = createRandFile(path, 1024)
  1069  	if err != nil {
  1070  		t.Fatal(err)
  1071  	}
  1072  
  1073  	// Upload the file to the renter.
  1074  	uploadValues := url.Values{}
  1075  	uploadValues.Set("source", path)
  1076  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1077  	if err != nil {
  1078  		t.Fatal(err)
  1079  	}
  1080  	// Only one piece will be uploaded (10% at current redundancy).
  1081  	var rf RenterFiles
  1082  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1083  		st.getAPI("/renter/files", &rf)
  1084  		time.Sleep(100 * time.Millisecond)
  1085  	}
  1086  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1087  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1088  	}
  1089  
  1090  	// Get current contract ID.
  1091  	var rc RenterContracts
  1092  	err = st.getAPI("/renter/contracts", &rc)
  1093  	if err != nil {
  1094  		t.Fatal(err)
  1095  	}
  1096  	contractID := rc.Contracts[0].ID
  1097  
  1098  	// Mine enough blocks to enter the renewal window.
  1099  	testWindow := testPeriod / 2
  1100  	for i := 0; i < testWindow+1; i++ {
  1101  		_, err = st.miner.AddBlock()
  1102  		if err != nil {
  1103  			t.Fatal(err)
  1104  		}
  1105  	}
  1106  	// Wait for the contract to be renewed.
  1107  	for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ {
  1108  		st.getAPI("/renter/contracts", &rc)
  1109  		time.Sleep(100 * time.Millisecond)
  1110  	}
  1111  	if rc.Contracts[0].ID == contractID {
  1112  		t.Fatal("contract was not renewed:", rc.Contracts[0])
  1113  	}
  1114  
  1115  	// Try downloading the file.
  1116  	downpath := filepath.Join(st.dir, "testdown.dat")
  1117  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1118  	if err != nil {
  1119  		t.Fatal(err)
  1120  	}
  1121  	// Check that the download has the right contents.
  1122  	orig, err := ioutil.ReadFile(path)
  1123  	if err != nil {
  1124  		t.Fatal(err)
  1125  	}
  1126  	download, err := ioutil.ReadFile(downpath)
  1127  	if err != nil {
  1128  		t.Fatal(err)
  1129  	}
  1130  	if bytes.Compare(orig, download) != 0 {
  1131  		t.Fatal("data mismatch when downloading a file")
  1132  	}
  1133  }
  1134  
  1135  // TestRenterAllowance sets up an integration test where a renter attempts to
  1136  // download a file after changing the allowance.
  1137  func TestRenterAllowance(t *testing.T) {
  1138  	t.Skip("bypassing NDF")
  1139  	if testing.Short() {
  1140  		t.SkipNow()
  1141  	}
  1142  	t.Parallel()
  1143  
  1144  	st, err := createServerTester(t.Name())
  1145  	if err != nil {
  1146  		t.Fatal(err)
  1147  	}
  1148  	defer st.server.panicClose()
  1149  
  1150  	// Announce the host and start accepting contracts.
  1151  	err = st.announceHost()
  1152  	if err != nil {
  1153  		t.Fatal(err)
  1154  	}
  1155  	err = st.acceptContracts()
  1156  	if err != nil {
  1157  		t.Fatal(err)
  1158  	}
  1159  	err = st.setHostStorage()
  1160  	if err != nil {
  1161  		t.Fatal(err)
  1162  	}
  1163  
  1164  	// Set an allowance for the renter, allowing a contract to be formed.
  1165  	allowanceValues := url.Values{}
  1166  	testFunds := types.SiacoinPrecision.Mul64(10000) // 10k SC
  1167  	testPeriod := 20
  1168  	allowanceValues.Set("funds", testFunds.String())
  1169  	allowanceValues.Set("period", strconv.Itoa(testPeriod))
  1170  	err = st.stdPostAPI("/renter", allowanceValues)
  1171  	if err != nil {
  1172  		t.Fatal(err)
  1173  	}
  1174  
  1175  	// Create a file.
  1176  	path := filepath.Join(st.dir, "test.dat")
  1177  	err = createRandFile(path, 1024)
  1178  	if err != nil {
  1179  		t.Fatal(err)
  1180  	}
  1181  
  1182  	// Upload the file to the renter.
  1183  	uploadValues := url.Values{}
  1184  	uploadValues.Set("source", path)
  1185  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1186  	if err != nil {
  1187  		t.Fatal(err)
  1188  	}
  1189  	// Only one piece will be uploaded (10% at current redundancy).
  1190  	var rf RenterFiles
  1191  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1192  		st.getAPI("/renter/files", &rf)
  1193  		time.Sleep(100 * time.Millisecond)
  1194  	}
  1195  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1196  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1197  	}
  1198  
  1199  	t.Skip("ndf - re-enable after contractor overhaul")
  1200  
  1201  	// Try downloading the file after modifying the allowance in various ways.
  1202  	allowances := []struct {
  1203  		funds  types.Currency
  1204  		period int
  1205  	}{
  1206  		{testFunds.Mul64(10), testPeriod / 2},
  1207  		{testFunds, testPeriod / 2},
  1208  		{testFunds.Div64(10), testPeriod / 2},
  1209  		{testFunds.Mul64(10), testPeriod},
  1210  		{testFunds, testPeriod},
  1211  		{testFunds.Div64(10), testPeriod},
  1212  		{testFunds.Mul64(10), testPeriod * 2},
  1213  		{testFunds, testPeriod * 2},
  1214  		{testFunds.Div64(10), testPeriod * 2},
  1215  	}
  1216  
  1217  	for _, a := range allowances {
  1218  		allowanceValues.Set("funds", a.funds.String())
  1219  		allowanceValues.Set("period", strconv.Itoa(a.period))
  1220  		err = st.stdPostAPI("/renter", allowanceValues)
  1221  		if err != nil {
  1222  			t.Fatal(err)
  1223  		}
  1224  		time.Sleep(100 * time.Millisecond)
  1225  
  1226  		// Try downloading the file.
  1227  		downpath := filepath.Join(st.dir, "testdown.dat")
  1228  		err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1229  		if err != nil {
  1230  			t.Fatal(err)
  1231  		}
  1232  		// Check that the download has the right contents.
  1233  		orig, err := ioutil.ReadFile(path)
  1234  		if err != nil {
  1235  			t.Fatal(err)
  1236  		}
  1237  		download, err := ioutil.ReadFile(downpath)
  1238  		if err != nil {
  1239  			t.Fatal(err)
  1240  		}
  1241  		if bytes.Compare(orig, download) != 0 {
  1242  			t.Fatal("data mismatch when downloading a file")
  1243  		}
  1244  	}
  1245  }
  1246  
  1247  // TestHostAndRentReload sets up an integration test where a host and renter
  1248  // do basic uploads and downloads, with an intervening shutdown+startup.
  1249  func TestHostAndRentReload(t *testing.T) {
  1250  	if testing.Short() {
  1251  		t.SkipNow()
  1252  	}
  1253  	t.Parallel()
  1254  	st, err := createServerTester(t.Name())
  1255  	if err != nil {
  1256  		t.Fatal(err)
  1257  	}
  1258  
  1259  	// Announce the host and start accepting contracts.
  1260  	err = st.announceHost()
  1261  	if err != nil {
  1262  		t.Fatal(err)
  1263  	}
  1264  	err = st.acceptContracts()
  1265  	if err != nil {
  1266  		t.Fatal(err)
  1267  	}
  1268  	err = st.setHostStorage()
  1269  	if err != nil {
  1270  		t.Fatal(err)
  1271  	}
  1272  	// Mine a block so that the wallet reclaims refund outputs
  1273  	_, err = st.miner.AddBlock()
  1274  	if err != nil {
  1275  		t.Fatal(err)
  1276  	}
  1277  
  1278  	// Set an allowance for the renter, allowing a contract to be formed.
  1279  	allowanceValues := url.Values{}
  1280  	testFunds := "10000000000000000000000000000" // 10k SC
  1281  	testPeriod := "10"
  1282  	allowanceValues.Set("funds", testFunds)
  1283  	allowanceValues.Set("period", testPeriod)
  1284  	allowanceValues.Set("renewwindow", testRenewWindow)
  1285  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1286  	err = st.stdPostAPI("/renter", allowanceValues)
  1287  	if err != nil {
  1288  		t.Fatal(err)
  1289  	}
  1290  
  1291  	// Block until the allowance has finished forming contracts.
  1292  	err = build.Retry(50, time.Millisecond*250, func() error {
  1293  		var rc RenterContracts
  1294  		err = st.getAPI("/renter/contracts", &rc)
  1295  		if err != nil {
  1296  			return errors.New("couldn't get renter stats")
  1297  		}
  1298  		if len(rc.Contracts) != 1 {
  1299  			return errors.New("no contracts")
  1300  		}
  1301  		return nil
  1302  	})
  1303  	if err != nil {
  1304  		t.Fatal("allowance setting failed")
  1305  	}
  1306  
  1307  	// Create a file.
  1308  	path := filepath.Join(st.dir, "test.dat")
  1309  	err = createRandFile(path, 1024)
  1310  	if err != nil {
  1311  		t.Fatal(err)
  1312  	}
  1313  
  1314  	// Upload the file to the renter.
  1315  	uploadValues := url.Values{}
  1316  	uploadValues.Set("source", path)
  1317  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1318  	if err != nil {
  1319  		t.Fatal(err)
  1320  	}
  1321  	// Only one piece will be uploaded (10% at current redundancy).
  1322  	var rf RenterFiles
  1323  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1324  		st.getAPI("/renter/files", &rf)
  1325  		time.Sleep(100 * time.Millisecond)
  1326  	}
  1327  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1328  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1329  	}
  1330  
  1331  	// Try downloading the file.
  1332  	downpath := filepath.Join(st.dir, "testdown.dat")
  1333  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1334  	if err != nil {
  1335  		t.Fatal(err)
  1336  	}
  1337  	// Check that the download has the right contents.
  1338  	orig, err := ioutil.ReadFile(path)
  1339  	if err != nil {
  1340  		t.Fatal(err)
  1341  	}
  1342  	download, err := ioutil.ReadFile(downpath)
  1343  	if err != nil {
  1344  		t.Fatal(err)
  1345  	}
  1346  	if bytes.Compare(orig, download) != 0 {
  1347  		t.Fatal("data mismatch when downloading a file")
  1348  	}
  1349  
  1350  	// The renter's downloads queue should have 1 entry now.
  1351  	var queue RenterDownloadQueue
  1352  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
  1353  		t.Fatal(err)
  1354  	}
  1355  	if len(queue.Downloads) != 1 {
  1356  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
  1357  	}
  1358  
  1359  	// close and reopen the server
  1360  	err = st.server.Close()
  1361  	if err != nil {
  1362  		t.Fatal(err)
  1363  	}
  1364  	st, err = assembleServerTester(st.walletKey, st.dir)
  1365  	if err != nil {
  1366  		t.Fatal(err)
  1367  	}
  1368  	defer st.server.panicClose()
  1369  
  1370  	// Announce the host again and wait until the host is re-scanned and put
  1371  	// back into the hostdb as an active host.
  1372  	announceValues := url.Values{}
  1373  	announceValues.Set("address", string(st.host.ExternalSettings().NetAddress))
  1374  	err = st.stdPostAPI("/host/announce", announceValues)
  1375  	if err != nil {
  1376  		t.Fatal(err)
  1377  	}
  1378  	// Mine a block.
  1379  	_, err = st.miner.AddBlock()
  1380  	if err != nil {
  1381  		t.Fatal(err)
  1382  	}
  1383  	err = build.Retry(100, time.Millisecond*100, func() error {
  1384  		var hosts HostdbActiveGET
  1385  		err := st.getAPI("/hostdb/active", &hosts)
  1386  		if err != nil {
  1387  			return err
  1388  		}
  1389  		if len(hosts.Hosts) != 1 {
  1390  			return errors.New("host is not in the set of active hosts")
  1391  		}
  1392  		return nil
  1393  	})
  1394  	if err != nil {
  1395  		t.Fatal(err)
  1396  	}
  1397  
  1398  	// Try downloading the file.
  1399  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1400  	if err != nil {
  1401  		t.Fatal(err)
  1402  	}
  1403  	// Check that the download has the right contents.
  1404  	orig, err = ioutil.ReadFile(path)
  1405  	if err != nil {
  1406  		t.Fatal(err)
  1407  	}
  1408  	download, err = ioutil.ReadFile(downpath)
  1409  	if err != nil {
  1410  		t.Fatal(err)
  1411  	}
  1412  	if bytes.Compare(orig, download) != 0 {
  1413  		t.Fatal("data mismatch when downloading a file")
  1414  	}
  1415  }
  1416  
  1417  // TestHostAndRenterRenewInterrupt
  1418  func TestHostAndRenterRenewInterrupt(t *testing.T) {
  1419  	t.Skip("active test following contractor overhaul")
  1420  	if testing.Short() {
  1421  		t.SkipNow()
  1422  	}
  1423  	t.Parallel()
  1424  	st, err := createServerTester(t.Name())
  1425  	if err != nil {
  1426  		t.Fatal(err)
  1427  	}
  1428  	stHost, err := blankServerTester(t.Name() + "-Host")
  1429  	if err != nil {
  1430  		t.Fatal(err)
  1431  	}
  1432  	sts := []*serverTester{st, stHost}
  1433  	err = fullyConnectNodes(sts)
  1434  	if err != nil {
  1435  		t.Fatal(err)
  1436  	}
  1437  	err = fundAllNodes(sts)
  1438  	if err != nil {
  1439  		t.Fatal(err)
  1440  	}
  1441  
  1442  	// Announce the host.
  1443  	err = stHost.acceptContracts()
  1444  	if err != nil {
  1445  		t.Fatal(err)
  1446  	}
  1447  	err = stHost.setHostStorage()
  1448  	if err != nil {
  1449  		t.Fatal(err)
  1450  	}
  1451  	err = stHost.announceHost()
  1452  	if err != nil {
  1453  		t.Fatal(err)
  1454  	}
  1455  
  1456  	// Wait for host to be seen in renter's hostdb
  1457  	var ah HostdbActiveGET
  1458  	for i := 0; i < 50; i++ {
  1459  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  1460  			t.Fatal(err)
  1461  		}
  1462  		if len(ah.Hosts) == 1 {
  1463  			break
  1464  		}
  1465  		time.Sleep(time.Millisecond * 100)
  1466  	}
  1467  	if len(ah.Hosts) != 1 {
  1468  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
  1469  	}
  1470  
  1471  	// Upload a file to the host.
  1472  	allowanceValues := url.Values{}
  1473  	testFunds := "10000000000000000000000000000" // 10k SC
  1474  	testPeriod := "10"
  1475  	testPeriodInt := 10
  1476  	allowanceValues.Set("funds", testFunds)
  1477  	allowanceValues.Set("period", testPeriod)
  1478  	err = st.stdPostAPI("/renter", allowanceValues)
  1479  	if err != nil {
  1480  		t.Fatal(err)
  1481  	}
  1482  	// Create a file.
  1483  	path := filepath.Join(st.dir, "test.dat")
  1484  	err = createRandFile(path, 10e3)
  1485  	if err != nil {
  1486  		t.Fatal(err)
  1487  	}
  1488  	// Upload the file to the renter.
  1489  	uploadValues := url.Values{}
  1490  	uploadValues.Set("source", path)
  1491  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1492  	if err != nil {
  1493  		t.Fatal(err)
  1494  	}
  1495  
  1496  	// Get current contract ID.
  1497  	var rc RenterContracts
  1498  	err = st.getAPI("/renter/contracts", &rc)
  1499  	if err != nil {
  1500  		t.Fatal(err)
  1501  	}
  1502  	contractID := rc.Contracts[0].ID
  1503  
  1504  	// Mine enough blocks to enter the renewal window.
  1505  	testWindow := testPeriodInt / 2
  1506  	for i := 0; i < testWindow+1; i++ {
  1507  		_, err = st.miner.AddBlock()
  1508  		if err != nil {
  1509  			t.Fatal(err)
  1510  		}
  1511  	}
  1512  	// Wait for the contract to be renewed.
  1513  	for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ {
  1514  		st.getAPI("/renter/contracts", &rc)
  1515  		time.Sleep(100 * time.Millisecond)
  1516  	}
  1517  	if rc.Contracts[0].ID == contractID {
  1518  		t.Fatal("contract was not renewed:", rc.Contracts[0])
  1519  	}
  1520  
  1521  	// Only one piece will be uploaded (10% at current redundancy).
  1522  	var rf RenterFiles
  1523  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1524  		st.getAPI("/renter/files", &rf)
  1525  		time.Sleep(1000 * time.Millisecond)
  1526  	}
  1527  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1528  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1529  	}
  1530  
  1531  	// Try downloading the file.
  1532  	downpath := filepath.Join(st.dir, "testdown.dat")
  1533  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1534  	if err != nil {
  1535  		t.Fatal(err)
  1536  	}
  1537  	// Check that the download has the right contents.
  1538  	orig, err := ioutil.ReadFile(path)
  1539  	if err != nil {
  1540  		t.Fatal(err)
  1541  	}
  1542  	download, err := ioutil.ReadFile(downpath)
  1543  	if err != nil {
  1544  		t.Fatal(err)
  1545  	}
  1546  	if bytes.Compare(orig, download) != 0 {
  1547  		t.Fatal("data mismatch when downloading a file")
  1548  	}
  1549  }
  1550  
  1551  // TestUploadedBytesReporting verifies that reporting of how many bytes have
  1552  // been uploaded via active contracts is accurate
  1553  func TestUploadedBytesReporting(t *testing.T) {
  1554  	if testing.Short() {
  1555  		t.SkipNow()
  1556  	}
  1557  	t.Parallel()
  1558  	st, err := createServerTester(t.Name())
  1559  	if err != nil {
  1560  		t.Fatal(err)
  1561  	}
  1562  	defer st.server.Close()
  1563  	stH1, err := blankServerTester(t.Name() + " - Host 2")
  1564  	if err != nil {
  1565  		t.Fatal(err)
  1566  	}
  1567  	defer stH1.server.Close()
  1568  	testGroup := []*serverTester{st, stH1}
  1569  
  1570  	// Connect the testers to eachother so that they are all on the same
  1571  	// blockchain.
  1572  	err = fullyConnectNodes(testGroup)
  1573  	if err != nil {
  1574  		t.Fatal(err)
  1575  	}
  1576  	// Make sure that every wallet has money in it.
  1577  	err = fundAllNodes(testGroup)
  1578  	if err != nil {
  1579  		t.Fatal(err)
  1580  	}
  1581  	// Add storage to every host.
  1582  	err = addStorageToAllHosts(testGroup)
  1583  	if err != nil {
  1584  		t.Fatal(err)
  1585  	}
  1586  	// Announce every host.
  1587  	err = announceAllHosts(testGroup)
  1588  	if err != nil {
  1589  		t.Fatal(err)
  1590  	}
  1591  
  1592  	// Set an allowance with two hosts.
  1593  	allowanceValues := url.Values{}
  1594  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  1595  	allowanceValues.Set("hosts", "2")
  1596  	allowanceValues.Set("period", "10")
  1597  	allowanceValues.Set("renewwindow", "5")
  1598  	err = st.stdPostAPI("/renter", allowanceValues)
  1599  	if err != nil {
  1600  		t.Fatal(err)
  1601  	}
  1602  
  1603  	// Block until the allowance has finished forming contracts.
  1604  	err = build.Retry(50, time.Millisecond*250, func() error {
  1605  		var rc RenterContracts
  1606  		err = st.getAPI("/renter/contracts", &rc)
  1607  		if err != nil {
  1608  			return errors.New("couldn't get renter stats")
  1609  		}
  1610  		if len(rc.Contracts) != 2 {
  1611  			return errors.New("no contracts")
  1612  		}
  1613  		return nil
  1614  	})
  1615  	if err != nil {
  1616  		t.Fatal("allowance setting failed")
  1617  	}
  1618  
  1619  	// Create a file to upload.
  1620  	filesize := int(modules.SectorSize * 2)
  1621  	path := filepath.Join(st.dir, "test.dat")
  1622  	err = createRandFile(path, filesize)
  1623  	if err != nil {
  1624  		t.Fatal(err)
  1625  	}
  1626  
  1627  	// Upload the file
  1628  	dataPieces := 1
  1629  	parityPieces := 1
  1630  	uploadValues := url.Values{}
  1631  	uploadValues.Set("source", path)
  1632  	uploadValues.Set("datapieces", fmt.Sprint(dataPieces))
  1633  	uploadValues.Set("paritypieces", fmt.Sprint(parityPieces))
  1634  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1635  	if err != nil {
  1636  		t.Fatal(err)
  1637  	}
  1638  
  1639  	// Calculate the encrypted size of our fully redundant encoded file
  1640  	pieceSize := modules.SectorSize - crypto.TwofishOverhead
  1641  	chunkSize := pieceSize * uint64(dataPieces)
  1642  	numChunks := uint64(filesize) / chunkSize
  1643  	if uint64(filesize)%chunkSize != 0 {
  1644  		numChunks++
  1645  	}
  1646  	fullyRedundantSize := modules.SectorSize * uint64(dataPieces+parityPieces) * uint64(numChunks)
  1647  
  1648  	// Monitor the file as it uploads. Ensure that the UploadProgress times
  1649  	// the fully redundant file size always equals UploadedBytes reported
  1650  	var rf RenterFiles
  1651  	for i := 0; i < 60 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100); i++ {
  1652  		st.getAPI("/renter/files", &rf)
  1653  		if len(rf.Files) >= 1 {
  1654  			uploadProgressBytes := uint64(float64(fullyRedundantSize) * rf.Files[0].UploadProgress / 100.0)
  1655  			// Note: in Go 1.10 we will be able to write Math.Round(uploadProgressBytes) != rf.Files[0].UploadedBytes
  1656  			if uploadProgressBytes != rf.Files[0].UploadedBytes && (uploadProgressBytes+1) != rf.Files[0].UploadedBytes {
  1657  				t.Fatalf("api reports having uploaded %v bytes when upload progress is %v%%, but the actual uploaded bytes count should be %v\n",
  1658  					rf.Files[0].UploadedBytes, rf.Files[0].UploadProgress, uploadProgressBytes)
  1659  			}
  1660  		}
  1661  		time.Sleep(time.Second)
  1662  	}
  1663  	if err != nil {
  1664  		t.Fatal(err)
  1665  	}
  1666  
  1667  	// Upload progress should be 100% and redundancy should reach 2
  1668  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100 || rf.Files[0].Redundancy != 2 {
  1669  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1670  	}
  1671  
  1672  	// When the file is fully redundantly uploaded, UploadedBytes should
  1673  	// equal the file's fully redundant size
  1674  	if rf.Files[0].UploadedBytes != fullyRedundantSize {
  1675  		t.Fatalf("api reports having uploaded %v bytes when upload progress is 100%%, but the actual fully redundant file size is %v\n",
  1676  			rf.Files[0].UploadedBytes, fullyRedundantSize)
  1677  	}
  1678  
  1679  }
  1680  
  1681  // TestRenterMissingHosts verifies that if hosts are taken offline, downloads
  1682  // fail.
  1683  func TestRenterMissingHosts(t *testing.T) {
  1684  	if testing.Short() || !build.VLONG {
  1685  		t.SkipNow()
  1686  	}
  1687  	st, err := createServerTester(t.Name())
  1688  	if err != nil {
  1689  		t.Fatal(err)
  1690  	}
  1691  	defer st.server.Close()
  1692  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  1693  	if err != nil {
  1694  		t.Fatal(err)
  1695  	}
  1696  	defer stH1.server.Close()
  1697  	stH2, err := blankServerTester(t.Name() + " - Host 2")
  1698  	if err != nil {
  1699  		t.Fatal(err)
  1700  	}
  1701  	defer stH2.server.Close()
  1702  	stH3, err := blankServerTester(t.Name() + " - Host 3")
  1703  	if err != nil {
  1704  		t.Fatal(err)
  1705  	}
  1706  	defer stH3.server.Close()
  1707  	testGroup := []*serverTester{st, stH1, stH2, stH3}
  1708  
  1709  	// Connect the testers to eachother so that they are all on the same
  1710  	// blockchain.
  1711  	err = fullyConnectNodes(testGroup)
  1712  	if err != nil {
  1713  		t.Fatal(err)
  1714  	}
  1715  	// Make sure that every wallet has money in it.
  1716  	err = fundAllNodes(testGroup)
  1717  	if err != nil {
  1718  		t.Fatal(err)
  1719  	}
  1720  
  1721  	// Add storage to every host.
  1722  	err = addStorageToAllHosts(testGroup)
  1723  	if err != nil {
  1724  		t.Fatal(err)
  1725  	}
  1726  	err = announceAllHosts(testGroup)
  1727  	if err != nil {
  1728  		t.Fatal(err)
  1729  	}
  1730  
  1731  	// Set an allowance with two hosts.
  1732  	allowanceValues := url.Values{}
  1733  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  1734  	allowanceValues.Set("hosts", "3")
  1735  	allowanceValues.Set("period", "20")
  1736  	err = st.stdPostAPI("/renter", allowanceValues)
  1737  	if err != nil {
  1738  		t.Fatal(err)
  1739  	}
  1740  
  1741  	// Block until the allowance has finished forming contracts.
  1742  	err = build.Retry(50, time.Millisecond*250, func() error {
  1743  		var rc RenterContracts
  1744  		err = st.getAPI("/renter/contracts", &rc)
  1745  		if err != nil {
  1746  			return errors.New("couldn't get renter stats")
  1747  		}
  1748  		if len(rc.Contracts) != 3 {
  1749  			return errors.New("no contracts")
  1750  		}
  1751  		return nil
  1752  	})
  1753  	if err != nil {
  1754  		t.Fatal("allowance setting failed:", err)
  1755  	}
  1756  
  1757  	// Create a file to upload.
  1758  	filesize := int(100)
  1759  	path := filepath.Join(st.dir, "test.dat")
  1760  	err = createRandFile(path, filesize)
  1761  	if err != nil {
  1762  		t.Fatal(err)
  1763  	}
  1764  
  1765  	// upload the file
  1766  	uploadValues := url.Values{}
  1767  	uploadValues.Set("source", path)
  1768  	uploadValues.Set("datapieces", "2")
  1769  	uploadValues.Set("paritypieces", "1")
  1770  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1771  	if err != nil {
  1772  		t.Fatal(err)
  1773  	}
  1774  
  1775  	// redundancy should reach 1.5
  1776  	var rf RenterFiles
  1777  	err = build.Retry(20, time.Second, func() error {
  1778  		st.getAPI("/renter/files", &rf)
  1779  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 {
  1780  			return nil
  1781  		}
  1782  		return errors.New("file not uploaded")
  1783  	})
  1784  	if err != nil {
  1785  		t.Fatal(err)
  1786  	}
  1787  
  1788  	// verify we can download
  1789  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
  1790  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1791  	if err != nil {
  1792  		t.Fatal(err)
  1793  	}
  1794  
  1795  	// take down one of the hosts
  1796  	err = stH1.server.Close()
  1797  	if err != nil {
  1798  		t.Fatal(err)
  1799  	}
  1800  
  1801  	// redundancy should not decrement, we have a backup host we can use.
  1802  	err = build.Retry(60, time.Second, func() error {
  1803  		st.getAPI("/renter/files", &rf)
  1804  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 {
  1805  			return nil
  1806  		}
  1807  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  1808  	})
  1809  	if err != nil {
  1810  		t.Log(err)
  1811  	}
  1812  
  1813  	// verify we still can download
  1814  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  1815  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1816  	if err != nil {
  1817  		t.Fatal(err)
  1818  	}
  1819  
  1820  	// take down another host
  1821  	err = stH2.server.Close()
  1822  	if err != nil {
  1823  		t.Fatal(err)
  1824  	}
  1825  
  1826  	// wait for the redundancy to decrement
  1827  	err = build.Retry(60, time.Second, func() error {
  1828  		st.getAPI("/renter/files", &rf)
  1829  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
  1830  			return nil
  1831  		}
  1832  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  1833  	})
  1834  	if err != nil {
  1835  		t.Log(err)
  1836  	}
  1837  
  1838  	// verify we still can download
  1839  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  1840  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1841  	if err != nil {
  1842  		t.Fatal(err)
  1843  	}
  1844  
  1845  	// take down another host
  1846  	err = stH3.server.Close()
  1847  	if err != nil {
  1848  		t.Fatal(err)
  1849  	}
  1850  
  1851  	// wait for the redundancy to decrement
  1852  	err = build.Retry(60, time.Second, func() error {
  1853  		st.getAPI("/renter/files", &rf)
  1854  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 0 {
  1855  			return nil
  1856  		}
  1857  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  1858  	})
  1859  	if err != nil {
  1860  		t.Log(err)
  1861  	}
  1862  
  1863  	// verify that the download fails
  1864  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify4.dat")
  1865  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1866  	if err == nil {
  1867  		t.Fatal("expected download to fail with redundancy <1")
  1868  	}
  1869  }
  1870  
  1871  // TestRepairLoopBlocking checks if the repair loop blocks operations while a
  1872  // non local file is being downloaded for repair.
  1873  func TestRepairLoopBlocking(t *testing.T) {
  1874  	// TODO: Refactor dependency management to block download
  1875  	t.Skip("Test requires refactoring")
  1876  	if testing.Short() || !build.VLONG {
  1877  		t.SkipNow()
  1878  	}
  1879  	st, err := createServerTester(t.Name())
  1880  	if err != nil {
  1881  		t.Fatal(err)
  1882  	}
  1883  	//st.renter.SetDependencies(renter.BlockRepairUpload{})
  1884  	defer st.server.Close()
  1885  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  1886  	if err != nil {
  1887  		t.Fatal(err)
  1888  	}
  1889  	defer stH1.server.Close()
  1890  	testGroup := []*serverTester{st, stH1}
  1891  
  1892  	// Connect the testers to eachother so that they are all on the same
  1893  	// blockchain.
  1894  	err = fullyConnectNodes(testGroup)
  1895  	if err != nil {
  1896  		t.Fatal(err)
  1897  	}
  1898  	// Make sure that every wallet has money in it.
  1899  	err = fundAllNodes(testGroup)
  1900  	if err != nil {
  1901  		t.Fatal(err)
  1902  	}
  1903  
  1904  	// Add storage to every host.
  1905  	err = addStorageToAllHosts(testGroup)
  1906  	if err != nil {
  1907  		t.Fatal(err)
  1908  	}
  1909  	err = announceAllHosts(testGroup)
  1910  	if err != nil {
  1911  		t.Fatal(err)
  1912  	}
  1913  
  1914  	// Set an allowance with two hosts.
  1915  	allowanceValues := url.Values{}
  1916  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  1917  	allowanceValues.Set("hosts", "2")
  1918  	allowanceValues.Set("period", "10")
  1919  	err = st.stdPostAPI("/renter", allowanceValues)
  1920  	if err != nil {
  1921  		t.Fatal(err)
  1922  	}
  1923  
  1924  	// Create a file with 1 chunk to upload.
  1925  	filesize := int(1)
  1926  	path := filepath.Join(st.dir, "test.dat")
  1927  	err = createRandFile(path, filesize)
  1928  	if err != nil {
  1929  		t.Fatal(err)
  1930  	}
  1931  
  1932  	// upload the file
  1933  	uploadValues := url.Values{}
  1934  	uploadValues.Set("source", path)
  1935  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1936  	if err != nil {
  1937  		t.Fatal(err)
  1938  	}
  1939  
  1940  	// redundancy should reach 2
  1941  	var rf RenterFiles
  1942  	err = build.Retry(60, time.Second, func() error {
  1943  		st.getAPI("/renter/files", &rf)
  1944  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  1945  			return nil
  1946  		}
  1947  		return errors.New("file not uploaded")
  1948  	})
  1949  	if err != nil {
  1950  		t.Fatal(err)
  1951  	}
  1952  
  1953  	// verify we can download
  1954  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
  1955  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1956  	if err != nil {
  1957  		t.Fatal(err)
  1958  	}
  1959  
  1960  	// remove the local copy of the file
  1961  	err = os.Remove(path)
  1962  	if err != nil {
  1963  		t.Fatal(err)
  1964  	}
  1965  
  1966  	// take down one of the hosts
  1967  	err = stH1.server.Close()
  1968  	if err != nil {
  1969  		t.Fatal(err)
  1970  	}
  1971  
  1972  	// wait for the redundancy to decrement
  1973  	err = build.Retry(60, time.Second, func() error {
  1974  		st.getAPI("/renter/files", &rf)
  1975  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
  1976  			return nil
  1977  		}
  1978  		return errors.New("file redundancy not decremented")
  1979  	})
  1980  	if err != nil {
  1981  		t.Fatal(err)
  1982  	}
  1983  
  1984  	// verify we still can download
  1985  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  1986  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  1987  	if err != nil {
  1988  		t.Fatal(err)
  1989  	}
  1990  
  1991  	// bring up a few new hosts
  1992  	testGroup = []*serverTester{st}
  1993  	for i := 0; i < 3; i++ {
  1994  		stNewHost, err := blankServerTester(t.Name() + fmt.Sprintf("-newhost%d", i))
  1995  		if err != nil {
  1996  			t.Fatal(err)
  1997  		}
  1998  		defer stNewHost.server.Close()
  1999  		testGroup = append(testGroup, stNewHost)
  2000  	}
  2001  
  2002  	// Connect the testers to eachother so that they are all on the same
  2003  	// blockchain.
  2004  	err = fullyConnectNodes(testGroup)
  2005  	if err != nil {
  2006  		t.Fatal(err)
  2007  	}
  2008  	_, err = synchronizationCheck(testGroup)
  2009  	if err != nil {
  2010  		t.Fatal(err)
  2011  	}
  2012  
  2013  	// Make sure that every wallet has money in it.
  2014  	err = fundAllNodes(testGroup)
  2015  	if err != nil {
  2016  		t.Fatal(err)
  2017  	}
  2018  
  2019  	for _, stNewHost := range testGroup[1 : len(testGroup)-1] {
  2020  		err = stNewHost.setHostStorage()
  2021  		if err != nil {
  2022  			t.Fatal(err)
  2023  		}
  2024  		err = stNewHost.announceHost()
  2025  		if err != nil {
  2026  			t.Fatal(err)
  2027  		}
  2028  		err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st)
  2029  		if err != nil {
  2030  			t.Fatal(err)
  2031  		}
  2032  
  2033  		// add a few new blocks in order to cause the renter to form contracts with the new host
  2034  		for i := 0; i < 10; i++ {
  2035  			b, err := testGroup[0].miner.AddBlock()
  2036  			if err != nil {
  2037  				t.Fatal(err)
  2038  			}
  2039  			tipID, err := synchronizationCheck(testGroup)
  2040  			if err != nil {
  2041  				t.Fatal(err)
  2042  			}
  2043  			if b.ID() != tipID {
  2044  				t.Fatal("test group does not have the tip block")
  2045  			}
  2046  		}
  2047  	}
  2048  
  2049  	// wait a few seconds for the the repair to be queued and started
  2050  	time.Sleep(3 * time.Second)
  2051  
  2052  	// redundancy should not increment back to 2 because the renter should be blocked
  2053  	st.getAPI("/renter/files", &rf)
  2054  	if len(rf.Files) >= 1 && rf.Files[0].Redundancy >= 2 && rf.Files[0].Available {
  2055  		t.Error("The file's redundancy incremented back to 2 but shouldn't")
  2056  	}
  2057  
  2058  	// create a second file to upload
  2059  	filesize = int(1)
  2060  	path2 := filepath.Join(st.dir, "test2.dat")
  2061  	err = createRandFile(path2, filesize)
  2062  	if err != nil {
  2063  		t.Fatal(err)
  2064  	}
  2065  
  2066  	// upload the second file
  2067  	uploadValues = url.Values{}
  2068  	uploadValues.Set("source", path2)
  2069  
  2070  	wait := make(chan error)
  2071  	go func() {
  2072  		wait <- st.stdPostAPI("/renter/upload/test2", uploadValues)
  2073  	}()
  2074  	select {
  2075  	case <-time.After(time.Minute):
  2076  		t.Fatal("/renter/upload API call didn't return within 60 seconds")
  2077  	case err = <-wait:
  2078  	}
  2079  	if err != nil {
  2080  		t.Fatal(err)
  2081  	}
  2082  
  2083  	// redundancy should reach 2 for the second file
  2084  	err = build.Retry(60, time.Second, func() error {
  2085  		st.getAPI("/renter/files", &rf)
  2086  		if len(rf.Files) >= 2 && rf.Files[1].Redundancy >= 2 {
  2087  			return nil
  2088  		}
  2089  		return errors.New("file 2 not uploaded")
  2090  	})
  2091  	if err != nil {
  2092  		t.Fatal(err)
  2093  	}
  2094  
  2095  	// verify we can download the second file
  2096  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  2097  	err = st.stdGetAPI("/renter/download/test2?destination=" + downloadPath)
  2098  	if err != nil {
  2099  		t.Fatal(err)
  2100  	}
  2101  }
  2102  
  2103  // TestRemoteFileRepairMassive is similar to TestRemoteFileRepair but uploads
  2104  // more files to find potential deadlocks or crashes
  2105  func TestRemoteFileRepairMassive(t *testing.T) {
  2106  	if testing.Short() || !build.VLONG {
  2107  		t.SkipNow()
  2108  	}
  2109  	st, err := createServerTester(t.Name())
  2110  	if err != nil {
  2111  		t.Fatal(err)
  2112  	}
  2113  	defer st.server.Close()
  2114  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  2115  	if err != nil {
  2116  		t.Fatal(err)
  2117  	}
  2118  	defer stH1.server.Close()
  2119  	testGroup := []*serverTester{st, stH1}
  2120  
  2121  	// Connect the testers to eachother so that they are all on the same
  2122  	// blockchain.
  2123  	err = fullyConnectNodes(testGroup)
  2124  	if err != nil {
  2125  		t.Fatal(err)
  2126  	}
  2127  	// Make sure that every wallet has money in it.
  2128  	err = fundAllNodes(testGroup)
  2129  	if err != nil {
  2130  		t.Fatal(err)
  2131  	}
  2132  
  2133  	// Add storage to every host.
  2134  	err = addStorageToAllHosts(testGroup)
  2135  	if err != nil {
  2136  		t.Fatal(err)
  2137  	}
  2138  	err = announceAllHosts(testGroup)
  2139  	if err != nil {
  2140  		t.Fatal(err)
  2141  	}
  2142  
  2143  	// Set an allowance with two hosts.
  2144  	allowanceValues := url.Values{}
  2145  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2146  	allowanceValues.Set("hosts", "2")
  2147  	allowanceValues.Set("period", "10")
  2148  	err = st.stdPostAPI("/renter", allowanceValues)
  2149  	if err != nil {
  2150  		t.Fatal(err)
  2151  	}
  2152  
  2153  	// Create a file to upload.
  2154  	filesize := int(4000)
  2155  	path := filepath.Join(st.dir, "test.dat")
  2156  	err = createRandFile(path, filesize)
  2157  	if err != nil {
  2158  		t.Fatal(err)
  2159  	}
  2160  
  2161  	// upload the file numUploads times
  2162  	numUploads := 10
  2163  	uploadValues := url.Values{}
  2164  	uploadValues.Set("source", path)
  2165  
  2166  	for i := 0; i < numUploads; i++ {
  2167  		err = st.stdPostAPI(fmt.Sprintf("/renter/upload/test%v", i), uploadValues)
  2168  		if err != nil {
  2169  			t.Fatal(err)
  2170  		}
  2171  	}
  2172  
  2173  	// redundancy should reach 2 for all files
  2174  	var rf RenterFiles
  2175  	err = build.Retry(600, time.Second, func() error {
  2176  		st.getAPI("/renter/files", &rf)
  2177  		if len(rf.Files) != numUploads {
  2178  			return errors.New("file not uploaded")
  2179  		}
  2180  		for i, f := range rf.Files {
  2181  			if f.Redundancy != 2 {
  2182  				return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy)
  2183  			}
  2184  		}
  2185  		return nil
  2186  	})
  2187  	if err != nil {
  2188  		t.Fatal(err)
  2189  	}
  2190  
  2191  	// remove the local copy of the file
  2192  	err = os.Remove(path)
  2193  	if err != nil {
  2194  		t.Fatal(err)
  2195  	}
  2196  
  2197  	// take down one of the hosts
  2198  	err = stH1.server.Close()
  2199  	if err != nil {
  2200  		t.Fatal(err)
  2201  	}
  2202  
  2203  	// wait for the redundancy to decrement
  2204  	err = build.Retry(60, time.Second, func() error {
  2205  		st.getAPI("/renter/files", &rf)
  2206  		if len(rf.Files) != numUploads {
  2207  			return errors.New("file not uploaded")
  2208  		}
  2209  		for _, f := range rf.Files {
  2210  			if f.Redundancy != 1 {
  2211  				return errors.New("file redudancy didn't decrement to x1")
  2212  			}
  2213  		}
  2214  		return nil
  2215  	})
  2216  	if err != nil {
  2217  		t.Fatal(err)
  2218  	}
  2219  
  2220  	// bring up a new host
  2221  	stNewHost, err := blankServerTester(t.Name() + "-newhost")
  2222  	if err != nil {
  2223  		t.Fatal(err)
  2224  	}
  2225  	defer stNewHost.server.Close()
  2226  
  2227  	testGroup = []*serverTester{st, stNewHost}
  2228  
  2229  	// Connect the testers to eachother so that they are all on the same
  2230  	// blockchain.
  2231  	err = fullyConnectNodes(testGroup)
  2232  	if err != nil {
  2233  		t.Fatal(err)
  2234  	}
  2235  	_, err = synchronizationCheck(testGroup)
  2236  	if err != nil {
  2237  		t.Fatal(err)
  2238  	}
  2239  
  2240  	// Make sure that every wallet has money in it.
  2241  	err = fundAllNodes(testGroup)
  2242  	if err != nil {
  2243  		t.Fatal(err)
  2244  	}
  2245  
  2246  	err = stNewHost.setHostStorage()
  2247  	if err != nil {
  2248  		t.Fatal(err)
  2249  	}
  2250  	err = stNewHost.announceHost()
  2251  	if err != nil {
  2252  		t.Fatal(err)
  2253  	}
  2254  	err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st)
  2255  	if err != nil {
  2256  		t.Fatal(err)
  2257  	}
  2258  
  2259  	// add a few new blocks in order to cause the renter to form contracts with the new host
  2260  	for i := 0; i < 10; i++ {
  2261  		b, err := testGroup[0].miner.AddBlock()
  2262  		if err != nil {
  2263  			t.Fatal(err)
  2264  		}
  2265  		tipID, err := synchronizationCheck(testGroup)
  2266  		if err != nil {
  2267  			t.Fatal(err)
  2268  		}
  2269  		if b.ID() != tipID {
  2270  			t.Fatal("test group does not have the tip block")
  2271  		}
  2272  	}
  2273  
  2274  	// redundancy should increment back to 2 as the renter uploads to the new
  2275  	// host using the download-to-upload strategy
  2276  	err = build.Retry(300, time.Second, func() error {
  2277  		st.getAPI("/renter/files", &rf)
  2278  		if len(rf.Files) != numUploads {
  2279  			return errors.New("file not uploaded")
  2280  		}
  2281  		for i, f := range rf.Files {
  2282  			if f.Redundancy != 2 {
  2283  				return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy)
  2284  			}
  2285  		}
  2286  		return nil
  2287  	})
  2288  	if err != nil {
  2289  		t.Fatal(err)
  2290  	}
  2291  }