gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/contractor/update_test.go (about) 1 package contractor 2 3 import ( 4 "testing" 5 "time" 6 7 "gitlab.com/SiaPrime/SiaPrime/build" 8 "gitlab.com/SiaPrime/SiaPrime/crypto" 9 "gitlab.com/SiaPrime/SiaPrime/modules" 10 "gitlab.com/SiaPrime/SiaPrime/types" 11 12 "gitlab.com/NebulousLabs/errors" 13 "gitlab.com/NebulousLabs/fastrand" 14 ) 15 16 // TestIntegrationAutoRenew tests that contracts are automatically renewed at 17 // the expected block height. 18 func TestIntegrationAutoRenew(t *testing.T) { 19 if testing.Short() { 20 t.SkipNow() 21 } 22 t.Parallel() 23 // create testing trio 24 _, c, m, err := newTestingTrio(t.Name()) 25 if err != nil { 26 t.Fatal(err) 27 } 28 29 // form a contract with the host 30 a := modules.Allowance{ 31 Funds: types.SiacoinPrecision.Mul64(100), // 100 SC 32 Hosts: 1, 33 Period: 50, 34 RenewWindow: 10, 35 ExpectedStorage: modules.DefaultAllowance.ExpectedStorage, 36 ExpectedUpload: modules.DefaultAllowance.ExpectedUpload, 37 ExpectedDownload: modules.DefaultAllowance.ExpectedDownload, 38 ExpectedRedundancy: modules.DefaultAllowance.ExpectedRedundancy, 39 } 40 err = c.SetAllowance(a) 41 if err != nil { 42 t.Fatal(err) 43 } 44 err = build.Retry(50, 100*time.Millisecond, func() error { 45 if len(c.Contracts()) == 0 { 46 return errors.New("contracts were not formed") 47 } 48 return nil 49 }) 50 if err != nil { 51 t.Fatal(err) 52 } 53 contract := c.Contracts()[0] 54 55 // revise the contract 56 editor, err := c.Editor(contract.HostPublicKey, nil) 57 if err != nil { 58 t.Fatal(err) 59 } 60 data := fastrand.Bytes(int(modules.SectorSize)) 61 // insert the sector 62 _, err = editor.Upload(data) 63 if err != nil { 64 t.Fatal(err) 65 } 66 err = editor.Close() 67 if err != nil { 68 t.Fatal(err) 69 } 70 71 // mine until we enter the renew window 72 renewHeight := contract.EndHeight - c.allowance.RenewWindow 73 for c.blockHeight < renewHeight { 74 _, err := m.AddBlock() 75 if err != nil { 76 t.Fatal(err) 77 } 78 } 79 // wait for goroutine in ProcessConsensusChange to finish 80 time.Sleep(100 * time.Millisecond) 81 c.maintenanceLock.Lock() 82 c.maintenanceLock.Unlock() 83 84 // check renewed contract 85 contract = c.Contracts()[0] 86 endHeight := c.contractEndHeight() 87 if contract.EndHeight != endHeight { 88 t.Fatalf("Wrong end height, expected %v got %v\n", endHeight, contract.EndHeight) 89 } 90 } 91 92 // TestIntegrationRenewInvalidate tests that editors and downloaders are 93 // properly invalidated when a renew is queued. 94 func TestIntegrationRenewInvalidate(t *testing.T) { 95 if testing.Short() { 96 t.SkipNow() 97 } 98 t.Parallel() 99 // create testing trio 100 _, c, m, err := newTestingTrio(t.Name()) 101 if err != nil { 102 t.Fatal(err) 103 } 104 105 // form a contract with the host 106 a := modules.Allowance{ 107 Funds: types.SiacoinPrecision.Mul64(100), // 100 SC 108 Hosts: 1, 109 Period: 50, 110 RenewWindow: 10, 111 ExpectedStorage: modules.DefaultAllowance.ExpectedStorage, 112 ExpectedUpload: modules.DefaultAllowance.ExpectedUpload, 113 ExpectedDownload: modules.DefaultAllowance.ExpectedDownload, 114 ExpectedRedundancy: modules.DefaultAllowance.ExpectedRedundancy, 115 } 116 err = c.SetAllowance(a) 117 if err != nil { 118 t.Fatal(err) 119 } 120 err = build.Retry(50, 100*time.Millisecond, func() error { 121 if len(c.Contracts()) == 0 { 122 return errors.New("contracts were not formed") 123 } 124 return nil 125 }) 126 if err != nil { 127 t.Fatal(err) 128 } 129 contract := c.Contracts()[0] 130 131 // revise the contract 132 editor, err := c.Editor(contract.HostPublicKey, nil) 133 if err != nil { 134 t.Fatal(err) 135 } 136 data := fastrand.Bytes(int(modules.SectorSize)) 137 // insert the sector 138 _, err = editor.Upload(data) 139 if err != nil { 140 t.Fatal(err) 141 } 142 143 // mine until we enter the renew window; the editor should be invalidated 144 renewHeight := contract.EndHeight - c.allowance.RenewWindow 145 for c.blockHeight < renewHeight { 146 _, err := m.AddBlock() 147 if err != nil { 148 t.Fatal(err) 149 } 150 } 151 // wait for goroutine in ProcessConsensusChange to finish 152 time.Sleep(100 * time.Millisecond) 153 c.maintenanceLock.Lock() 154 c.maintenanceLock.Unlock() 155 156 // check renewed contract 157 contract = c.Contracts()[0] 158 endHeight := c.contractEndHeight() 159 c.mu.Lock() 160 if contract.EndHeight != endHeight { 161 t.Fatalf("Wrong end height, expected %v got %v\n", endHeight, contract.EndHeight) 162 } 163 c.mu.Unlock() 164 165 // editor should have been invalidated 166 _, err = editor.Upload(make([]byte, modules.SectorSize)) 167 if err != errInvalidEditor && err != errInvalidSession { 168 t.Error("expected invalid editor error; got", err) 169 } 170 editor.Close() 171 172 // create a downloader 173 downloader, err := c.Downloader(contract.HostPublicKey, nil) 174 if err != nil { 175 t.Fatal(err) 176 } 177 // mine until we enter the renew window 178 renewHeight = contract.EndHeight - c.allowance.RenewWindow 179 for c.blockHeight < renewHeight { 180 _, err := m.AddBlock() 181 if err != nil { 182 t.Fatal(err) 183 } 184 } 185 186 // downloader should have been invalidated 187 err = build.Retry(50, 100*time.Millisecond, func() error { 188 // wait for goroutine in ProcessConsensusChange to finish 189 c.maintenanceLock.Lock() 190 c.maintenanceLock.Unlock() 191 _, err2 := downloader.Download(crypto.Hash{}, 0, 0) 192 if err2 != errInvalidDownloader && err2 != errInvalidSession { 193 return errors.AddContext(err, "expected invalid downloader error") 194 } 195 return downloader.Close() 196 }) 197 if err != nil { 198 t.Fatal(err) 199 } 200 }