gitlab.com/jokerrs1/Sia@v1.3.2/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  	"strings"
    16  	"sync"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/NebulousLabs/Sia/build"
    21  	"github.com/NebulousLabs/Sia/crypto"
    22  	"github.com/NebulousLabs/Sia/modules"
    23  	"github.com/NebulousLabs/Sia/types"
    24  )
    25  
    26  // TestHostObligationAcceptingContracts verifies that the host will complete
    27  // storage proofs and the renter will successfully download even if the host
    28  // has set accepting contracts to false.
    29  func TestHostObligationAcceptingContracts(t *testing.T) {
    30  	if testing.Short() {
    31  		t.SkipNow()
    32  	}
    33  	st, err := createServerTester(t.Name())
    34  	if err != nil {
    35  		t.Fatal(err)
    36  	}
    37  	defer st.server.Close()
    38  	err = st.setHostStorage()
    39  	if err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	err = st.acceptContracts()
    43  	if err != nil {
    44  		t.Fatal(err)
    45  	}
    46  	err = st.announceHost()
    47  	if err != nil {
    48  		t.Fatal(err)
    49  	}
    50  	allowanceValues := url.Values{}
    51  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
    52  	allowanceValues.Set("hosts", "1")
    53  	allowanceValues.Set("period", "10")
    54  	allowanceValues.Set("renewwindow", "5")
    55  	err = st.stdPostAPI("/renter", allowanceValues)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	// Block until the allowance has finished forming contracts.
    61  	err = build.Retry(50, time.Millisecond*250, func() error {
    62  		var rc RenterContracts
    63  		err = st.getAPI("/renter/contracts", &rc)
    64  		if err != nil {
    65  			return errors.New("couldn't get renter stats")
    66  		}
    67  		if len(rc.Contracts) != 1 {
    68  			return errors.New("no contracts")
    69  		}
    70  		return nil
    71  	})
    72  	if err != nil {
    73  		t.Fatal("allowance setting failed")
    74  	}
    75  
    76  	filesize := int(1024)
    77  	path := filepath.Join(st.dir, "test.dat")
    78  	err = createRandFile(path, filesize)
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	// upload the file
    84  	uploadValues := url.Values{}
    85  	uploadValues.Set("source", path)
    86  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	// redundancy should reach 1
    92  	var rf RenterFiles
    93  	err = retry(120, time.Millisecond*250, func() error {
    94  		st.getAPI("/renter/files", &rf)
    95  		if len(rf.Files) >= 1 && rf.Files[0].Available {
    96  			return nil
    97  		}
    98  		return errors.New("file not uploaded")
    99  	})
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	// set acceptingcontracts = false, mine some blocks, verify we can download
   105  	settings := st.host.InternalSettings()
   106  	settings.AcceptingContracts = false
   107  	st.host.SetInternalSettings(settings)
   108  	for i := 0; i < 3; i++ {
   109  		_, err := st.miner.AddBlock()
   110  		if err != nil {
   111  			t.Fatal(err)
   112  		}
   113  		time.Sleep(time.Millisecond * 100)
   114  	}
   115  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
   116  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
   117  	if err != nil {
   118  		t.Fatal(err)
   119  	}
   120  
   121  	// mine blocks to cause the host to submit storage proofs to the blockchain.
   122  	for i := 0; i < 15; i++ {
   123  		_, err := st.miner.AddBlock()
   124  		if err != nil {
   125  			t.Fatal(err)
   126  		}
   127  		time.Sleep(time.Millisecond * 100)
   128  	}
   129  
   130  	// should have successful proofs
   131  	success := false
   132  	for _, so := range st.host.StorageObligations() {
   133  		if so.ProofConfirmed {
   134  			success = true
   135  			break
   136  		}
   137  	}
   138  	if !success {
   139  		t.Fatal("no successful storage proofs")
   140  	}
   141  }
   142  
   143  // TestRenterLocalRepair verifies that the renter will use the local file to
   144  // repair if the file exists locally
   145  func TestRenterLocalRepair(t *testing.T) {
   146  	if testing.Short() {
   147  		t.SkipNow()
   148  	}
   149  	st, err := createServerTester(t.Name())
   150  	if err != nil {
   151  		t.Fatal(err)
   152  	}
   153  	defer st.server.Close()
   154  	stH1, err := blankServerTester(t.Name() + " - Host 1")
   155  	if err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	defer stH1.server.Close()
   159  	testGroup := []*serverTester{st, stH1}
   160  
   161  	// Connect the testers to eachother so that they are all on the same
   162  	// blockchain.
   163  	err = fullyConnectNodes(testGroup)
   164  	if err != nil {
   165  		t.Fatal(err)
   166  	}
   167  	// Make sure that every wallet has money in it.
   168  	err = fundAllNodes(testGroup)
   169  	if err != nil {
   170  		t.Fatal(err)
   171  	}
   172  
   173  	// Add storage to every host.
   174  	err = addStorageToAllHosts(testGroup)
   175  	if err != nil {
   176  		t.Fatal(err)
   177  	}
   178  	err = announceAllHosts(testGroup)
   179  	if err != nil {
   180  		t.Fatal(err)
   181  	}
   182  
   183  	// Set an allowance with two hosts.
   184  	allowanceValues := url.Values{}
   185  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
   186  	allowanceValues.Set("hosts", "2")
   187  	allowanceValues.Set("period", "10")
   188  	allowanceValues.Set("renewwindow", "5")
   189  	err = st.stdPostAPI("/renter", allowanceValues)
   190  	if err != nil {
   191  		t.Fatal(err)
   192  	}
   193  
   194  	// Block until the allowance has finished forming contracts.
   195  	err = build.Retry(50, time.Millisecond*250, func() error {
   196  		var rc RenterContracts
   197  		err = st.getAPI("/renter/contracts", &rc)
   198  		if err != nil {
   199  			return errors.New("couldn't get renter stats")
   200  		}
   201  		if len(rc.Contracts) != 2 {
   202  			return errors.New("no contracts")
   203  		}
   204  		return nil
   205  	})
   206  	if err != nil {
   207  		t.Fatal("allowance setting failed")
   208  	}
   209  
   210  	// Create a file to upload.
   211  	filesize := int(1024)
   212  	path := filepath.Join(st.dir, "test.dat")
   213  	err = createRandFile(path, filesize)
   214  	if err != nil {
   215  		t.Fatal(err)
   216  	}
   217  
   218  	// upload the file
   219  	uploadValues := url.Values{}
   220  	uploadValues.Set("source", path)
   221  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   222  	if err != nil {
   223  		t.Fatal(err)
   224  	}
   225  
   226  	// redundancy should reach 2
   227  	var rf RenterFiles
   228  	err = retry(60, time.Second, func() error {
   229  		st.getAPI("/renter/files", &rf)
   230  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy >= 2 {
   231  			return nil
   232  		}
   233  		return errors.New("file not uploaded")
   234  	})
   235  	if err != nil {
   236  		t.Fatal(err)
   237  	}
   238  
   239  	// download spending should not have increased
   240  	var rg RenterGET
   241  	err = st.getAPI("/renter", &rg)
   242  	if err != nil {
   243  		t.Fatal(err)
   244  	}
   245  	if rg.FinancialMetrics.DownloadSpending.Cmp(types.NewCurrency64(0)) > 0 {
   246  		t.Fatalf("expected no download spending, got %v instead\n", rg.FinancialMetrics.DownloadSpending)
   247  	}
   248  
   249  	// take down one of the hosts
   250  	err = stH1.server.Close()
   251  	if err != nil {
   252  		t.Fatal(err)
   253  	}
   254  	// Mine a block so the renter realizes the host is offline.
   255  	b, err := st.miner.AddBlock()
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  	err = waitForBlock(b.ID(), st)
   260  	if err != nil {
   261  		t.Fatal(err)
   262  	}
   263  
   264  	// wait for the redundancy to decrement
   265  	err = retry(60, time.Second, func() error {
   266  		if err := st.getAPI("/renter/files", &rf); err != nil {
   267  			return err
   268  		}
   269  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
   270  			return nil
   271  		}
   272  		return errors.New("file redundancy not decremented")
   273  	})
   274  	if err != nil {
   275  		t.Fatal(err, len(rf.Files), rf.Files[0].Redundancy)
   276  	}
   277  
   278  	// bring up a new host
   279  	stNewHost, err := blankServerTester(t.Name() + "-newhost")
   280  	if err != nil {
   281  		t.Fatal(err)
   282  	}
   283  	defer stNewHost.server.Close()
   284  	testGroup = []*serverTester{st, stNewHost}
   285  
   286  	// Connect the testers to eachother so that they are all on the same
   287  	// blockchain.
   288  	err = fullyConnectNodes(testGroup)
   289  	if err != nil {
   290  		t.Fatal(err)
   291  	}
   292  	_, err = synchronizationCheck(testGroup)
   293  	if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  
   297  	// Make sure that every wallet has money in it.
   298  	err = fundAllNodes(testGroup)
   299  	if err != nil {
   300  		t.Fatal(err)
   301  	}
   302  
   303  	// Set up storage on the new host.
   304  	err = stNewHost.setHostStorage()
   305  	if err != nil {
   306  		t.Fatal(err)
   307  	}
   308  	err = stNewHost.announceHost()
   309  	if err != nil {
   310  		t.Fatal(err)
   311  	}
   312  	// Mine a block so the renter sees the host in its hostdb. Need to mine two
   313  	// blocks because after the announcement, the renter node's blockchain is
   314  	// actually behind.
   315  	b, err = stNewHost.miner.AddBlock()
   316  	if err != nil {
   317  		t.Fatal(err)
   318  	}
   319  	err = waitForBlock(b.ID(), testGroup[0])
   320  	if err != nil {
   321  		t.Fatal(err)
   322  	}
   323  	_, err = synchronizationCheck(testGroup)
   324  	if err != nil {
   325  		t.Fatal(err)
   326  	}
   327  
   328  	// Wait for host to be seen in renter's hostdb
   329  	var ah HostdbActiveGET
   330  	err = build.Retry(250, time.Millisecond*250, func() error {
   331  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   332  			t.Fatal(err)
   333  		}
   334  		if len(ah.Hosts) != 2 {
   335  			return errors.New("not enough hosts in hostdb")
   336  		}
   337  		for _, host := range ah.Hosts {
   338  			if len(host.ScanHistory) < 2 {
   339  				return errors.New("hosts are not scanned")
   340  			}
   341  		}
   342  		return nil
   343  	})
   344  	if err != nil {
   345  		t.Fatal(err, ah)
   346  	}
   347  
   348  	// Mine a block so the contractor sees that it can form a new contract.
   349  	b, err = testGroup[0].miner.AddBlock()
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  	err = waitForBlock(b.ID(), testGroup[0])
   354  	if err != nil {
   355  		t.Fatal(err)
   356  	}
   357  	_, err = synchronizationCheck(testGroup)
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  
   362  	// Block until we formed a contract with the new host.
   363  	err = build.Retry(50, time.Millisecond*250, func() error {
   364  		var rc RenterContracts
   365  		err = st.getAPI("/renter/contracts", &rc)
   366  		if err != nil {
   367  			return errors.New("couldn't get renter stats")
   368  		}
   369  		if len(rc.Contracts) != 3 {
   370  			return fmt.Errorf("Insufficient contracts: expected %v was %v", 3, len(rc.Contracts))
   371  		}
   372  		return nil
   373  	})
   374  	if err != nil {
   375  		t.Fatalf("Failed to form new contract: %v", err)
   376  	}
   377  
   378  	// redundancy should increment back to 2 as the renter uploads to the new
   379  	// host using the download-to-upload strategy
   380  	err = retry(1000, 250*time.Millisecond, func() error {
   381  		if err := st.getAPI("/renter/files", &rf); err != nil {
   382  			return err
   383  		}
   384  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 && rf.Files[0].Available {
   385  			return nil
   386  		}
   387  		return errors.New("file redundancy not incremented")
   388  	})
   389  	if err != nil {
   390  		t.Log(len(rf.Files))
   391  		t.Log(rf.Files[0].Redundancy)
   392  		t.Log(rf.Files[0].Available)
   393  		t.Fatal(err)
   394  	}
   395  	if rg.FinancialMetrics.DownloadSpending.Cmp(types.NewCurrency64(0)) > 0 {
   396  		t.Fatalf("expected no download spending, got %v instead\n", rg.FinancialMetrics.DownloadSpending)
   397  	}
   398  }
   399  
   400  // TestRemoteFileRepair verifies that if a trackedFile is made unavailable
   401  // locally by being deleted, the repair loop will download the necessary chunks
   402  // from the living hosts and upload them to new hosts.
   403  func TestRemoteFileRepair(t *testing.T) {
   404  	if testing.Short() {
   405  		t.SkipNow()
   406  	}
   407  	st, err := createServerTester(t.Name())
   408  	if err != nil {
   409  		t.Fatal(err)
   410  	}
   411  	defer st.server.Close()
   412  	stH1, err := blankServerTester(t.Name() + " - Host 1")
   413  	if err != nil {
   414  		t.Fatal(err)
   415  	}
   416  	defer stH1.server.Close()
   417  	testGroup := []*serverTester{st, stH1}
   418  
   419  	// Connect the testers to eachother so that they are all on the same
   420  	// blockchain.
   421  	err = fullyConnectNodes(testGroup)
   422  	if err != nil {
   423  		t.Fatal(err)
   424  	}
   425  	// Make sure that every wallet has money in it.
   426  	err = fundAllNodes(testGroup)
   427  	if err != nil {
   428  		t.Fatal(err)
   429  	}
   430  
   431  	// Add storage to every host.
   432  	err = addStorageToAllHosts(testGroup)
   433  	if err != nil {
   434  		t.Fatal(err)
   435  	}
   436  	err = announceAllHosts(testGroup)
   437  	if err != nil {
   438  		t.Fatal(err)
   439  	}
   440  
   441  	// Set an allowance with two hosts.
   442  	allowanceValues := url.Values{}
   443  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
   444  	allowanceValues.Set("hosts", "2")
   445  	allowanceValues.Set("period", "10")
   446  	allowanceValues.Set("renewwindow", "5")
   447  	err = st.stdPostAPI("/renter", allowanceValues)
   448  	if err != nil {
   449  		t.Fatal(err)
   450  	}
   451  
   452  	// Create a file to upload.
   453  	filesize := int(45767)
   454  	path := filepath.Join(st.dir, "test.dat")
   455  	err = createRandFile(path, filesize)
   456  	if err != nil {
   457  		t.Fatal(err)
   458  	}
   459  
   460  	// upload the file
   461  	uploadValues := url.Values{}
   462  	uploadValues.Set("source", path)
   463  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   464  	if err != nil {
   465  		t.Fatal(err)
   466  	}
   467  
   468  	// redundancy should reach 2
   469  	var rf RenterFiles
   470  	err = retry(60, time.Second, func() error {
   471  		if err := st.getAPI("/renter/files", &rf); err != nil {
   472  			return err
   473  		}
   474  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
   475  			return nil
   476  		}
   477  		return errors.New("file not uploaded")
   478  	})
   479  	if err != nil {
   480  		t.Fatal(err)
   481  	}
   482  
   483  	// verify we can download
   484  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
   485  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
   486  	if err != nil {
   487  		t.Fatal(err)
   488  	}
   489  	// save a copy of the file contents in memory for verification later
   490  	orig, err := ioutil.ReadFile(path)
   491  	if err != nil {
   492  		t.Fatal(err)
   493  	}
   494  	downloadedFile, err := ioutil.ReadFile(downloadPath)
   495  	if err != nil {
   496  		t.Fatal(err)
   497  	}
   498  	if !bytes.Equal(orig, downloadedFile) {
   499  		t.Log("Files not equal, lengths:", len(orig), len(downloadedFile))
   500  		t.Fatal("Uploaded and downloaded file do not have matching data.")
   501  	}
   502  
   503  	// remove the local copy of the file
   504  	err = build.Retry(50, time.Millisecond*200, func() error {
   505  		return os.Remove(path)
   506  	})
   507  	if err != nil {
   508  		t.Fatal(err)
   509  	}
   510  
   511  	// take down one of the hosts
   512  	err = stH1.server.Close()
   513  	if err != nil {
   514  		t.Fatal(err)
   515  	}
   516  	// wait for the redundancy to decrement
   517  	err = retry(120, time.Millisecond*250, func() error {
   518  		st.getAPI("/renter/files", &rf)
   519  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
   520  			return nil
   521  		}
   522  		return errors.New("file redundancy not decremented")
   523  	})
   524  	if err != nil {
   525  		t.Fatal(err)
   526  	}
   527  	// verify we still can download
   528  	downloadPath2 := filepath.Join(st.dir, "test-downloaded-verify2.dat")
   529  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath2)
   530  	if err != nil {
   531  		t.Fatal(err)
   532  	}
   533  	downloadedFile2, err := ioutil.ReadFile(downloadPath)
   534  	if err != nil {
   535  		t.Fatal(err)
   536  	}
   537  	if !bytes.Equal(orig, downloadedFile2) {
   538  		t.Log("Files not equal, lengths:", len(orig), len(downloadedFile2))
   539  		t.Fatal("Uploaded and downloaded file do not have matching data.")
   540  	}
   541  
   542  	// bring up a new host
   543  	stNewHost, err := blankServerTester(t.Name() + "-newhost")
   544  	if err != nil {
   545  		t.Fatal(err)
   546  	}
   547  	defer stNewHost.server.Close()
   548  	testGroup = []*serverTester{st, stNewHost}
   549  	// Connect the testers to eachother so that they are all on the same
   550  	// blockchain.
   551  	err = fullyConnectNodes(testGroup)
   552  	if err != nil {
   553  		t.Fatal(err)
   554  	}
   555  	_, err = synchronizationCheck(testGroup)
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  
   560  	// Make sure that every wallet has money in it, then set the storage and
   561  	// perform announcements.
   562  	err = fundAllNodes(testGroup)
   563  	if err != nil {
   564  		t.Fatal(err)
   565  	}
   566  	err = stNewHost.setHostStorage()
   567  	if err != nil {
   568  		t.Fatal(err)
   569  	}
   570  	err = stNewHost.announceHost()
   571  	if err != nil {
   572  		t.Fatal(err)
   573  	}
   574  	_, err = stNewHost.miner.AddBlock()
   575  	if err != nil {
   576  		t.Fatal(err)
   577  	}
   578  	err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st)
   579  	if err != nil {
   580  		t.Fatal(err)
   581  	}
   582  	_, err = synchronizationCheck(testGroup)
   583  	if err != nil {
   584  		t.Fatal(err)
   585  	}
   586  
   587  	// Wait for host to be seen in renter's hostdb
   588  	var ah HostdbActiveGET
   589  	err = build.Retry(250, time.Millisecond*250, func() error {
   590  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
   591  			t.Fatal(err)
   592  		}
   593  		if len(ah.Hosts) != 2 {
   594  			return errors.New("not enough hosts in hostdb")
   595  		}
   596  		for _, host := range ah.Hosts {
   597  			if len(host.ScanHistory) < 2 {
   598  				return errors.New("hosts are not scanned")
   599  			}
   600  		}
   601  		return nil
   602  	})
   603  	if err != nil {
   604  		t.Fatal(err)
   605  	}
   606  
   607  	// Mine a block so the contractor sees that it can form a new contract.
   608  	_, err = testGroup[0].miner.AddBlock()
   609  	if err != nil {
   610  		t.Fatal(err)
   611  	}
   612  	_, err = synchronizationCheck(testGroup)
   613  	if err != nil {
   614  		t.Fatal(err)
   615  	}
   616  
   617  	// Block until we formed a contract with the new host.
   618  	err = build.Retry(50, time.Millisecond*250, func() error {
   619  		var rc RenterContracts
   620  		err = st.getAPI("/renter/contracts", &rc)
   621  		if err != nil {
   622  			return errors.New("couldn't get renter stats")
   623  		}
   624  		if len(rc.Contracts) != 3 {
   625  			return fmt.Errorf("Insufficient contracts: expected %v was %v", 3, len(rc.Contracts))
   626  		}
   627  		return nil
   628  	})
   629  	if err != nil {
   630  		t.Fatalf("Failed to form new contract: %v", err)
   631  	}
   632  
   633  	// redundancy should increment back to 2 as the renter uploads to the new
   634  	// host using the download-to-upload strategy
   635  	err = retry(500, 250*time.Millisecond, func() error {
   636  		if err := st.getAPI("/renter/files", &rf); err != nil {
   637  			return err
   638  		}
   639  
   640  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 && rf.Files[0].Available {
   641  			return nil
   642  		}
   643  		return errors.New("file redundancy not incremented")
   644  	})
   645  	if err != nil {
   646  		t.Log(len(rf.Files), rf.Files[0].Redundancy, rf.Files[0].Available)
   647  		t.Fatal(err)
   648  	}
   649  
   650  	// Try to download the repaired file.
   651  	downloadPath = filepath.Join(st.dir, "test-downloaded3.dat")
   652  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
   653  	if err != nil {
   654  		t.Fatal(err)
   655  	}
   656  
   657  	// Check that the download has the right contents.
   658  	downloaded, err := ioutil.ReadFile(downloadPath)
   659  	if err != nil {
   660  		t.Fatal(err)
   661  	}
   662  	if !bytes.Equal(orig, downloaded) {
   663  		t.Fatal("data mismatch when downloading a file")
   664  	}
   665  }
   666  
   667  // TestHostAndRentVanilla sets up an integration test where a host and renter
   668  // do basic uploads and downloads.
   669  func TestHostAndRentVanilla(t *testing.T) {
   670  	if testing.Short() {
   671  		t.SkipNow()
   672  	}
   673  	t.Parallel()
   674  	st, err := createServerTester(t.Name())
   675  	if err != nil {
   676  		t.Fatal(err)
   677  	}
   678  	defer st.server.panicClose()
   679  
   680  	// Announce the host and start accepting contracts.
   681  	err = st.announceHost()
   682  	if err != nil {
   683  		t.Fatal(err)
   684  	}
   685  	err = st.setHostStorage()
   686  	if err != nil {
   687  		t.Fatal(err)
   688  	}
   689  	err = st.acceptContracts()
   690  	if err != nil {
   691  		t.Fatal(err)
   692  	}
   693  
   694  	// Set an allowance for the renter, allowing a contract to be formed.
   695  	allowanceValues := url.Values{}
   696  	testFunds := "10000000000000000000000000000" // 10k SC
   697  	testPeriod := "20"
   698  	renewWindow := "10"
   699  	testPeriodInt := 20
   700  	allowanceValues.Set("funds", testFunds)
   701  	allowanceValues.Set("period", testPeriod)
   702  	allowanceValues.Set("renewwindow", renewWindow)
   703  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
   704  	err = st.stdPostAPI("/renter", allowanceValues)
   705  	if err != nil {
   706  		t.Fatal(err)
   707  	}
   708  
   709  	// Block until the allowance has finished forming contracts.
   710  	err = build.Retry(50, time.Millisecond*250, func() error {
   711  		var rc RenterContracts
   712  		err = st.getAPI("/renter/contracts", &rc)
   713  		if err != nil {
   714  			return errors.New("couldn't get renter stats")
   715  		}
   716  		if len(rc.Contracts) != 1 {
   717  			return errors.New("no contracts")
   718  		}
   719  		return nil
   720  	})
   721  	if err != nil {
   722  		t.Fatal("allowance setting failed")
   723  	}
   724  
   725  	// Check the host, who should now be reporting file contracts.
   726  	//
   727  	// TODO: Switch to using an API call.
   728  	obligations := st.host.StorageObligations()
   729  	if len(obligations) != 1 {
   730  		t.Error("Host has wrong number of obligations:", len(obligations))
   731  	}
   732  
   733  	// Create a file.
   734  	path := filepath.Join(st.dir, "test.dat")
   735  	err = createRandFile(path, 1024)
   736  	if err != nil {
   737  		t.Fatal(err)
   738  	}
   739  
   740  	// Upload the file to the renter.
   741  	uploadValues := url.Values{}
   742  	uploadValues.Set("source", path)
   743  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   744  	if err != nil {
   745  		t.Fatal(err)
   746  	}
   747  	// Only one piece will be uploaded (10% at current redundancy).
   748  	var rf RenterFiles
   749  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
   750  		st.getAPI("/renter/files", &rf)
   751  		time.Sleep(100 * time.Millisecond)
   752  	}
   753  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
   754  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   755  	}
   756  
   757  	// On a second connection, upload another file.
   758  	path2 := filepath.Join(st.dir, "test2.dat")
   759  	test2Size := modules.SectorSize*2 + 1
   760  	err = createRandFile(path2, int(test2Size))
   761  	if err != nil {
   762  		t.Fatal(err)
   763  	}
   764  	uploadValues = url.Values{}
   765  	uploadValues.Set("source", path2)
   766  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
   767  	if err != nil {
   768  		t.Fatal(err)
   769  	}
   770  	// Only one piece will be uploaded (10% at current redundancy).
   771  	for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ {
   772  		st.getAPI("/renter/files", &rf)
   773  		time.Sleep(100 * time.Millisecond)
   774  	}
   775  	if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 {
   776  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1])
   777  	}
   778  
   779  	// Try downloading the first file.
   780  	downpath := filepath.Join(st.dir, "testdown.dat")
   781  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   782  	if err != nil {
   783  		t.Fatal(err)
   784  	}
   785  	// Check that the download has the right contents.
   786  	orig, err := ioutil.ReadFile(path)
   787  	if err != nil {
   788  		t.Fatal(err)
   789  	}
   790  	download, err := ioutil.ReadFile(downpath)
   791  	if err != nil {
   792  		t.Fatal(err)
   793  	}
   794  	if bytes.Compare(orig, download) != 0 {
   795  		t.Fatal("data mismatch when downloading a file")
   796  	}
   797  
   798  	// The renter's downloads queue should have 1 entry now.
   799  	var queue RenterDownloadQueue
   800  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   801  		t.Fatal(err)
   802  	}
   803  	if len(queue.Downloads) != 1 {
   804  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   805  	}
   806  
   807  	// Try downloading the second file.
   808  	downpath2 := filepath.Join(st.dir, "testdown2.dat")
   809  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath2)
   810  	if err != nil {
   811  		t.Fatal(err)
   812  	}
   813  	// Check that the download has the right contents.
   814  	orig2, err := ioutil.ReadFile(path2)
   815  	if err != nil {
   816  		t.Fatal(err)
   817  	}
   818  	download2, err := ioutil.ReadFile(downpath2)
   819  	if err != nil {
   820  		t.Fatal(err)
   821  	}
   822  	if bytes.Compare(orig2, download2) != 0 {
   823  		t.Fatal("data mismatch when downloading a file")
   824  	}
   825  
   826  	// The renter's downloads queue should have 2 entries now.
   827  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   828  		t.Fatal(err)
   829  	}
   830  	if len(queue.Downloads) != 2 {
   831  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   832  	}
   833  
   834  	// Mine two blocks, which should cause the host to submit the storage
   835  	// obligation to the blockchain.
   836  	for i := 0; i < 2; i++ {
   837  		_, err := st.miner.AddBlock()
   838  		if err != nil {
   839  			t.Fatal(err)
   840  		}
   841  		time.Sleep(time.Millisecond * 200)
   842  	}
   843  
   844  	// Check that the host was able to get the file contract confirmed on the
   845  	// blockchain.
   846  	obligations = st.host.StorageObligations()
   847  	if len(obligations) != 1 {
   848  		t.Error("Host has wrong number of obligations:", len(obligations))
   849  	}
   850  	if !obligations[0].OriginConfirmed {
   851  		t.Error("host has not seen the file contract on the blockchain")
   852  	}
   853  
   854  	// Mine blocks until the host should have submitted a storage proof.
   855  	for i := 0; i <= testPeriodInt+5; i++ {
   856  		_, err := st.miner.AddBlock()
   857  		if err != nil {
   858  			t.Fatal(err)
   859  		}
   860  		time.Sleep(time.Millisecond * 200)
   861  	}
   862  
   863  	success := false
   864  	obligations = st.host.StorageObligations()
   865  	for _, obligation := range obligations {
   866  		if obligation.ProofConfirmed {
   867  			success = true
   868  			break
   869  		}
   870  	}
   871  	if !success {
   872  		t.Error("does not seem like the host has submitted a storage proof successfully to the network")
   873  	}
   874  }
   875  
   876  // TestHostAndRentMultiHost sets up an integration test where three hosts and a
   877  // renter do basic (parallel) uploads and downloads.
   878  func TestHostAndRentMultiHost(t *testing.T) {
   879  	if testing.Short() || !build.VLONG {
   880  		t.SkipNow()
   881  	}
   882  	t.Parallel()
   883  	st, err := createServerTester(t.Name())
   884  	if err != nil {
   885  		t.Fatal(err)
   886  	}
   887  	defer st.server.panicClose()
   888  	stH1, err := blankServerTester(t.Name() + " - Host 2")
   889  	if err != nil {
   890  		t.Fatal(err)
   891  	}
   892  	defer stH1.server.panicClose()
   893  	stH2, err := blankServerTester(t.Name() + " - Host 3")
   894  	if err != nil {
   895  		t.Fatal(err)
   896  	}
   897  	defer stH2.server.panicClose()
   898  	testGroup := []*serverTester{st, stH1, stH2}
   899  
   900  	// Connect the testers to eachother so that they are all on the same
   901  	// blockchain.
   902  	err = fullyConnectNodes(testGroup)
   903  	if err != nil {
   904  		t.Fatal(err)
   905  	}
   906  
   907  	// Make sure that every wallet has money in it.
   908  	err = fundAllNodes(testGroup)
   909  	if err != nil {
   910  		t.Fatal(err)
   911  	}
   912  
   913  	// Add storage to every host.
   914  	err = addStorageToAllHosts(testGroup)
   915  	if err != nil {
   916  		t.Fatal(err)
   917  	}
   918  
   919  	// Announce every host.
   920  	err = announceAllHosts(testGroup)
   921  	if err != nil {
   922  		t.Fatal(err)
   923  	}
   924  
   925  	// Set an allowance with three hosts.
   926  	allowanceValues := url.Values{}
   927  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
   928  	allowanceValues.Set("hosts", "3")
   929  	allowanceValues.Set("period", "10")
   930  	allowanceValues.Set("renewwindow", "2")
   931  	err = st.stdPostAPI("/renter", allowanceValues)
   932  	if err != nil {
   933  		t.Fatal(err)
   934  	}
   935  
   936  	// Create a file to upload.
   937  	filesize := int(45678)
   938  	path := filepath.Join(st.dir, "test.dat")
   939  	err = createRandFile(path, filesize)
   940  	if err != nil {
   941  		t.Fatal(err)
   942  	}
   943  
   944  	// Upload a file with 2-of-6 redundancy.
   945  	uploadValues := url.Values{}
   946  	uploadValues.Set("source", path)
   947  	uploadValues.Set("datapieces", "2")
   948  	uploadValues.Set("paritypieces", "4")
   949  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
   950  	if err != nil {
   951  		t.Fatal(err)
   952  	}
   953  	// Three pieces should get uploaded.
   954  	var rf RenterFiles
   955  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50); i++ {
   956  		st.getAPI("/renter/files", &rf)
   957  		time.Sleep(100 * time.Millisecond)
   958  	}
   959  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 50 {
   960  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
   961  	}
   962  
   963  	// Try downloading the file.
   964  	downpath := filepath.Join(st.dir, "testdown.dat")
   965  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
   966  	if err != nil {
   967  		t.Fatal(err)
   968  	}
   969  	// Check that the download has the right contents.
   970  	orig, err := ioutil.ReadFile(path)
   971  	if err != nil {
   972  		t.Fatal(err)
   973  	}
   974  	download, err := ioutil.ReadFile(downpath)
   975  	if err != nil {
   976  		t.Fatal(err)
   977  	}
   978  	if bytes.Compare(orig, download) != 0 {
   979  		t.Fatal("data mismatch when downloading a file")
   980  	}
   981  
   982  	// The renter's downloads queue should have 1 entry now.
   983  	var queue RenterDownloadQueue
   984  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
   985  		t.Fatal(err)
   986  	}
   987  	if len(queue.Downloads) != 1 {
   988  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
   989  	}
   990  }
   991  
   992  // TestHostAndRentManyFiles sets up an integration test where a single renter
   993  // is uploading many files to the network.
   994  func TestHostAndRentManyFiles(t *testing.T) {
   995  	if testing.Short() || !build.VLONG {
   996  		t.SkipNow()
   997  	}
   998  	t.Parallel()
   999  	st, err := createServerTester(t.Name())
  1000  	if err != nil {
  1001  		t.Fatal(err)
  1002  	}
  1003  	defer st.server.panicClose()
  1004  	stH1, err := blankServerTester(t.Name() + " - Host 2")
  1005  	if err != nil {
  1006  		t.Fatal(err)
  1007  	}
  1008  	defer stH1.server.panicClose()
  1009  	stH2, err := blankServerTester(t.Name() + " - Host 3")
  1010  	if err != nil {
  1011  		t.Fatal(err)
  1012  	}
  1013  	defer stH2.server.panicClose()
  1014  	stH3, err := blankServerTester(t.Name() + " - Host 4")
  1015  	if err != nil {
  1016  		t.Fatal(err)
  1017  	}
  1018  	defer stH3.server.panicClose()
  1019  	testGroup := []*serverTester{st, stH1, stH2, stH3}
  1020  
  1021  	// Connect the testers to eachother so that they are all on the same
  1022  	// blockchain.
  1023  	err = fullyConnectNodes(testGroup)
  1024  	if err != nil {
  1025  		t.Fatal(err)
  1026  	}
  1027  
  1028  	// Make sure that every wallet has money in it.
  1029  	err = fundAllNodes(testGroup)
  1030  	if err != nil {
  1031  		t.Fatal(err)
  1032  	}
  1033  
  1034  	// Add storage to every host.
  1035  	err = addStorageToAllHosts(testGroup)
  1036  	if err != nil {
  1037  		t.Fatal(err)
  1038  	}
  1039  
  1040  	// Announce every host.
  1041  	err = announceAllHosts(testGroup)
  1042  	if err != nil {
  1043  		t.Fatal(err)
  1044  	}
  1045  
  1046  	// Set an allowance with four hosts.
  1047  	allowanceValues := url.Values{}
  1048  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  1049  	allowanceValues.Set("hosts", "4")
  1050  	allowanceValues.Set("period", "5")
  1051  	allowanceValues.Set("renewwindow", "2")
  1052  	err = st.stdPostAPI("/renter", allowanceValues)
  1053  	if err != nil {
  1054  		t.Fatal(err)
  1055  	}
  1056  
  1057  	// Create 3 files to upload at the same time.
  1058  	filesize1 := int(12347)
  1059  	filesize2 := int(22343)
  1060  	filesize3 := int(32349)
  1061  	path1 := filepath.Join(st.dir, "test1.dat")
  1062  	path2 := filepath.Join(st.dir, "test2.dat")
  1063  	path3 := filepath.Join(st.dir, "test3.dat")
  1064  	err = createRandFile(path1, filesize1)
  1065  	if err != nil {
  1066  		t.Fatal(err)
  1067  	}
  1068  	err = createRandFile(path2, filesize2)
  1069  	if err != nil {
  1070  		t.Fatal(err)
  1071  	}
  1072  	err = createRandFile(path3, filesize3)
  1073  	if err != nil {
  1074  		t.Fatal(err)
  1075  	}
  1076  
  1077  	// Concurrently upload a file with 1-of-4 redundancy, 2-of-4 redundancy,
  1078  	// and 3-of-4 redundancy.
  1079  	var wg sync.WaitGroup
  1080  	wg.Add(3)
  1081  	go func() {
  1082  		defer wg.Done()
  1083  		uploadValues := url.Values{}
  1084  		uploadValues.Set("source", path1)
  1085  		uploadValues.Set("datapieces", "1")
  1086  		uploadValues.Set("paritypieces", "3")
  1087  		err := st.stdPostAPI("/renter/upload/test1", uploadValues)
  1088  		if err != nil {
  1089  			t.Error(err)
  1090  		}
  1091  	}()
  1092  	go func() {
  1093  		defer wg.Done()
  1094  		uploadValues := url.Values{}
  1095  		uploadValues.Set("source", path2)
  1096  		uploadValues.Set("datapieces", "2")
  1097  		uploadValues.Set("paritypieces", "2")
  1098  		err := st.stdPostAPI("/renter/upload/test2", uploadValues)
  1099  		if err != nil {
  1100  			t.Error(err)
  1101  		}
  1102  	}()
  1103  	go func() {
  1104  		defer wg.Done()
  1105  		uploadValues := url.Values{}
  1106  		uploadValues.Set("source", path3)
  1107  		uploadValues.Set("datapieces", "3")
  1108  		uploadValues.Set("paritypieces", "1")
  1109  		err := st.stdPostAPI("/renter/upload/test3", uploadValues)
  1110  		if err != nil {
  1111  			t.Error(err)
  1112  		}
  1113  	}()
  1114  
  1115  	// Block until the upload call is complete for all three files.
  1116  	wg.Wait()
  1117  
  1118  	// Block until all files hit 100% uploaded.
  1119  	var rf RenterFiles
  1120  	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++ {
  1121  		st.getAPI("/renter/files", &rf)
  1122  		time.Sleep(500 * time.Millisecond)
  1123  	}
  1124  	if len(rf.Files) != 3 || rf.Files[0].UploadProgress < 100 || rf.Files[1].UploadProgress < 100 || rf.Files[2].UploadProgress < 100 {
  1125  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1], rf.Files[2])
  1126  	}
  1127  
  1128  	// Download all three files in parallel.
  1129  	wg.Add(3)
  1130  	go func() {
  1131  		defer wg.Done()
  1132  		downpath := filepath.Join(st.dir, "testdown1.dat")
  1133  		err := st.stdGetAPI("/renter/download/test1?destination=" + downpath)
  1134  		if err != nil {
  1135  			t.Error(err)
  1136  		}
  1137  		// Check that the download has the right contents.
  1138  		orig, err := ioutil.ReadFile(path1)
  1139  		if err != nil {
  1140  			t.Error(err)
  1141  		}
  1142  		download, err := ioutil.ReadFile(downpath)
  1143  		if err != nil {
  1144  			t.Error(err)
  1145  		}
  1146  		if bytes.Compare(orig, download) != 0 {
  1147  			t.Error("data mismatch when downloading a file")
  1148  		}
  1149  	}()
  1150  	go func() {
  1151  		defer wg.Done()
  1152  		downpath := filepath.Join(st.dir, "testdown2.dat")
  1153  		err := st.stdGetAPI("/renter/download/test2?destination=" + downpath)
  1154  		if err != nil {
  1155  			t.Error(err)
  1156  		}
  1157  		// Check that the download has the right contents.
  1158  		orig, err := ioutil.ReadFile(path2)
  1159  		if err != nil {
  1160  			t.Error(err)
  1161  		}
  1162  		download, err := ioutil.ReadFile(downpath)
  1163  		if err != nil {
  1164  			t.Error(err)
  1165  		}
  1166  		if bytes.Compare(orig, download) != 0 {
  1167  			t.Error("data mismatch when downloading a file")
  1168  		}
  1169  	}()
  1170  	go func() {
  1171  		defer wg.Done()
  1172  		downpath := filepath.Join(st.dir, "testdown3.dat")
  1173  		err := st.stdGetAPI("/renter/download/test3?destination=" + downpath)
  1174  		if err != nil {
  1175  			t.Error(err)
  1176  		}
  1177  		// Check that the download has the right contents.
  1178  		orig, err := ioutil.ReadFile(path3)
  1179  		if err != nil {
  1180  			t.Error(err)
  1181  		}
  1182  		download, err := ioutil.ReadFile(downpath)
  1183  		if err != nil {
  1184  			t.Error(err)
  1185  		}
  1186  		if bytes.Compare(orig, download) != 0 {
  1187  			t.Error("data mismatch when downloading a file")
  1188  		}
  1189  	}()
  1190  	wg.Wait()
  1191  
  1192  	// The renter's downloads queue should have 3 entries now.
  1193  	var queue RenterDownloadQueue
  1194  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
  1195  		t.Fatal(err)
  1196  	}
  1197  	if len(queue.Downloads) != 3 {
  1198  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
  1199  	}
  1200  }
  1201  
  1202  // TestRenterUploadDownload tests that downloading and uploading in parallel
  1203  // does not result in failures or stalling.
  1204  func TestRenterUploadDownload(t *testing.T) {
  1205  	if testing.Short() {
  1206  		t.SkipNow()
  1207  	}
  1208  	st, err := createServerTester(t.Name())
  1209  	if err != nil {
  1210  		t.Fatal(err)
  1211  	}
  1212  	defer st.server.panicClose()
  1213  
  1214  	// Announce the host and start accepting contracts.
  1215  	err = st.announceHost()
  1216  	if err != nil {
  1217  		t.Fatal(err)
  1218  	}
  1219  	err = st.acceptContracts()
  1220  	if err != nil {
  1221  		t.Fatal(err)
  1222  	}
  1223  	err = st.setHostStorage()
  1224  	if err != nil {
  1225  		t.Fatal(err)
  1226  	}
  1227  
  1228  	// Set an allowance for the renter, allowing a contract to be formed.
  1229  	allowanceValues := url.Values{}
  1230  	testFunds := "10000000000000000000000000000" // 10k SC
  1231  	testPeriod := "10"
  1232  	allowanceValues.Set("funds", testFunds)
  1233  	allowanceValues.Set("period", testPeriod)
  1234  	allowanceValues.Set("renewwindow", testRenewWindow)
  1235  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1236  	err = st.stdPostAPI("/renter", allowanceValues)
  1237  	if err != nil {
  1238  		t.Fatal(err)
  1239  	}
  1240  
  1241  	// Block until the allowance has finished forming contracts.
  1242  	err = build.Retry(50, time.Millisecond*250, func() error {
  1243  		var rc RenterContracts
  1244  		err = st.getAPI("/renter/contracts", &rc)
  1245  		if err != nil {
  1246  			return errors.New("couldn't get renter stats")
  1247  		}
  1248  		if len(rc.Contracts) != 1 {
  1249  			return errors.New("no contracts")
  1250  		}
  1251  		return nil
  1252  	})
  1253  	if err != nil {
  1254  		t.Fatal("allowance setting failed")
  1255  	}
  1256  
  1257  	// Check financial metrics; coins should have been spent on contracts
  1258  	var rg RenterGET
  1259  	err = st.getAPI("/renter", &rg)
  1260  	if err != nil {
  1261  		t.Fatal(err)
  1262  	}
  1263  	spent := rg.Settings.Allowance.Funds.Sub(rg.FinancialMetrics.Unspent)
  1264  	if spent.IsZero() {
  1265  		t.Fatal("financial metrics do not reflect contract spending")
  1266  	}
  1267  
  1268  	// Create a file.
  1269  	path := filepath.Join(st.dir, "test.dat")
  1270  	err = createRandFile(path, 1024)
  1271  	if err != nil {
  1272  		t.Fatal(err)
  1273  	}
  1274  
  1275  	// Upload to host.
  1276  	uploadValues := url.Values{}
  1277  	uploadValues.Set("source", path)
  1278  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1279  	if err != nil {
  1280  		t.Fatal(err)
  1281  	}
  1282  	// Only one piece will be uploaded (10% at current redundancy).
  1283  	var rf RenterFiles
  1284  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1285  		st.getAPI("/renter/files", &rf)
  1286  		time.Sleep(100 * time.Millisecond)
  1287  	}
  1288  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1289  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1290  	}
  1291  
  1292  	// In parallel, upload another file and download the first file.
  1293  	path2 := filepath.Join(st.dir, "test2.dat")
  1294  	test2Size := modules.SectorSize*2 + 1
  1295  	err = createRandFile(path2, int(test2Size))
  1296  	if err != nil {
  1297  		t.Fatal(err)
  1298  	}
  1299  	uploadValues = url.Values{}
  1300  	uploadValues.Set("source", path2)
  1301  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
  1302  	if err != nil {
  1303  		t.Fatal(err)
  1304  	}
  1305  	downpath := filepath.Join(st.dir, "testdown.dat")
  1306  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1307  	if err != nil {
  1308  		t.Fatal(err)
  1309  	}
  1310  	// Check that the download has the right contents.
  1311  	orig, err := ioutil.ReadFile(path)
  1312  	if err != nil {
  1313  		t.Fatal(err)
  1314  	}
  1315  	download, err := ioutil.ReadFile(downpath)
  1316  	if err != nil {
  1317  		t.Fatal(err)
  1318  	}
  1319  	if bytes.Compare(orig, download) != 0 {
  1320  		t.Fatal("data mismatch when downloading a file")
  1321  	}
  1322  
  1323  	// Wait for upload to complete.
  1324  	for i := 0; i < 200 && (len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10); i++ {
  1325  		st.getAPI("/renter/files", &rf)
  1326  		time.Sleep(100 * time.Millisecond)
  1327  	}
  1328  	if len(rf.Files) != 2 || rf.Files[0].UploadProgress < 10 || rf.Files[1].UploadProgress < 10 {
  1329  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0], rf.Files[1])
  1330  	}
  1331  
  1332  	// Check financial metrics; funds should have been spent on uploads/downloads
  1333  	err = st.getAPI("/renter", &rg)
  1334  	if err != nil {
  1335  		t.Fatal(err)
  1336  	}
  1337  	fm := rg.FinancialMetrics
  1338  	newSpent := rg.Settings.Allowance.Funds.Sub(fm.Unspent)
  1339  	// all new spending should be reflected in upload/download/storage spending
  1340  	diff := fm.UploadSpending.Add(fm.DownloadSpending).Add(fm.StorageSpending)
  1341  	if !diff.Equals(newSpent.Sub(spent)) {
  1342  		t.Fatal("all new spending should be reflected in metrics:", diff, newSpent.Sub(spent))
  1343  	}
  1344  }
  1345  
  1346  // TestRenterCancelAllowance tests that setting an empty allowance causes
  1347  // uploads, downloads, and renewals to cease.
  1348  func TestRenterCancelAllowance(t *testing.T) {
  1349  	if testing.Short() {
  1350  		t.SkipNow()
  1351  	}
  1352  	st, err := createServerTester(t.Name())
  1353  	if err != nil {
  1354  		t.Fatal(err)
  1355  	}
  1356  	defer st.server.panicClose()
  1357  
  1358  	// Announce the host and start accepting contracts.
  1359  	err = st.announceHost()
  1360  	if err != nil {
  1361  		t.Fatal(err)
  1362  	}
  1363  	err = st.setHostStorage()
  1364  	if err != nil {
  1365  		t.Fatal(err)
  1366  	}
  1367  	err = st.acceptContracts()
  1368  	if err != nil {
  1369  		t.Fatal(err)
  1370  	}
  1371  
  1372  	// Set an allowance for the renter, allowing a contract to be formed.
  1373  	allowanceValues := url.Values{}
  1374  	testFunds := "10000000000000000000000000000" // 10k SC
  1375  	testPeriod := "20"
  1376  	allowanceValues.Set("funds", testFunds)
  1377  	allowanceValues.Set("period", testPeriod)
  1378  	allowanceValues.Set("renewwindow", testRenewWindow)
  1379  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1380  	err = st.stdPostAPI("/renter", allowanceValues)
  1381  	if err != nil {
  1382  		t.Fatal(err)
  1383  	}
  1384  
  1385  	// Block until the allowance has finished forming contracts.
  1386  	err = build.Retry(50, time.Millisecond*250, func() error {
  1387  		var rc RenterContracts
  1388  		err = st.getAPI("/renter/contracts", &rc)
  1389  		if err != nil {
  1390  			return errors.New("couldn't get renter stats")
  1391  		}
  1392  		if len(rc.Contracts) != 1 {
  1393  			return errors.New("no contracts")
  1394  		}
  1395  		return nil
  1396  	})
  1397  	if err != nil {
  1398  		t.Fatal("allowance setting failed")
  1399  	}
  1400  
  1401  	// Create a file.
  1402  	path := filepath.Join(st.dir, "test.dat")
  1403  	err = createRandFile(path, 1024)
  1404  	if err != nil {
  1405  		t.Fatal(err)
  1406  	}
  1407  
  1408  	// Upload the file to the renter.
  1409  	uploadValues := url.Values{}
  1410  	uploadValues.Set("source", path)
  1411  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1412  	if err != nil {
  1413  		t.Fatal(err)
  1414  	}
  1415  	// Only one piece will be uploaded (10% at current redundancy).
  1416  	var rf RenterFiles
  1417  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1418  		st.getAPI("/renter/files", &rf)
  1419  		time.Sleep(100 * time.Millisecond)
  1420  	}
  1421  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1422  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1423  	}
  1424  
  1425  	// Cancel the allowance
  1426  	allowanceValues = url.Values{}
  1427  	allowanceValues.Set("funds", "0")
  1428  	allowanceValues.Set("hosts", "0")
  1429  	allowanceValues.Set("period", "0")
  1430  	allowanceValues.Set("renewwindow", "0")
  1431  	err = st.stdPostAPI("/renter", allowanceValues)
  1432  	if err != nil {
  1433  		t.Fatal(err)
  1434  	}
  1435  
  1436  	// Try downloading the file; should fail
  1437  	downpath := filepath.Join(st.dir, "testdown.dat")
  1438  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1439  	if err == nil || !strings.Contains(err.Error(), "download failed") {
  1440  		t.Fatal("expected insufficient hosts error, got", err)
  1441  	}
  1442  }
  1443  
  1444  // TestRenterParallelDelete tests that uploading and deleting parallel does not
  1445  // result in failures or stalling.
  1446  func TestRenterParallelDelete(t *testing.T) {
  1447  	if testing.Short() {
  1448  		t.SkipNow()
  1449  	}
  1450  	st, err := createServerTester(t.Name())
  1451  	if err != nil {
  1452  		t.Fatal(err)
  1453  	}
  1454  	defer st.server.panicClose()
  1455  
  1456  	// Announce the host and start accepting contracts.
  1457  	err = st.announceHost()
  1458  	if err != nil {
  1459  		t.Fatal(err)
  1460  	}
  1461  	err = st.acceptContracts()
  1462  	if err != nil {
  1463  		t.Fatal(err)
  1464  	}
  1465  	err = st.setHostStorage()
  1466  	if err != nil {
  1467  		t.Fatal(err)
  1468  	}
  1469  
  1470  	// Set an allowance for the renter, allowing a contract to be formed.
  1471  	allowanceValues := url.Values{}
  1472  	testFunds := "10000000000000000000000000000" // 10k SC
  1473  	testPeriod := "10"
  1474  	allowanceValues.Set("funds", testFunds)
  1475  	allowanceValues.Set("period", testPeriod)
  1476  	allowanceValues.Set("renewwindow", testRenewWindow)
  1477  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1478  	err = st.stdPostAPI("/renter", allowanceValues)
  1479  	if err != nil {
  1480  		t.Fatal(err)
  1481  	}
  1482  
  1483  	// Create two files.
  1484  	path := filepath.Join(st.dir, "test.dat")
  1485  	err = createRandFile(path, 1024)
  1486  	if err != nil {
  1487  		t.Fatal(err)
  1488  	}
  1489  	path2 := filepath.Join(st.dir, "test2.dat")
  1490  	err = createRandFile(path2, 1024)
  1491  	if err != nil {
  1492  		t.Fatal(err)
  1493  	}
  1494  
  1495  	// Upload the first file to host.
  1496  	uploadValues := url.Values{}
  1497  	uploadValues.Set("source", path)
  1498  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1499  	if err != nil {
  1500  		t.Fatal(err)
  1501  	}
  1502  	// Wait for the first file to be registered in the renter.
  1503  	var rf RenterFiles
  1504  	for i := 0; i < 200 && len(rf.Files) != 1; i++ {
  1505  		st.getAPI("/renter/files", &rf)
  1506  		time.Sleep(100 * time.Millisecond)
  1507  	}
  1508  	if len(rf.Files) != 1 {
  1509  		t.Fatal("file is not being registered:", rf.Files)
  1510  	}
  1511  
  1512  	// In parallel, start uploading the other file, and delete the first file.
  1513  	uploadValues = url.Values{}
  1514  	uploadValues.Set("source", path2)
  1515  	err = st.stdPostAPI("/renter/upload/test2", uploadValues)
  1516  	if err != nil {
  1517  		t.Fatal(err)
  1518  	}
  1519  
  1520  	err = st.stdPostAPI("/renter/delete/test", url.Values{})
  1521  	if err != nil {
  1522  		t.Fatal(err)
  1523  	}
  1524  	// Only the second file should be present
  1525  	st.getAPI("/renter/files", &rf)
  1526  	if len(rf.Files) != 1 || rf.Files[0].SiaPath != "test2" {
  1527  		t.Fatal("file was not deleted properly:", rf.Files)
  1528  	}
  1529  
  1530  	// Wait for the second upload to complete.
  1531  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1532  		st.getAPI("/renter/files", &rf)
  1533  		time.Sleep(100 * time.Millisecond)
  1534  	}
  1535  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1536  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files)
  1537  	}
  1538  
  1539  	// In parallel, download and delete the second file.
  1540  	go st.stdPostAPI("/renter/delete/test2", url.Values{})
  1541  	time.Sleep(100 * time.Millisecond)
  1542  	downpath := filepath.Join(st.dir, "testdown.dat")
  1543  	err = st.stdGetAPI("/renter/download/test2?destination=" + downpath)
  1544  	if err == nil {
  1545  		t.Fatal("download should fail after delete")
  1546  	}
  1547  
  1548  	// No files should be present
  1549  	st.getAPI("/renter/files", &rf)
  1550  	if len(rf.Files) != 0 {
  1551  		t.Fatal("file was not deleted properly:", rf.Files)
  1552  	}
  1553  }
  1554  
  1555  // TestRenterRenew sets up an integration test where a renter renews a
  1556  // contract with a host.
  1557  func TestRenterRenew(t *testing.T) {
  1558  	if testing.Short() {
  1559  		t.SkipNow()
  1560  	}
  1561  	st, err := createServerTester(t.Name())
  1562  	if err != nil {
  1563  		t.Fatal(err)
  1564  	}
  1565  	defer st.server.panicClose()
  1566  
  1567  	// Announce the host and start accepting contracts.
  1568  	err = st.announceHost()
  1569  	if err != nil {
  1570  		t.Fatal(err)
  1571  	}
  1572  	err = st.acceptContracts()
  1573  	if err != nil {
  1574  		t.Fatal(err)
  1575  	}
  1576  	err = st.setHostStorage()
  1577  	if err != nil {
  1578  		t.Fatal(err)
  1579  	}
  1580  	var ah HostdbActiveGET
  1581  	for i := 0; i < 50; i++ {
  1582  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  1583  			t.Fatal(err)
  1584  		}
  1585  		if len(ah.Hosts) == 1 {
  1586  			break
  1587  		}
  1588  		time.Sleep(time.Millisecond * 100)
  1589  	}
  1590  	if len(ah.Hosts) != 1 {
  1591  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
  1592  	}
  1593  
  1594  	// Set an allowance for the renter, allowing a contract to be formed.
  1595  	allowanceValues := url.Values{}
  1596  	testFunds := "10000000000000000000000000000" // 10k SC
  1597  	testPeriod := 10
  1598  	allowanceValues.Set("funds", testFunds)
  1599  	allowanceValues.Set("period", strconv.Itoa(testPeriod))
  1600  	allowanceValues.Set("renewwindow", strconv.Itoa(testPeriod/2))
  1601  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1602  	err = st.stdPostAPI("/renter", allowanceValues)
  1603  	if err != nil {
  1604  		t.Fatal(err)
  1605  	}
  1606  
  1607  	// Block until the allowance has finished forming contracts.
  1608  	err = build.Retry(50, time.Millisecond*250, func() error {
  1609  		var rc RenterContracts
  1610  		err = st.getAPI("/renter/contracts", &rc)
  1611  		if err != nil {
  1612  			return errors.New("couldn't get renter stats")
  1613  		}
  1614  		if len(rc.Contracts) != 1 {
  1615  			return errors.New("no contracts")
  1616  		}
  1617  		return nil
  1618  	})
  1619  	if err != nil {
  1620  		t.Fatal("allowance setting failed")
  1621  	}
  1622  
  1623  	// Create a file.
  1624  	path := filepath.Join(st.dir, "test.dat")
  1625  	err = createRandFile(path, 1024)
  1626  	if err != nil {
  1627  		t.Fatal(err)
  1628  	}
  1629  
  1630  	// Upload the file to the renter.
  1631  	uploadValues := url.Values{}
  1632  	uploadValues.Set("source", path)
  1633  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1634  	if err != nil {
  1635  		t.Fatal(err)
  1636  	}
  1637  	// Only one piece will be uploaded (10% at current redundancy).
  1638  	var rf RenterFiles
  1639  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1640  		st.getAPI("/renter/files", &rf)
  1641  		time.Sleep(100 * time.Millisecond)
  1642  	}
  1643  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1644  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1645  	}
  1646  
  1647  	// Get current contract ID.
  1648  	var rc RenterContracts
  1649  	err = st.getAPI("/renter/contracts", &rc)
  1650  	if err != nil {
  1651  		t.Fatal(err)
  1652  	}
  1653  	contractID := rc.Contracts[0].ID
  1654  
  1655  	// Mine enough blocks to enter the renewal window.
  1656  	testWindow := testPeriod / 2
  1657  	for i := 0; i < testWindow+1; i++ {
  1658  		_, err = st.miner.AddBlock()
  1659  		if err != nil {
  1660  			t.Fatal(err)
  1661  		}
  1662  	}
  1663  	// Wait for the contract to be renewed.
  1664  	for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ {
  1665  		st.getAPI("/renter/contracts", &rc)
  1666  		time.Sleep(100 * time.Millisecond)
  1667  	}
  1668  	if rc.Contracts[0].ID == contractID {
  1669  		t.Fatal("contract was not renewed:", rc.Contracts[0])
  1670  	}
  1671  
  1672  	// Try downloading the file.
  1673  	downpath := filepath.Join(st.dir, "testdown.dat")
  1674  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1675  	if err != nil {
  1676  		t.Fatal(err)
  1677  	}
  1678  	// Check that the download has the right contents.
  1679  	orig, err := ioutil.ReadFile(path)
  1680  	if err != nil {
  1681  		t.Fatal(err)
  1682  	}
  1683  	download, err := ioutil.ReadFile(downpath)
  1684  	if err != nil {
  1685  		t.Fatal(err)
  1686  	}
  1687  	if bytes.Compare(orig, download) != 0 {
  1688  		t.Fatal("data mismatch when downloading a file")
  1689  	}
  1690  }
  1691  
  1692  // TestRenterAllowance sets up an integration test where a renter attempts to
  1693  // download a file after changing the allowance.
  1694  func TestRenterAllowance(t *testing.T) {
  1695  	t.Skip("bypassing NDF")
  1696  	if testing.Short() {
  1697  		t.SkipNow()
  1698  	}
  1699  	t.Parallel()
  1700  
  1701  	st, err := createServerTester(t.Name())
  1702  	if err != nil {
  1703  		t.Fatal(err)
  1704  	}
  1705  	defer st.server.panicClose()
  1706  
  1707  	// Announce the host and start accepting contracts.
  1708  	err = st.announceHost()
  1709  	if err != nil {
  1710  		t.Fatal(err)
  1711  	}
  1712  	err = st.acceptContracts()
  1713  	if err != nil {
  1714  		t.Fatal(err)
  1715  	}
  1716  	err = st.setHostStorage()
  1717  	if err != nil {
  1718  		t.Fatal(err)
  1719  	}
  1720  
  1721  	// Set an allowance for the renter, allowing a contract to be formed.
  1722  	allowanceValues := url.Values{}
  1723  	testFunds := types.SiacoinPrecision.Mul64(10000) // 10k SC
  1724  	testPeriod := 20
  1725  	allowanceValues.Set("funds", testFunds.String())
  1726  	allowanceValues.Set("period", strconv.Itoa(testPeriod))
  1727  	err = st.stdPostAPI("/renter", allowanceValues)
  1728  	if err != nil {
  1729  		t.Fatal(err)
  1730  	}
  1731  
  1732  	// Create a file.
  1733  	path := filepath.Join(st.dir, "test.dat")
  1734  	err = createRandFile(path, 1024)
  1735  	if err != nil {
  1736  		t.Fatal(err)
  1737  	}
  1738  
  1739  	// Upload the file to the renter.
  1740  	uploadValues := url.Values{}
  1741  	uploadValues.Set("source", path)
  1742  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1743  	if err != nil {
  1744  		t.Fatal(err)
  1745  	}
  1746  	// Only one piece will be uploaded (10% at current redundancy).
  1747  	var rf RenterFiles
  1748  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1749  		st.getAPI("/renter/files", &rf)
  1750  		time.Sleep(100 * time.Millisecond)
  1751  	}
  1752  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1753  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1754  	}
  1755  
  1756  	t.Skip("ndf - re-enable after contractor overhaul")
  1757  
  1758  	// Try downloading the file after modifying the allowance in various ways.
  1759  	allowances := []struct {
  1760  		funds  types.Currency
  1761  		period int
  1762  	}{
  1763  		{testFunds.Mul64(10), testPeriod / 2},
  1764  		{testFunds, testPeriod / 2},
  1765  		{testFunds.Div64(10), testPeriod / 2},
  1766  		{testFunds.Mul64(10), testPeriod},
  1767  		{testFunds, testPeriod},
  1768  		{testFunds.Div64(10), testPeriod},
  1769  		{testFunds.Mul64(10), testPeriod * 2},
  1770  		{testFunds, testPeriod * 2},
  1771  		{testFunds.Div64(10), testPeriod * 2},
  1772  	}
  1773  
  1774  	for _, a := range allowances {
  1775  		allowanceValues.Set("funds", a.funds.String())
  1776  		allowanceValues.Set("period", strconv.Itoa(a.period))
  1777  		err = st.stdPostAPI("/renter", allowanceValues)
  1778  		if err != nil {
  1779  			t.Fatal(err)
  1780  		}
  1781  		time.Sleep(100 * time.Millisecond)
  1782  
  1783  		// Try downloading the file.
  1784  		downpath := filepath.Join(st.dir, "testdown.dat")
  1785  		err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1786  		if err != nil {
  1787  			t.Fatal(err)
  1788  		}
  1789  		// Check that the download has the right contents.
  1790  		orig, err := ioutil.ReadFile(path)
  1791  		if err != nil {
  1792  			t.Fatal(err)
  1793  		}
  1794  		download, err := ioutil.ReadFile(downpath)
  1795  		if err != nil {
  1796  			t.Fatal(err)
  1797  		}
  1798  		if bytes.Compare(orig, download) != 0 {
  1799  			t.Fatal("data mismatch when downloading a file")
  1800  		}
  1801  	}
  1802  }
  1803  
  1804  // TestHostAndRentReload sets up an integration test where a host and renter
  1805  // do basic uploads and downloads, with an intervening shutdown+startup.
  1806  func TestHostAndRentReload(t *testing.T) {
  1807  	if testing.Short() {
  1808  		t.SkipNow()
  1809  	}
  1810  	t.Parallel()
  1811  	st, err := createServerTester(t.Name())
  1812  	if err != nil {
  1813  		t.Fatal(err)
  1814  	}
  1815  
  1816  	// Announce the host and start accepting contracts.
  1817  	err = st.announceHost()
  1818  	if err != nil {
  1819  		t.Fatal(err)
  1820  	}
  1821  	err = st.acceptContracts()
  1822  	if err != nil {
  1823  		t.Fatal(err)
  1824  	}
  1825  	err = st.setHostStorage()
  1826  	if err != nil {
  1827  		t.Fatal(err)
  1828  	}
  1829  	// Mine a block so that the wallet reclaims refund outputs
  1830  	_, err = st.miner.AddBlock()
  1831  	if err != nil {
  1832  		t.Fatal(err)
  1833  	}
  1834  
  1835  	// Set an allowance for the renter, allowing a contract to be formed.
  1836  	allowanceValues := url.Values{}
  1837  	testFunds := "10000000000000000000000000000" // 10k SC
  1838  	testPeriod := "10"
  1839  	allowanceValues.Set("funds", testFunds)
  1840  	allowanceValues.Set("period", testPeriod)
  1841  	allowanceValues.Set("renewwindow", testRenewWindow)
  1842  	allowanceValues.Set("hosts", fmt.Sprint(recommendedHosts))
  1843  	err = st.stdPostAPI("/renter", allowanceValues)
  1844  	if err != nil {
  1845  		t.Fatal(err)
  1846  	}
  1847  
  1848  	// Block until the allowance has finished forming contracts.
  1849  	err = build.Retry(50, time.Millisecond*250, func() error {
  1850  		var rc RenterContracts
  1851  		err = st.getAPI("/renter/contracts", &rc)
  1852  		if err != nil {
  1853  			return errors.New("couldn't get renter stats")
  1854  		}
  1855  		if len(rc.Contracts) != 1 {
  1856  			return errors.New("no contracts")
  1857  		}
  1858  		return nil
  1859  	})
  1860  	if err != nil {
  1861  		t.Fatal("allowance setting failed")
  1862  	}
  1863  
  1864  	// Create a file.
  1865  	path := filepath.Join(st.dir, "test.dat")
  1866  	err = createRandFile(path, 1024)
  1867  	if err != nil {
  1868  		t.Fatal(err)
  1869  	}
  1870  
  1871  	// Upload the file to the renter.
  1872  	uploadValues := url.Values{}
  1873  	uploadValues.Set("source", path)
  1874  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  1875  	if err != nil {
  1876  		t.Fatal(err)
  1877  	}
  1878  	// Only one piece will be uploaded (10% at current redundancy).
  1879  	var rf RenterFiles
  1880  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  1881  		st.getAPI("/renter/files", &rf)
  1882  		time.Sleep(100 * time.Millisecond)
  1883  	}
  1884  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  1885  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  1886  	}
  1887  
  1888  	// Try downloading the file.
  1889  	downpath := filepath.Join(st.dir, "testdown.dat")
  1890  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1891  	if err != nil {
  1892  		t.Fatal(err)
  1893  	}
  1894  	// Check that the download has the right contents.
  1895  	orig, err := ioutil.ReadFile(path)
  1896  	if err != nil {
  1897  		t.Fatal(err)
  1898  	}
  1899  	download, err := ioutil.ReadFile(downpath)
  1900  	if err != nil {
  1901  		t.Fatal(err)
  1902  	}
  1903  	if bytes.Compare(orig, download) != 0 {
  1904  		t.Fatal("data mismatch when downloading a file")
  1905  	}
  1906  
  1907  	// The renter's downloads queue should have 1 entry now.
  1908  	var queue RenterDownloadQueue
  1909  	if err = st.getAPI("/renter/downloads", &queue); err != nil {
  1910  		t.Fatal(err)
  1911  	}
  1912  	if len(queue.Downloads) != 1 {
  1913  		t.Fatalf("expected renter to have 1 download in the queue; got %v", len(queue.Downloads))
  1914  	}
  1915  
  1916  	// close and reopen the server
  1917  	err = st.server.Close()
  1918  	if err != nil {
  1919  		t.Fatal(err)
  1920  	}
  1921  	st, err = assembleServerTester(st.walletKey, st.dir)
  1922  	if err != nil {
  1923  		t.Fatal(err)
  1924  	}
  1925  	defer st.server.panicClose()
  1926  
  1927  	// Announce the host again and wait until the host is re-scanned and put
  1928  	// back into the hostdb as an active host.
  1929  	announceValues := url.Values{}
  1930  	announceValues.Set("address", string(st.host.ExternalSettings().NetAddress))
  1931  	err = st.stdPostAPI("/host/announce", announceValues)
  1932  	if err != nil {
  1933  		t.Fatal(err)
  1934  	}
  1935  	// Mine a block.
  1936  	_, err = st.miner.AddBlock()
  1937  	if err != nil {
  1938  		t.Fatal(err)
  1939  	}
  1940  	err = retry(100, time.Millisecond*100, func() error {
  1941  		var hosts HostdbActiveGET
  1942  		err := st.getAPI("/hostdb/active", &hosts)
  1943  		if err != nil {
  1944  			return err
  1945  		}
  1946  		if len(hosts.Hosts) != 1 {
  1947  			return errors.New("host is not in the set of active hosts")
  1948  		}
  1949  		return nil
  1950  	})
  1951  	if err != nil {
  1952  		t.Fatal(err)
  1953  	}
  1954  
  1955  	// Try downloading the file.
  1956  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  1957  	if err != nil {
  1958  		t.Fatal(err)
  1959  	}
  1960  	// Check that the download has the right contents.
  1961  	orig, err = ioutil.ReadFile(path)
  1962  	if err != nil {
  1963  		t.Fatal(err)
  1964  	}
  1965  	download, err = ioutil.ReadFile(downpath)
  1966  	if err != nil {
  1967  		t.Fatal(err)
  1968  	}
  1969  	if bytes.Compare(orig, download) != 0 {
  1970  		t.Fatal("data mismatch when downloading a file")
  1971  	}
  1972  }
  1973  
  1974  // TestHostAndRenterRenewInterrupt
  1975  func TestHostAndRenterRenewInterrupt(t *testing.T) {
  1976  	t.Skip("active test following contractor overhaul")
  1977  	if testing.Short() {
  1978  		t.SkipNow()
  1979  	}
  1980  	t.Parallel()
  1981  	st, err := createServerTester(t.Name())
  1982  	if err != nil {
  1983  		t.Fatal(err)
  1984  	}
  1985  	stHost, err := blankServerTester(t.Name() + "-Host")
  1986  	if err != nil {
  1987  		t.Fatal(err)
  1988  	}
  1989  	sts := []*serverTester{st, stHost}
  1990  	err = fullyConnectNodes(sts)
  1991  	if err != nil {
  1992  		t.Fatal(err)
  1993  	}
  1994  	err = fundAllNodes(sts)
  1995  	if err != nil {
  1996  		t.Fatal(err)
  1997  	}
  1998  
  1999  	// Announce the host.
  2000  	err = stHost.acceptContracts()
  2001  	if err != nil {
  2002  		t.Fatal(err)
  2003  	}
  2004  	err = stHost.setHostStorage()
  2005  	if err != nil {
  2006  		t.Fatal(err)
  2007  	}
  2008  	err = stHost.announceHost()
  2009  	if err != nil {
  2010  		t.Fatal(err)
  2011  	}
  2012  
  2013  	// Wait for host to be seen in renter's hostdb
  2014  	var ah HostdbActiveGET
  2015  	for i := 0; i < 50; i++ {
  2016  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  2017  			t.Fatal(err)
  2018  		}
  2019  		if len(ah.Hosts) == 1 {
  2020  			break
  2021  		}
  2022  		time.Sleep(time.Millisecond * 100)
  2023  	}
  2024  	if len(ah.Hosts) != 1 {
  2025  		t.Fatalf("expected 1 host, got %v", len(ah.Hosts))
  2026  	}
  2027  
  2028  	// Upload a file to the host.
  2029  	allowanceValues := url.Values{}
  2030  	testFunds := "10000000000000000000000000000" // 10k SC
  2031  	testPeriod := "10"
  2032  	testPeriodInt := 10
  2033  	allowanceValues.Set("funds", testFunds)
  2034  	allowanceValues.Set("period", testPeriod)
  2035  	err = st.stdPostAPI("/renter", allowanceValues)
  2036  	if err != nil {
  2037  		t.Fatal(err)
  2038  	}
  2039  	// Create a file.
  2040  	path := filepath.Join(st.dir, "test.dat")
  2041  	err = createRandFile(path, 10e3)
  2042  	if err != nil {
  2043  		t.Fatal(err)
  2044  	}
  2045  	// Upload the file to the renter.
  2046  	uploadValues := url.Values{}
  2047  	uploadValues.Set("source", path)
  2048  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  2049  	if err != nil {
  2050  		t.Fatal(err)
  2051  	}
  2052  
  2053  	// Get current contract ID.
  2054  	var rc RenterContracts
  2055  	err = st.getAPI("/renter/contracts", &rc)
  2056  	if err != nil {
  2057  		t.Fatal(err)
  2058  	}
  2059  	contractID := rc.Contracts[0].ID
  2060  
  2061  	// Mine enough blocks to enter the renewal window.
  2062  	testWindow := testPeriodInt / 2
  2063  	for i := 0; i < testWindow+1; i++ {
  2064  		_, err = st.miner.AddBlock()
  2065  		if err != nil {
  2066  			t.Fatal(err)
  2067  		}
  2068  	}
  2069  	// Wait for the contract to be renewed.
  2070  	for i := 0; i < 200 && (len(rc.Contracts) != 1 || rc.Contracts[0].ID == contractID); i++ {
  2071  		st.getAPI("/renter/contracts", &rc)
  2072  		time.Sleep(100 * time.Millisecond)
  2073  	}
  2074  	if rc.Contracts[0].ID == contractID {
  2075  		t.Fatal("contract was not renewed:", rc.Contracts[0])
  2076  	}
  2077  
  2078  	// Only one piece will be uploaded (10% at current redundancy).
  2079  	var rf RenterFiles
  2080  	for i := 0; i < 200 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10); i++ {
  2081  		st.getAPI("/renter/files", &rf)
  2082  		time.Sleep(1000 * time.Millisecond)
  2083  	}
  2084  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 10 {
  2085  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  2086  	}
  2087  
  2088  	// Try downloading the file.
  2089  	downpath := filepath.Join(st.dir, "testdown.dat")
  2090  	err = st.stdGetAPI("/renter/download/test?destination=" + downpath)
  2091  	if err != nil {
  2092  		t.Fatal(err)
  2093  	}
  2094  	// Check that the download has the right contents.
  2095  	orig, err := ioutil.ReadFile(path)
  2096  	if err != nil {
  2097  		t.Fatal(err)
  2098  	}
  2099  	download, err := ioutil.ReadFile(downpath)
  2100  	if err != nil {
  2101  		t.Fatal(err)
  2102  	}
  2103  	if bytes.Compare(orig, download) != 0 {
  2104  		t.Fatal("data mismatch when downloading a file")
  2105  	}
  2106  }
  2107  
  2108  // TestRedundancyReporting verifies that redundancy reporting is accurate if
  2109  // contracts become offline.
  2110  func TestRedundancyReporting(t *testing.T) {
  2111  	if testing.Short() {
  2112  		t.SkipNow()
  2113  	}
  2114  	t.Parallel()
  2115  	st, err := createServerTester(t.Name())
  2116  	if err != nil {
  2117  		t.Fatal(err)
  2118  	}
  2119  	defer st.server.Close()
  2120  	stH1, err := blankServerTester(t.Name() + " - Host 2")
  2121  	if err != nil {
  2122  		t.Fatal(err)
  2123  	}
  2124  	testGroup := []*serverTester{st, stH1}
  2125  
  2126  	// Connect the testers to eachother so that they are all on the same
  2127  	// blockchain.
  2128  	err = fullyConnectNodes(testGroup)
  2129  	if err != nil {
  2130  		t.Fatal(err)
  2131  	}
  2132  	// Make sure that every wallet has money in it.
  2133  	err = fundAllNodes(testGroup)
  2134  	if err != nil {
  2135  		t.Fatal(err)
  2136  	}
  2137  	// Add storage to every host.
  2138  	err = addStorageToAllHosts(testGroup)
  2139  	if err != nil {
  2140  		t.Fatal(err)
  2141  	}
  2142  	// Announce every host.
  2143  	err = announceAllHosts(testGroup)
  2144  	if err != nil {
  2145  		t.Fatal(err)
  2146  	}
  2147  
  2148  	// Set an allowance with two hosts.
  2149  	allowanceValues := url.Values{}
  2150  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2151  	allowanceValues.Set("hosts", "2")
  2152  	allowanceValues.Set("period", "10")
  2153  	allowanceValues.Set("renewwindow", "5")
  2154  	err = st.stdPostAPI("/renter", allowanceValues)
  2155  	if err != nil {
  2156  		t.Fatal(err)
  2157  	}
  2158  
  2159  	// Block until the allowance has finished forming contracts.
  2160  	err = build.Retry(50, time.Millisecond*250, func() error {
  2161  		var rc RenterContracts
  2162  		err = st.getAPI("/renter/contracts", &rc)
  2163  		if err != nil {
  2164  			return errors.New("couldn't get renter stats")
  2165  		}
  2166  		if len(rc.Contracts) != 2 {
  2167  			return errors.New("no contracts")
  2168  		}
  2169  		return nil
  2170  	})
  2171  	if err != nil {
  2172  		t.Fatal("allowance setting failed")
  2173  	}
  2174  
  2175  	// Create a file to upload.
  2176  	filesize := int(1024)
  2177  	path := filepath.Join(st.dir, "test.dat")
  2178  	err = createRandFile(path, filesize)
  2179  	if err != nil {
  2180  		t.Fatal(err)
  2181  	}
  2182  
  2183  	// upload the file
  2184  	uploadValues := url.Values{}
  2185  	uploadValues.Set("source", path)
  2186  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  2187  	if err != nil {
  2188  		t.Fatal(err)
  2189  	}
  2190  
  2191  	// redundancy should reach 2
  2192  	var rf RenterFiles
  2193  	err = retry(60, time.Second, func() error {
  2194  		st.getAPI("/renter/files", &rf)
  2195  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  2196  			return nil
  2197  		}
  2198  		return errors.New("file not uploaded")
  2199  	})
  2200  	if err != nil {
  2201  		t.Fatal(err)
  2202  	}
  2203  
  2204  	// take down one of the hosts
  2205  	stH1.server.Close()
  2206  
  2207  	// wait for the redundancy to decrement
  2208  	err = retry(60, time.Second, func() error {
  2209  		st.getAPI("/renter/files", &rf)
  2210  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
  2211  			return nil
  2212  		}
  2213  		return errors.New("file redundancy not decremented")
  2214  	})
  2215  	if err != nil {
  2216  		t.Fatal(err)
  2217  	}
  2218  
  2219  	// bring back the host and let it mine a block
  2220  	stH1, err = assembleServerTester(stH1.walletKey, stH1.dir)
  2221  	if err != nil {
  2222  		t.Fatal(err)
  2223  	}
  2224  	defer stH1.server.Close()
  2225  
  2226  	testGroup = []*serverTester{st, stH1}
  2227  	// Make sure the leader of the group has the longest chain before
  2228  	// connecting the nodes
  2229  	if _, err := st.miner.AddBlock(); err != nil {
  2230  		t.Fatal(err)
  2231  	}
  2232  	err = fullyConnectNodes(testGroup)
  2233  	if err != nil {
  2234  		t.Fatal(err)
  2235  	}
  2236  
  2237  	// Add a block to clear the transaction pool and give the host an output to
  2238  	// make an announcement, and then make the announcement.
  2239  	_, err = st.miner.AddBlock()
  2240  	if err != nil {
  2241  		t.Fatal(err)
  2242  	}
  2243  	_, err = synchronizationCheck(testGroup)
  2244  	if err != nil {
  2245  		t.Fatal(err)
  2246  	}
  2247  	err = announceAllHosts(testGroup)
  2248  	if err != nil {
  2249  		t.Fatal(err)
  2250  	}
  2251  	_, err = st.miner.AddBlock()
  2252  	if err != nil {
  2253  		t.Fatal(err)
  2254  	}
  2255  	err = waitForBlock(st.cs.CurrentBlock().ID(), stH1)
  2256  	if err != nil {
  2257  		t.Fatal(err)
  2258  	}
  2259  	_, err = synchronizationCheck(testGroup)
  2260  	if err != nil {
  2261  		t.Fatal(err)
  2262  	}
  2263  
  2264  	// Wait until the host shows back up in the hostdb.
  2265  	var ah HostdbActiveGET
  2266  	err = retry(250, time.Millisecond*250, func() error {
  2267  		if err = st.getAPI("/hostdb/active", &ah); err != nil {
  2268  			t.Fatal(err)
  2269  		}
  2270  		if len(ah.Hosts) != 2 {
  2271  			return errors.New("not enough hosts in hostdb")
  2272  		}
  2273  		for _, host := range ah.Hosts {
  2274  			if len(host.ScanHistory) < 2 {
  2275  				return errors.New("hosts are not scanned")
  2276  			}
  2277  		}
  2278  		return nil
  2279  	})
  2280  	if err != nil {
  2281  		t.Fatal(err)
  2282  	}
  2283  
  2284  	// Mine another block so that the contract checker updates the IsGood status
  2285  	// of the contracts.
  2286  	_, err = st.miner.AddBlock()
  2287  	if err != nil {
  2288  		t.Fatal(err)
  2289  	}
  2290  	_, err = synchronizationCheck(testGroup)
  2291  	if err != nil {
  2292  		t.Fatal(err)
  2293  	}
  2294  
  2295  	// Redundancy should re-report at 2.
  2296  	err = retry(250, 100*time.Millisecond, func() error {
  2297  		st.getAPI("/renter/files", &rf)
  2298  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  2299  			return nil
  2300  		}
  2301  		return errors.New("file redundancy not incremented")
  2302  	})
  2303  	if err != nil {
  2304  		t.Fatal(err)
  2305  	}
  2306  }
  2307  
  2308  // TestUploadedBytesReporting verifies that reporting of how many bytes have
  2309  // been uploaded via active contracts is accurate
  2310  func TestUploadedBytesReporting(t *testing.T) {
  2311  	if testing.Short() {
  2312  		t.SkipNow()
  2313  	}
  2314  	t.Parallel()
  2315  	st, err := createServerTester(t.Name())
  2316  	if err != nil {
  2317  		t.Fatal(err)
  2318  	}
  2319  	defer st.server.Close()
  2320  	stH1, err := blankServerTester(t.Name() + " - Host 2")
  2321  	if err != nil {
  2322  		t.Fatal(err)
  2323  	}
  2324  	defer stH1.server.Close()
  2325  	testGroup := []*serverTester{st, stH1}
  2326  
  2327  	// Connect the testers to eachother so that they are all on the same
  2328  	// blockchain.
  2329  	err = fullyConnectNodes(testGroup)
  2330  	if err != nil {
  2331  		t.Fatal(err)
  2332  	}
  2333  	// Make sure that every wallet has money in it.
  2334  	err = fundAllNodes(testGroup)
  2335  	if err != nil {
  2336  		t.Fatal(err)
  2337  	}
  2338  	// Add storage to every host.
  2339  	err = addStorageToAllHosts(testGroup)
  2340  	if err != nil {
  2341  		t.Fatal(err)
  2342  	}
  2343  	// Announce every host.
  2344  	err = announceAllHosts(testGroup)
  2345  	if err != nil {
  2346  		t.Fatal(err)
  2347  	}
  2348  
  2349  	// Set an allowance with two hosts.
  2350  	allowanceValues := url.Values{}
  2351  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2352  	allowanceValues.Set("hosts", "2")
  2353  	allowanceValues.Set("period", "10")
  2354  	allowanceValues.Set("renewwindow", "5")
  2355  	err = st.stdPostAPI("/renter", allowanceValues)
  2356  	if err != nil {
  2357  		t.Fatal(err)
  2358  	}
  2359  
  2360  	// Block until the allowance has finished forming contracts.
  2361  	err = build.Retry(50, time.Millisecond*250, func() error {
  2362  		var rc RenterContracts
  2363  		err = st.getAPI("/renter/contracts", &rc)
  2364  		if err != nil {
  2365  			return errors.New("couldn't get renter stats")
  2366  		}
  2367  		if len(rc.Contracts) != 2 {
  2368  			return errors.New("no contracts")
  2369  		}
  2370  		return nil
  2371  	})
  2372  	if err != nil {
  2373  		t.Fatal("allowance setting failed")
  2374  	}
  2375  
  2376  	// Create a file to upload.
  2377  	filesize := int(modules.SectorSize * 2)
  2378  	path := filepath.Join(st.dir, "test.dat")
  2379  	err = createRandFile(path, filesize)
  2380  	if err != nil {
  2381  		t.Fatal(err)
  2382  	}
  2383  
  2384  	// Upload the file
  2385  	dataPieces := 1
  2386  	parityPieces := 1
  2387  	uploadValues := url.Values{}
  2388  	uploadValues.Set("source", path)
  2389  	uploadValues.Set("datapieces", fmt.Sprint(dataPieces))
  2390  	uploadValues.Set("paritypieces", fmt.Sprint(parityPieces))
  2391  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  2392  	if err != nil {
  2393  		t.Fatal(err)
  2394  	}
  2395  
  2396  	// Calculate the encrypted size of our fully redundant encoded file
  2397  	pieceSize := modules.SectorSize - crypto.TwofishOverhead
  2398  	chunkSize := pieceSize * uint64(dataPieces)
  2399  	numChunks := uint64(filesize) / chunkSize
  2400  	if uint64(filesize)%chunkSize != 0 {
  2401  		numChunks++
  2402  	}
  2403  	fullyRedundantSize := modules.SectorSize * uint64(dataPieces+parityPieces) * uint64(numChunks)
  2404  
  2405  	// Monitor the file as it uploads. Ensure that the UploadProgress times
  2406  	// the fully redundant file size always equals UploadedBytes reported
  2407  	var rf RenterFiles
  2408  	for i := 0; i < 60 && (len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100); i++ {
  2409  		st.getAPI("/renter/files", &rf)
  2410  		if len(rf.Files) >= 1 {
  2411  			uploadProgressBytes := uint64(float64(fullyRedundantSize) * rf.Files[0].UploadProgress / 100.0)
  2412  			// Note: in Go 1.10 we will be able to write Math.Round(uploadProgressBytes) != rf.Files[0].UploadedBytes
  2413  			if uploadProgressBytes != rf.Files[0].UploadedBytes && (uploadProgressBytes+1) != rf.Files[0].UploadedBytes {
  2414  				t.Fatalf("api reports having uploaded %v bytes when upload progress is %v%%, but the actual uploaded bytes count should be %v\n",
  2415  					rf.Files[0].UploadedBytes, rf.Files[0].UploadProgress, uploadProgressBytes)
  2416  			}
  2417  		}
  2418  		time.Sleep(time.Second)
  2419  	}
  2420  	if err != nil {
  2421  		t.Fatal(err)
  2422  	}
  2423  
  2424  	// Upload progress should be 100% and redundancy should reach 2
  2425  	if len(rf.Files) != 1 || rf.Files[0].UploadProgress < 100 || rf.Files[0].Redundancy != 2 {
  2426  		t.Fatal("the uploading is not succeeding for some reason:", rf.Files[0])
  2427  	}
  2428  
  2429  	// When the file is fully redundantly uploaded, UploadedBytes should
  2430  	// equal the file's fully redundant size
  2431  	if rf.Files[0].UploadedBytes != fullyRedundantSize {
  2432  		t.Fatalf("api reports having uploaded %v bytes when upload progress is 100%%, but the actual fully redundant file size is %v\n",
  2433  			rf.Files[0].UploadedBytes, fullyRedundantSize)
  2434  	}
  2435  
  2436  }
  2437  
  2438  // TestRenterMissingHosts verifies that if hosts are taken offline, downloads
  2439  // fail.
  2440  func TestRenterMissingHosts(t *testing.T) {
  2441  	if testing.Short() || !build.VLONG {
  2442  		t.SkipNow()
  2443  	}
  2444  	st, err := createServerTester(t.Name())
  2445  	if err != nil {
  2446  		t.Fatal(err)
  2447  	}
  2448  	defer st.server.Close()
  2449  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  2450  	if err != nil {
  2451  		t.Fatal(err)
  2452  	}
  2453  	defer stH1.server.Close()
  2454  	stH2, err := blankServerTester(t.Name() + " - Host 2")
  2455  	if err != nil {
  2456  		t.Fatal(err)
  2457  	}
  2458  	defer stH2.server.Close()
  2459  	stH3, err := blankServerTester(t.Name() + " - Host 3")
  2460  	if err != nil {
  2461  		t.Fatal(err)
  2462  	}
  2463  	defer stH3.server.Close()
  2464  	testGroup := []*serverTester{st, stH1, stH2, stH3}
  2465  
  2466  	// Connect the testers to eachother so that they are all on the same
  2467  	// blockchain.
  2468  	err = fullyConnectNodes(testGroup)
  2469  	if err != nil {
  2470  		t.Fatal(err)
  2471  	}
  2472  	// Make sure that every wallet has money in it.
  2473  	err = fundAllNodes(testGroup)
  2474  	if err != nil {
  2475  		t.Fatal(err)
  2476  	}
  2477  
  2478  	// Add storage to every host.
  2479  	err = addStorageToAllHosts(testGroup)
  2480  	if err != nil {
  2481  		t.Fatal(err)
  2482  	}
  2483  	err = announceAllHosts(testGroup)
  2484  	if err != nil {
  2485  		t.Fatal(err)
  2486  	}
  2487  
  2488  	// Set an allowance with two hosts.
  2489  	allowanceValues := url.Values{}
  2490  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2491  	allowanceValues.Set("hosts", "3")
  2492  	allowanceValues.Set("period", "20")
  2493  	err = st.stdPostAPI("/renter", allowanceValues)
  2494  	if err != nil {
  2495  		t.Fatal(err)
  2496  	}
  2497  
  2498  	// Block until the allowance has finished forming contracts.
  2499  	err = build.Retry(50, time.Millisecond*250, func() error {
  2500  		var rc RenterContracts
  2501  		err = st.getAPI("/renter/contracts", &rc)
  2502  		if err != nil {
  2503  			return errors.New("couldn't get renter stats")
  2504  		}
  2505  		if len(rc.Contracts) != 3 {
  2506  			return errors.New("no contracts")
  2507  		}
  2508  		return nil
  2509  	})
  2510  	if err != nil {
  2511  		t.Fatal("allowance setting failed:", err)
  2512  	}
  2513  
  2514  	// Create a file to upload.
  2515  	filesize := int(100)
  2516  	path := filepath.Join(st.dir, "test.dat")
  2517  	err = createRandFile(path, filesize)
  2518  	if err != nil {
  2519  		t.Fatal(err)
  2520  	}
  2521  
  2522  	// upload the file
  2523  	uploadValues := url.Values{}
  2524  	uploadValues.Set("source", path)
  2525  	uploadValues.Set("datapieces", "2")
  2526  	uploadValues.Set("paritypieces", "1")
  2527  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  2528  	if err != nil {
  2529  		t.Fatal(err)
  2530  	}
  2531  
  2532  	// redundancy should reach 1.5
  2533  	var rf RenterFiles
  2534  	err = retry(20, time.Second, func() error {
  2535  		st.getAPI("/renter/files", &rf)
  2536  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 {
  2537  			return nil
  2538  		}
  2539  		return errors.New("file not uploaded")
  2540  	})
  2541  	if err != nil {
  2542  		t.Fatal(err)
  2543  	}
  2544  
  2545  	// verify we can download
  2546  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
  2547  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2548  	if err != nil {
  2549  		t.Fatal(err)
  2550  	}
  2551  
  2552  	// take down one of the hosts
  2553  	err = stH1.server.Close()
  2554  	if err != nil {
  2555  		t.Fatal(err)
  2556  	}
  2557  
  2558  	// redundancy should not decrement, we have a backup host we can use.
  2559  	err = retry(60, time.Second, func() error {
  2560  		st.getAPI("/renter/files", &rf)
  2561  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1.5 {
  2562  			return nil
  2563  		}
  2564  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  2565  	})
  2566  	if err != nil {
  2567  		t.Log(err)
  2568  	}
  2569  
  2570  	// verify we still can download
  2571  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  2572  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2573  	if err != nil {
  2574  		t.Fatal(err)
  2575  	}
  2576  
  2577  	// take down another host
  2578  	err = stH2.server.Close()
  2579  	if err != nil {
  2580  		t.Fatal(err)
  2581  	}
  2582  
  2583  	// wait for the redundancy to decrement
  2584  	err = retry(60, time.Second, func() error {
  2585  		st.getAPI("/renter/files", &rf)
  2586  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
  2587  			return nil
  2588  		}
  2589  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  2590  	})
  2591  	if err != nil {
  2592  		t.Log(err)
  2593  	}
  2594  
  2595  	// verify we still can download
  2596  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  2597  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2598  	if err != nil {
  2599  		t.Fatal(err)
  2600  	}
  2601  
  2602  	// take down another host
  2603  	err = stH3.server.Close()
  2604  	if err != nil {
  2605  		t.Fatal(err)
  2606  	}
  2607  
  2608  	// wait for the redundancy to decrement
  2609  	err = retry(60, time.Second, func() error {
  2610  		st.getAPI("/renter/files", &rf)
  2611  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 0 {
  2612  			return nil
  2613  		}
  2614  		return errors.New("file redundancy not decremented: " + fmt.Sprint(rf.Files[0].Redundancy))
  2615  	})
  2616  	if err != nil {
  2617  		t.Log(err)
  2618  	}
  2619  
  2620  	// verify that the download fails
  2621  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify4.dat")
  2622  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2623  	if err == nil {
  2624  		t.Fatal("expected download to fail with redundancy <1")
  2625  	}
  2626  }
  2627  
  2628  // TestRepairLoopBlocking checks if the repair loop blocks operations while a
  2629  // non local file is being downloaded for repair.
  2630  func TestRepairLoopBlocking(t *testing.T) {
  2631  	// TODO: Refactor dependency management to block download
  2632  	t.Skip("Test requires refactoring")
  2633  	if testing.Short() || !build.VLONG {
  2634  		t.SkipNow()
  2635  	}
  2636  	st, err := createServerTester(t.Name())
  2637  	if err != nil {
  2638  		t.Fatal(err)
  2639  	}
  2640  	//st.renter.SetDependencies(renter.BlockRepairUpload{})
  2641  	defer st.server.Close()
  2642  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  2643  	if err != nil {
  2644  		t.Fatal(err)
  2645  	}
  2646  	defer stH1.server.Close()
  2647  	testGroup := []*serverTester{st, stH1}
  2648  
  2649  	// Connect the testers to eachother so that they are all on the same
  2650  	// blockchain.
  2651  	err = fullyConnectNodes(testGroup)
  2652  	if err != nil {
  2653  		t.Fatal(err)
  2654  	}
  2655  	// Make sure that every wallet has money in it.
  2656  	err = fundAllNodes(testGroup)
  2657  	if err != nil {
  2658  		t.Fatal(err)
  2659  	}
  2660  
  2661  	// Add storage to every host.
  2662  	err = addStorageToAllHosts(testGroup)
  2663  	if err != nil {
  2664  		t.Fatal(err)
  2665  	}
  2666  	err = announceAllHosts(testGroup)
  2667  	if err != nil {
  2668  		t.Fatal(err)
  2669  	}
  2670  
  2671  	// Set an allowance with two hosts.
  2672  	allowanceValues := url.Values{}
  2673  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2674  	allowanceValues.Set("hosts", "2")
  2675  	allowanceValues.Set("period", "10")
  2676  	err = st.stdPostAPI("/renter", allowanceValues)
  2677  	if err != nil {
  2678  		t.Fatal(err)
  2679  	}
  2680  
  2681  	// Create a file with 1 chunk to upload.
  2682  	filesize := int(1)
  2683  	path := filepath.Join(st.dir, "test.dat")
  2684  	err = createRandFile(path, filesize)
  2685  	if err != nil {
  2686  		t.Fatal(err)
  2687  	}
  2688  
  2689  	// upload the file
  2690  	uploadValues := url.Values{}
  2691  	uploadValues.Set("source", path)
  2692  	err = st.stdPostAPI("/renter/upload/test", uploadValues)
  2693  	if err != nil {
  2694  		t.Fatal(err)
  2695  	}
  2696  
  2697  	// redundancy should reach 2
  2698  	var rf RenterFiles
  2699  	err = retry(60, time.Second, func() error {
  2700  		st.getAPI("/renter/files", &rf)
  2701  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 2 {
  2702  			return nil
  2703  		}
  2704  		return errors.New("file not uploaded")
  2705  	})
  2706  	if err != nil {
  2707  		t.Fatal(err)
  2708  	}
  2709  
  2710  	// verify we can download
  2711  	downloadPath := filepath.Join(st.dir, "test-downloaded-verify.dat")
  2712  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2713  	if err != nil {
  2714  		t.Fatal(err)
  2715  	}
  2716  
  2717  	// remove the local copy of the file
  2718  	err = os.Remove(path)
  2719  	if err != nil {
  2720  		t.Fatal(err)
  2721  	}
  2722  
  2723  	// take down one of the hosts
  2724  	err = stH1.server.Close()
  2725  	if err != nil {
  2726  		t.Fatal(err)
  2727  	}
  2728  
  2729  	// wait for the redundancy to decrement
  2730  	err = retry(60, time.Second, func() error {
  2731  		st.getAPI("/renter/files", &rf)
  2732  		if len(rf.Files) >= 1 && rf.Files[0].Redundancy == 1 {
  2733  			return nil
  2734  		}
  2735  		return errors.New("file redundancy not decremented")
  2736  	})
  2737  	if err != nil {
  2738  		t.Fatal(err)
  2739  	}
  2740  
  2741  	// verify we still can download
  2742  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  2743  	err = st.stdGetAPI("/renter/download/test?destination=" + downloadPath)
  2744  	if err != nil {
  2745  		t.Fatal(err)
  2746  	}
  2747  
  2748  	// bring up a few new hosts
  2749  	testGroup = []*serverTester{st}
  2750  	for i := 0; i < 3; i++ {
  2751  		stNewHost, err := blankServerTester(t.Name() + fmt.Sprintf("-newhost%d", i))
  2752  		if err != nil {
  2753  			t.Fatal(err)
  2754  		}
  2755  		defer stNewHost.server.Close()
  2756  		testGroup = append(testGroup, stNewHost)
  2757  	}
  2758  
  2759  	// Connect the testers to eachother so that they are all on the same
  2760  	// blockchain.
  2761  	err = fullyConnectNodes(testGroup)
  2762  	if err != nil {
  2763  		t.Fatal(err)
  2764  	}
  2765  	_, err = synchronizationCheck(testGroup)
  2766  	if err != nil {
  2767  		t.Fatal(err)
  2768  	}
  2769  
  2770  	// Make sure that every wallet has money in it.
  2771  	err = fundAllNodes(testGroup)
  2772  	if err != nil {
  2773  		t.Fatal(err)
  2774  	}
  2775  
  2776  	for _, stNewHost := range testGroup[1 : len(testGroup)-1] {
  2777  		err = stNewHost.setHostStorage()
  2778  		if err != nil {
  2779  			t.Fatal(err)
  2780  		}
  2781  		err = stNewHost.announceHost()
  2782  		if err != nil {
  2783  			t.Fatal(err)
  2784  		}
  2785  		err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st)
  2786  		if err != nil {
  2787  			t.Fatal(err)
  2788  		}
  2789  
  2790  		// add a few new blocks in order to cause the renter to form contracts with the new host
  2791  		for i := 0; i < 10; i++ {
  2792  			b, err := testGroup[0].miner.AddBlock()
  2793  			if err != nil {
  2794  				t.Fatal(err)
  2795  			}
  2796  			tipID, err := synchronizationCheck(testGroup)
  2797  			if err != nil {
  2798  				t.Fatal(err)
  2799  			}
  2800  			if b.ID() != tipID {
  2801  				t.Fatal("test group does not have the tip block")
  2802  			}
  2803  		}
  2804  	}
  2805  
  2806  	// wait a few seconds for the the repair to be queued and started
  2807  	time.Sleep(3 * time.Second)
  2808  
  2809  	// redundancy should not increment back to 2 because the renter should be blocked
  2810  	st.getAPI("/renter/files", &rf)
  2811  	if len(rf.Files) >= 1 && rf.Files[0].Redundancy >= 2 && rf.Files[0].Available {
  2812  		t.Error("The file's redundancy incremented back to 2 but shouldn't")
  2813  	}
  2814  
  2815  	// create a second file to upload
  2816  	filesize = int(1)
  2817  	path2 := filepath.Join(st.dir, "test2.dat")
  2818  	err = createRandFile(path2, filesize)
  2819  	if err != nil {
  2820  		t.Fatal(err)
  2821  	}
  2822  
  2823  	// upload the second file
  2824  	uploadValues = url.Values{}
  2825  	uploadValues.Set("source", path2)
  2826  
  2827  	wait := make(chan error)
  2828  	go func() {
  2829  		wait <- st.stdPostAPI("/renter/upload/test2", uploadValues)
  2830  	}()
  2831  	select {
  2832  	case <-time.After(time.Minute):
  2833  		t.Fatal("/renter/upload API call didn't return within 60 seconds")
  2834  	case err = <-wait:
  2835  	}
  2836  	if err != nil {
  2837  		t.Fatal(err)
  2838  	}
  2839  
  2840  	// redundancy should reach 2 for the second file
  2841  	err = retry(60, time.Second, func() error {
  2842  		st.getAPI("/renter/files", &rf)
  2843  		if len(rf.Files) >= 2 && rf.Files[1].Redundancy >= 2 {
  2844  			return nil
  2845  		}
  2846  		return errors.New("file 2 not uploaded")
  2847  	})
  2848  	if err != nil {
  2849  		t.Fatal(err)
  2850  	}
  2851  
  2852  	// verify we can download the second file
  2853  	downloadPath = filepath.Join(st.dir, "test-downloaded-verify2.dat")
  2854  	err = st.stdGetAPI("/renter/download/test2?destination=" + downloadPath)
  2855  	if err != nil {
  2856  		t.Fatal(err)
  2857  	}
  2858  }
  2859  
  2860  // TestRemoteFileRepairMassive is similar to TestRemoteFileRepair but uploads
  2861  // more files to find potential deadlocks or crashes
  2862  func TestRemoteFileRepairMassive(t *testing.T) {
  2863  	if testing.Short() || !build.VLONG {
  2864  		t.SkipNow()
  2865  	}
  2866  	st, err := createServerTester(t.Name())
  2867  	if err != nil {
  2868  		t.Fatal(err)
  2869  	}
  2870  	defer st.server.Close()
  2871  	stH1, err := blankServerTester(t.Name() + " - Host 1")
  2872  	if err != nil {
  2873  		t.Fatal(err)
  2874  	}
  2875  	defer stH1.server.Close()
  2876  	testGroup := []*serverTester{st, stH1}
  2877  
  2878  	// Connect the testers to eachother so that they are all on the same
  2879  	// blockchain.
  2880  	err = fullyConnectNodes(testGroup)
  2881  	if err != nil {
  2882  		t.Fatal(err)
  2883  	}
  2884  	// Make sure that every wallet has money in it.
  2885  	err = fundAllNodes(testGroup)
  2886  	if err != nil {
  2887  		t.Fatal(err)
  2888  	}
  2889  
  2890  	// Add storage to every host.
  2891  	err = addStorageToAllHosts(testGroup)
  2892  	if err != nil {
  2893  		t.Fatal(err)
  2894  	}
  2895  	err = announceAllHosts(testGroup)
  2896  	if err != nil {
  2897  		t.Fatal(err)
  2898  	}
  2899  
  2900  	// Set an allowance with two hosts.
  2901  	allowanceValues := url.Values{}
  2902  	allowanceValues.Set("funds", "50000000000000000000000000000") // 50k SC
  2903  	allowanceValues.Set("hosts", "2")
  2904  	allowanceValues.Set("period", "10")
  2905  	err = st.stdPostAPI("/renter", allowanceValues)
  2906  	if err != nil {
  2907  		t.Fatal(err)
  2908  	}
  2909  
  2910  	// Create a file to upload.
  2911  	filesize := int(4000)
  2912  	path := filepath.Join(st.dir, "test.dat")
  2913  	err = createRandFile(path, filesize)
  2914  	if err != nil {
  2915  		t.Fatal(err)
  2916  	}
  2917  
  2918  	// upload the file numUploads times
  2919  	numUploads := 10
  2920  	uploadValues := url.Values{}
  2921  	uploadValues.Set("source", path)
  2922  
  2923  	for i := 0; i < numUploads; i++ {
  2924  		err = st.stdPostAPI(fmt.Sprintf("/renter/upload/test%v", i), uploadValues)
  2925  		if err != nil {
  2926  			t.Fatal(err)
  2927  		}
  2928  	}
  2929  
  2930  	// redundancy should reach 2 for all files
  2931  	var rf RenterFiles
  2932  	err = retry(600, time.Second, func() error {
  2933  		st.getAPI("/renter/files", &rf)
  2934  		if len(rf.Files) != numUploads {
  2935  			return errors.New("file not uploaded")
  2936  		}
  2937  		for i, f := range rf.Files {
  2938  			if f.Redundancy != 2 {
  2939  				return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy)
  2940  			}
  2941  		}
  2942  		return nil
  2943  	})
  2944  	if err != nil {
  2945  		t.Fatal(err)
  2946  	}
  2947  
  2948  	// remove the local copy of the file
  2949  	err = os.Remove(path)
  2950  	if err != nil {
  2951  		t.Fatal(err)
  2952  	}
  2953  
  2954  	// take down one of the hosts
  2955  	err = stH1.server.Close()
  2956  	if err != nil {
  2957  		t.Fatal(err)
  2958  	}
  2959  
  2960  	// wait for the redundancy to decrement
  2961  	err = retry(60, time.Second, func() error {
  2962  		st.getAPI("/renter/files", &rf)
  2963  		if len(rf.Files) != numUploads {
  2964  			return errors.New("file not uploaded")
  2965  		}
  2966  		for _, f := range rf.Files {
  2967  			if f.Redundancy != 1 {
  2968  				return errors.New("file redudancy didn't decrement to x1")
  2969  			}
  2970  		}
  2971  		return nil
  2972  	})
  2973  	if err != nil {
  2974  		t.Fatal(err)
  2975  	}
  2976  
  2977  	// bring up a new host
  2978  	stNewHost, err := blankServerTester(t.Name() + "-newhost")
  2979  	if err != nil {
  2980  		t.Fatal(err)
  2981  	}
  2982  	defer stNewHost.server.Close()
  2983  
  2984  	testGroup = []*serverTester{st, stNewHost}
  2985  
  2986  	// Connect the testers to eachother so that they are all on the same
  2987  	// blockchain.
  2988  	err = fullyConnectNodes(testGroup)
  2989  	if err != nil {
  2990  		t.Fatal(err)
  2991  	}
  2992  	_, err = synchronizationCheck(testGroup)
  2993  	if err != nil {
  2994  		t.Fatal(err)
  2995  	}
  2996  
  2997  	// Make sure that every wallet has money in it.
  2998  	err = fundAllNodes(testGroup)
  2999  	if err != nil {
  3000  		t.Fatal(err)
  3001  	}
  3002  
  3003  	err = stNewHost.setHostStorage()
  3004  	if err != nil {
  3005  		t.Fatal(err)
  3006  	}
  3007  	err = stNewHost.announceHost()
  3008  	if err != nil {
  3009  		t.Fatal(err)
  3010  	}
  3011  	err = waitForBlock(stNewHost.cs.CurrentBlock().ID(), st)
  3012  	if err != nil {
  3013  		t.Fatal(err)
  3014  	}
  3015  
  3016  	// add a few new blocks in order to cause the renter to form contracts with the new host
  3017  	for i := 0; i < 10; i++ {
  3018  		b, err := testGroup[0].miner.AddBlock()
  3019  		if err != nil {
  3020  			t.Fatal(err)
  3021  		}
  3022  		tipID, err := synchronizationCheck(testGroup)
  3023  		if err != nil {
  3024  			t.Fatal(err)
  3025  		}
  3026  		if b.ID() != tipID {
  3027  			t.Fatal("test group does not have the tip block")
  3028  		}
  3029  	}
  3030  
  3031  	// redundancy should increment back to 2 as the renter uploads to the new
  3032  	// host using the download-to-upload strategy
  3033  	err = retry(300, time.Second, func() error {
  3034  		st.getAPI("/renter/files", &rf)
  3035  		if len(rf.Files) != numUploads {
  3036  			return errors.New("file not uploaded")
  3037  		}
  3038  		for i, f := range rf.Files {
  3039  			if f.Redundancy != 2 {
  3040  				return fmt.Errorf("file %v only reached %v redundancy", i, f.Redundancy)
  3041  			}
  3042  		}
  3043  		return nil
  3044  	})
  3045  	if err != nil {
  3046  		t.Fatal(err)
  3047  	}
  3048  }