Commit 9a539059 authored by David Vorick's avatar David Vorick

Merge branch 'expected-storage-allowance' into 'master'

Move userGuidelines into allowance

See merge request !3283
parents adcfecca 821625e3
Pipeline #36388874 failed with stages
in 117 minutes and 20 seconds
......@@ -42,9 +42,9 @@ func printScoreBreakdown(info *api.HostdbHostsGET) {
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
fmt.Fprintf(w, "\t\tAge:\t %.3f\n", info.ScoreBreakdown.AgeAdjustment)
fmt.Fprintf(w, "\t\tBurn:\t %.3f\n", info.ScoreBreakdown.BurnAdjustment)
fmt.Fprintf(w, "\t\tCollateral:\t %.3f\n", info.ScoreBreakdown.CollateralAdjustment/1e27)
fmt.Fprintf(w, "\t\tCollateral:\t %.3f\n", info.ScoreBreakdown.CollateralAdjustment/1e96)
fmt.Fprintf(w, "\t\tInteraction:\t %.3f\n", info.ScoreBreakdown.InteractionAdjustment)
fmt.Fprintf(w, "\t\tPrice:\t %.3f\n", info.ScoreBreakdown.PriceAdjustment*1e6)
fmt.Fprintf(w, "\t\tPrice:\t %.3f\n", info.ScoreBreakdown.PriceAdjustment*1e24)
fmt.Fprintf(w, "\t\tStorage:\t %.3f\n", info.ScoreBreakdown.StorageRemainingAdjustment)
fmt.Fprintf(w, "\t\tUptime:\t %.3f\n", info.ScoreBreakdown.UptimeAdjustment)
fmt.Fprintf(w, "\t\tVersion:\t %.3f\n", info.ScoreBreakdown.VersionAdjustment)
......@@ -287,9 +287,9 @@ func hostdbviewcmd(pubkey string) {
fmt.Println("Host information:")
fmt.Println(" Public Key:", info.Entry.PublicKeyString)
fmt.Println(" Public Key: ", info.Entry.PublicKeyString)
fmt.Println(" Block First Seen:", info.Entry.FirstSeen)
fmt.Println(" Absolute Score:", info.ScoreBreakdown.Score)
fmt.Println(" Absolute Score: ", info.ScoreBreakdown.Score)
fmt.Println("\n Host Settings:")
w := tabwriter.NewWriter(os.Stdout, 0, 0, 2, ' ', 0)
......
......@@ -26,6 +26,15 @@ var (
renterShowHistory bool // Show download history in addition to download queue.
siaDir string // Path to sia data dir
walletRawTxn bool // Encode/decode transactions in base64-encoded binary.
allowanceFunds string // amount of money to be used within a period
allowancePeriod string // length of period
allowanceHosts string // number of hosts to form contracts with
allowanceRenewWindow string // renew window of allowance
allowanceExpectedStorage string // expected storage stored on hosts before redundancy
allowanceExpectedUpload string // expected data uploaded within period
allowanceExpectedDownload string // expected data downloaded within period
allowanceExpectedRedundancy string // expected redundancy of most uploaded files
)
var (
......@@ -139,6 +148,15 @@ func main() {
renterFilesListCmd.Flags().BoolVarP(&renterListVerbose, "verbose", "v", false, "Show additional file info such as redundancy")
renterExportCmd.AddCommand(renterExportContractTxnsCmd)
renterSetAllowanceCmd.Flags().StringVar(&allowanceFunds, "amount", "", "amount of money in allowance, specified in currency units")
renterSetAllowanceCmd.Flags().StringVar(&allowancePeriod, "period", "", "period of allowance in blocks (b), hours (h), days (d) or weeks (w)")
renterSetAllowanceCmd.Flags().StringVar(&allowanceHosts, "hosts", "", "number of hosts the renter will spread the uploaded data across")
renterSetAllowanceCmd.Flags().StringVar(&allowanceRenewWindow, "renew-window", "", "renew window in blocks (b), hours (h), days (d) or weeks (w)")
renterSetAllowanceCmd.Flags().StringVar(&allowanceExpectedStorage, "expected-storage", "", "expected storage in bytes (B), kilobytes (KB), megabytes (MB) etc. up to yottabytes (YB)")
renterSetAllowanceCmd.Flags().StringVar(&allowanceExpectedUpload, "expected-upload", "", "expected upload in period in bytes (B), kilobytes (KB), megabytes (MB) etc. up to yottabytes (YB)")
renterSetAllowanceCmd.Flags().StringVar(&allowanceExpectedDownload, "expected-download", "", "expected download in period in bytes (B), kilobytes (KB), megabytes (MB) etc. up to yottabytes (YB)")
renterSetAllowanceCmd.Flags().StringVar(&allowanceExpectedRedundancy, "expected-redundancy", "", "expected redundancy of most uploaded files")
root.AddCommand(gatewayCmd)
gatewayCmd.AddCommand(gatewayConnectCmd, gatewayDisconnectCmd, gatewayAddressCmd, gatewayListCmd)
......
......@@ -117,16 +117,6 @@ and if no allowance is set an allowance of 500SC, 12w period, 50 hosts, and 4w r
Short: "Set the allowance",
Long: `Set the amount of money that can be spent over a given period.
amount is given in currency units (SC, KS, etc.)
period is given in either blocks (b), hours (h), days (d), or weeks (w). A
block is approximately 10 minutes, so one hour is six blocks, a day is 144
blocks, and a week is 1008 blocks.
The Sia renter module spreads data across more than one Sia server computer
or "host". The "hosts" parameter for the setallowance command determines
how many different hosts the renter will spread the data across.
Allowance can be automatically renewed periodically. If the current
blockheight + the renew window >= the end height the contract,
then the contract is renewed automatically.
......@@ -266,13 +256,24 @@ func renterallowancecmd() {
}
allowance := rg.Settings.Allowance
// Normalize the expectations over the period.
allowance.ExpectedUpload *= uint64(allowance.Period)
allowance.ExpectedDownload *= uint64(allowance.Period)
// Show allowance info
fmt.Printf(`Allowance:
Amount: %v
Period: %v blocks
Renew Window: %v blocks
Hosts: %v
`, currencyUnits(allowance.Funds), allowance.Period, allowance.RenewWindow, allowance.Hosts)
Amount: %v
Period: %v blocks
Renew Window: %v blocks
Hosts: %v
Expectations for period:
Expected Storage: %v
Expected Upload: %v
Expected Download: %v
Expected Redundancy: %v
`, currencyUnits(allowance.Funds), allowance.Period, allowance.RenewWindow, allowance.Hosts, filesizeUnits(int64(allowance.ExpectedStorage)),
filesizeUnits(int64(allowance.ExpectedUpload)), filesizeUnits(int64(allowance.ExpectedDownload)), allowance.ExpectedRedundancy)
// Show spending detail
fm := rg.FinancialMetrics
......@@ -347,56 +348,134 @@ again:
fmt.Println("Allowance canceled.")
}
// rentersetallowancecmd allows the user to set the allowance.
// the first two parameters, amount and period, are required.
// the second two parameters are optional:
// hosts integer number of hosts
// renewperiod how many blocks between renewals
// rentersetallowancecmd allows the user to set the allowance or modify
// individual fields of it.
func rentersetallowancecmd(cmd *cobra.Command, args []string) {
if len(args) < 2 || len(args) > 4 {
cmd.UsageFunc()(cmd)
os.Exit(exitCodeUsage)
}
hastings, err := parseCurrency(args[0])
if err != nil {
die("Could not parse amount:", err)
}
blocks, err := parsePeriod(args[1])
if err != nil {
die("Could not parse period:", err)
}
allowance := modules.Allowance{}
_, err = fmt.Sscan(hastings, &allowance.Funds)
req := httpClient.RenterPostPartialAllowance()
changedFields := 0
// Get the current period setting.
rg, err := httpClient.RenterGet()
if err != nil {
die("Could not parse amount:", err)
die("Could not get renter settings")
}
period := rg.Settings.Allowance.Period
_, err = fmt.Sscan(blocks, &allowance.Period)
if err != nil {
die("Could not parse period:", err)
// parse funds
if allowanceFunds != "" {
hastings, err := parseCurrency(allowanceFunds)
if err != nil {
die("Could not parse amount:", err)
}
var funds types.Currency
_, err = fmt.Sscan(hastings, &funds)
if err != nil {
die("Could not parse amount:", err)
}
req = req.WithFunds(funds)
changedFields++
}
if len(args) > 2 {
hosts, err := strconv.Atoi(args[2])
// parse period
if allowancePeriod != "" {
blocks, err := parsePeriod(allowancePeriod)
if err != nil {
die("Could not parse period:", err)
}
_, err = fmt.Sscan(blocks, &period)
if err != nil {
die("Could not parse period:", err)
}
req = req.WithPeriod(period)
changedFields++
}
// parse hosts
if allowanceHosts != "" {
hosts, err := strconv.Atoi(allowanceHosts)
if err != nil {
die("Could not parse host count")
}
allowance.Hosts = uint64(hosts)
req = req.WithHosts(uint64(hosts))
changedFields++
}
if len(args) > 3 {
renewWindow, err := parsePeriod(args[3])
// parse renewWindow
if allowanceRenewWindow != "" {
rw, err := parsePeriod(allowanceRenewWindow)
if err != nil {
die("Could not parse renew window")
}
_, err = fmt.Sscan(renewWindow, &allowance.RenewWindow)
var renewWindow types.BlockHeight
_, err = fmt.Sscan(rw, &renewWindow)
if err != nil {
die("Could not parse renew window:", err)
}
req = req.WithRenewWindow(renewWindow)
changedFields++
}
err = httpClient.RenterPostAllowance(allowance)
if err != nil {
// parse expectedStorage
if allowanceExpectedStorage != "" {
es, err := parseFilesize(allowanceExpectedStorage)
if err != nil {
die("Could not parse expected storage")
}
var expectedStorage uint64
_, err = fmt.Sscan(es, &expectedStorage)
if err != nil {
die("Could not parse expected storage")
}
req = req.WithExpectedStorage(expectedStorage)
changedFields++
}
// parse expectedUpload
if allowanceExpectedUpload != "" {
eu, err := parseFilesize(allowanceExpectedUpload)
if err != nil {
die("Could not parse expected upload")
}
var expectedUpload uint64
_, err = fmt.Sscan(eu, &expectedUpload)
if err != nil {
die("Could not parse expected upload")
}
req = req.WithExpectedUpload(expectedUpload / uint64(period))
changedFields++
}
// parse expectedDownload
if allowanceExpectedDownload != "" {
ed, err := parseFilesize(allowanceExpectedDownload)
if err != nil {
die("Could not parse expected download")
}
var expectedDownload uint64
_, err = fmt.Sscan(ed, &expectedDownload)
if err != nil {
die("Could not parse expected download")
}
req = req.WithExpectedDownload(expectedDownload / uint64(period))
changedFields++
}
// parse expectedRedundancy
if allowanceExpectedRedundancy != "" {
er, err := parseFilesize(allowanceExpectedRedundancy)
if err != nil {
die("Could not parse expected redundancy")
}
var expectedRedundancy float64
_, err = fmt.Sscan(er, &expectedRedundancy)
if err != nil {
die("Could not parse expected redundancy")
}
req = req.WithExpectedRedundancy(expectedRedundancy)
changedFields++
}
// check if any fields were updated.
if changedFields == 0 {
fmt.Println("No flags specified. Allowance not updated.")
return
}
if err := req.Send(); err != nil {
die("Could not set allowance:", err)
}
fmt.Println("Allowance updated.")
fmt.Printf("Allowance updated. %v setting(s) changed.\n", changedFields)
}
// byValue sorts contracts by their value in siacoins, high to low. If two
......
......@@ -974,14 +974,20 @@ modify settings that control the renter's behavior.
###### Query String Parameters [(with comments)](/doc/api/Renter.md#query-string-parameters)
```
checkforipviolation // true or false
funds // hastings
expectedstorage // bytes expected to be stored on sia (without redundancy)
expectedupload // blocks
expecteddownload // blocks
expectedredundancy // float
funds // hastings
hosts
period // block height
renewwindow // block height
maxdownloadspeed // bytes per second
maxuploadspeed // bytes per second
streamcachesize // number of data chunks cached when streaming
period // block height
renewwindow // block height
maxdownloadspeed // bytes per second
maxuploadspeed // bytes per second
checkforipviolation // true or false
streamcachesize // number of data chunks cached when streaming
```
###### Response
......@@ -1904,4 +1910,4 @@ addresses will be reported in /wallet/unspent.
###### Response
standard success or error response. See
[#standard-responses](#standard-responses).
\ No newline at end of file
[#standard-responses](#standard-responses).
......@@ -148,6 +148,29 @@ maxuploadspeed
// Stream cache size specifies how many data chunks will be cached while
// streaming.
streamcachesize
// The next 4 values all relate to tuning the allowance. The usage pattern for
// the storage (e.g. download heavy, storage heavy, etc.) impacts which hosts are
// optimal. These values provide hints indicating what sort of usage pattern the
// user will be employing, allowing the software to pick more optimal selections
// of hosts.
//
// The expected storage in bytes the user expects to upload to the network.
// Shouldn't include redundancy.
expectedstorage
// The expected amount of data which will be uploaded through the API before
// redundancy in bytes per block.
expectedupload
// The expected amount of data which will be downloaded through the API in
// bytes per block.
expecteddownload
// Expected redundancy is the expected redundancy of the majority of the files
// the user is going to upload. If most files are going to be uploaded at a 3.0x
// redundancy, this should be set to 3.0.
expectedredundancy
```
###### Response
......
......@@ -438,7 +438,7 @@ func RenterPayoutsPreTax(host HostDBEntry, funding, txnFee, basePrice, baseColla
hostCollateral = maxStorageSizeTime.Mul(host.Collateral).Add(baseCollateral)
// Don't add more collateral than 10x the collateral for the expected
// storage to save on fees.
maxRenterCollateral := host.Collateral.Mul64(uint64(period)).Mul64(expectedStorage).Mul64(10)
maxRenterCollateral := host.Collateral.Mul64(uint64(period)).Mul64(expectedStorage).Mul64(5)
if hostCollateral.Cmp(maxRenterCollateral) > 0 {
hostCollateral = maxRenterCollateral
}
......
......@@ -19,12 +19,15 @@ var (
DefaultAllowance = Allowance{
Funds: types.SiacoinPrecision.Mul64(500),
Hosts: uint64(PriceEstimationScope),
Period: types.BlockHeight(12096),
RenewWindow: types.BlockHeight(4032),
}
Period: types.BlockHeight(3 * types.BlocksPerMonth),
RenewWindow: types.BlockHeight(types.BlocksPerMonth),
// ErrHostFault is an error that is usually extended to indicate that an error
// is the host's fault.
ExpectedStorage: 1e12, // 1 TB
ExpectedUpload: uint64(200e9) / types.BlocksPerMonth, // 200 GB per month
ExpectedDownload: uint64(100e9) / types.BlocksPerMonth, // 100 GB per month
ExpectedRedundancy: 3.0, // default is 10/30 erasure coding
}
// ErrHostFault indicates if an error is the host's fault.
ErrHostFault = errors.New("host has returned an error")
// PriceEstimationScope is the number of hosts that get queried by the
......@@ -36,14 +39,6 @@ var (
Dev: int(12),
Testing: int(4),
}).(int)
// DefaultUsageGuideLines is a sane set of guidelines.
DefaultUsageGuideLines = UsageGuidelines{
ExpectedStorage: 25e9,
ExpectedUploadFrequency: 24192,
ExpectedDownloadFrequency: 12096,
ExpectedRedundancy: 3.0,
}
)
// FilterMode is the helper type for the enum constants for the HostDB filter
......@@ -92,33 +87,6 @@ func (fm *FilterMode) FromString(s string) error {
return nil
}
// UsageGuidelines is a temporary helper struct.
// TODO: These values should be rolled into the allowance, instead of being a
// separate struct that we pass in.
//
// expectedStorage is the amount of data that we expect to have in a contract.
//
// expectedUploadFrequency is the expected number of blocks between each
// complete re-upload of the filesystem. This will be a combination of the rate
// at which a user uploads files, the rate at which a user replaces files, and
// the rate at which a user has to repair files due to host churn. If the
// expected storage is 25 GB and the expected upload frequency is 24 weeks, it
// means the user is expected to do about 1 GB of upload per week on average
// throughout the life of the contract.
//
// expectedDownloadFrequency is the expected number of blocks between each
// complete download of the filesystem. This should include the user
// downloading, streaming, and repairing files.
//
// expectedDataPieces and expectedParityPieces are used to give information
// about the redundancy of the files being uploaded.
type UsageGuidelines struct {
ExpectedStorage uint64
ExpectedUploadFrequency uint64
ExpectedDownloadFrequency uint64
ExpectedRedundancy float64
}
// IsHostsFault indicates if a returned error is the host's fault.
func IsHostsFault(err error) bool {
return errors.Contains(err, ErrHostFault)
......@@ -174,6 +142,20 @@ type Allowance struct {
Hosts uint64 `json:"hosts"`
Period types.BlockHeight `json:"period"`
RenewWindow types.BlockHeight `json:"renewwindow"`
// ExpectedStorage is the amount of data that we expect to have in a contract.
ExpectedStorage uint64 `json:"expectedstorage"`
// ExpectedUpload is the expected amount of data uploaded through the API,
// before redundancy, per block.
ExpectedUpload uint64 `json:"expectedupload"`
// ExpectedDownload is the expected amount of data downloaded through the
// API per block.
ExpectedDownload uint64 `json:"expecteddownload"`
// ExpectedRedundancy is the average redundancy of files being uploaded.
ExpectedRedundancy float64 `json:"expectedredundancy"`
}
// ContractUtility contains metrics internal to the contractor that reflect the
......
......@@ -89,7 +89,7 @@ const (
// PriceEstimationSafetyFactor is the factor of safety used in the price
// estimation to account for any missed costs
PriceEstimationSafetyFactor = 1.33
PriceEstimationSafetyFactor = 1.2
)
var (
......
......@@ -8,10 +8,14 @@ import (
)
var (
errAllowanceNoHosts = errors.New("hosts must be non-zero")
errAllowanceNotSynced = errors.New("you must be synced to set an allowance")
errAllowanceWindowSize = errors.New("renew window must be less than period")
errAllowanceZeroPeriod = errors.New("period must be non-zero")
errAllowanceNoHosts = errors.New("hosts must be non-zero")
errAllowanceNotSynced = errors.New("you must be synced to set an allowance")
errAllowanceWindowSize = errors.New("renew window must be less than period")
errAllowanceZeroPeriod = errors.New("period must be non-zero")
errAllowanceZeroExpectedStorage = errors.New("expected storage must be non-zero")
errAllowanceZeroExpectedUpload = errors.New("expected upload must be non-zero")
errAllowanceZeroExpectedDownload = errors.New("expected download must be non-zero")
errAllowanceZeroExpectedRedundancy = errors.New("expected redundancy must be non-zero")
// ErrAllowanceZeroWindow is returned when the caller requests a
// zero-length renewal window. This will happen if the caller sets the
......@@ -53,6 +57,14 @@ func (c *Contractor) SetAllowance(a modules.Allowance) error {
return ErrAllowanceZeroWindow
} else if a.RenewWindow >= a.Period {
return errAllowanceWindowSize
} else if a.ExpectedStorage == 0 {
return errAllowanceZeroExpectedStorage
} else if a.ExpectedUpload == 0 {
return errAllowanceZeroExpectedUpload
} else if a.ExpectedDownload == 0 {
return errAllowanceZeroExpectedDownload
} else if a.ExpectedRedundancy == 0 {
return errAllowanceZeroExpectedRedundancy
} else if !c.cs.Synced() {
return errAllowanceNotSynced
}
......@@ -63,8 +75,12 @@ func (c *Contractor) SetAllowance(a modules.Allowance) error {
// empty. the current period is set in the past by the renew window to make sure
// the first period aligns with the first period contracts in the same way
// that future periods align with contracts
// Also remember that we might have to unlock our contracts if the
// allowance was set to the empty allowance before.
unlockContracts := false
if reflect.DeepEqual(c.allowance, modules.Allowance{}) {
c.currentPeriod = c.blockHeight - a.RenewWindow
unlockContracts = true
}
c.allowance = a
err := c.saveSync()
......@@ -75,18 +91,20 @@ func (c *Contractor) SetAllowance(a modules.Allowance) error {
// Cycle through all contracts and unlock them again since they might have
// been locked by managedCancelAllowance previously.
ids := c.staticContracts.IDs()
for _, id := range ids {
contract, exists := c.staticContracts.Acquire(id)
if !exists {
continue
}
utility := contract.Utility()
utility.Locked = false
err := contract.UpdateUtility(utility)
c.staticContracts.Return(contract)
if err != nil {
return err
if unlockContracts {
ids := c.staticContracts.IDs()
for _, id := range ids {
contract, exists := c.staticContracts.Acquire(id)
if !exists {
continue
}
utility := contract.Utility()
utility.Locked = false
err := contract.UpdateUtility(utility)
c.staticContracts.Return(contract)
if err != nil {
return err
}
}
}
......@@ -98,8 +116,14 @@ func (c *Contractor) SetAllowance(a modules.Allowance) error {
// Interrupt any existing maintenance and launch a new round of
// maintenance.
c.managedInterruptContractMaintenance()
go c.threadedContractMaintenance()
if err := c.tg.Add(); err != nil {
return err
}
go func() {
defer c.tg.Done()
c.managedInterruptContractMaintenance()
c.threadedContractMaintenance()
}()
return nil
}
......
......@@ -7,6 +7,7 @@ package contractor
import (
"fmt"
"math/big"
"reflect"
"gitlab.com/NebulousLabs/Sia/build"
"gitlab.com/NebulousLabs/Sia/modules"
......@@ -304,8 +305,13 @@ func (c *Contractor) managedNewContract(host modules.HostDBEntry, contractFundin
}
// Determine if host settings align with allowance period
c.mu.Lock()
if reflect.DeepEqual(c.allowance, modules.Allowance{}) {
c.mu.Unlock()
return types.ZeroCurrency, modules.RenterContract{}, errors.New("called managedNewContract but allowance wasn't set")
}
period := c.allowance.Period
c.mu.Unlock()
if host.MaxDuration < period {
err := errors.New("unable to form contract with host due to insufficient MaxDuration of host")
return types.ZeroCurrency, modules.RenterContract{}, err
......@@ -324,6 +330,7 @@ func (c *Contractor) managedNewContract(host modules.HostDBEntry, contractFundin
// create contract params
c.mu.RLock()
params := proto.ContractParams{
Allowance: c.allowance,
Host: host,
Funding: contractFunding,
StartHeight: c.blockHeight,
......@@ -428,6 +435,10 @@ func (c *Contractor) managedRenew(sc *proto.SafeContract, contractFunding types.
// Fetch the host associated with this contract.
host, ok := c.hdb.Host(contract.HostPublicKey)
c.mu.Lock()
if reflect.DeepEqual(c.allowance, modules.Allowance{}) {
c.mu.Unlock()
return modules.RenterContract{}, errors.New("called managedRenew but allowance isn't set")
}
period := c.allowance.Period
c.mu.Unlock()
if !ok {
......@@ -454,6 +465,7 @@ func (c *Contractor) managedRenew(sc *proto.SafeContract, contractFunding types.
// create contract params
c.mu.RLock()
params := proto.ContractParams{
Allowance: c.allowance,
Host: host,
Funding: contractFunding,
StartHeight: c.blockHeight,
......
......@@ -178,10 +178,14 @@ func TestAllowanceSpending(t *testing.T) {
// set an allowance
testAllowance := modules.Allowance{
Funds: types.SiacoinPrecision.Mul64(6000),
RenewWindow: 100,
Hosts: 1,
Period: 200,
Funds: types.SiacoinPrecision.Mul64(6000),
RenewWindow: 100,
Hosts: 1,
Period: 200,
ExpectedStorage: modules.DefaultAllowance.ExpectedStorage,
ExpectedUpload: modules.DefaultAllowance.ExpectedUpload,
ExpectedDownload: modules.DefaultAllowance.ExpectedDownload,
ExpectedRedundancy: modules.DefaultAllowance.ExpectedRedundancy,
}
err = c.SetAllowance(testAllowance)
if err != nil {
......@@ -334,10 +338,30 @@ func TestIntegrationSetAllowance(t *testing.T) {
if err != errAllowanceWindowSize {
t.Errorf("expected %q, got %q", errAllowanceWindowSize, err)
}
a.RenewWindow = 10
err = c.SetAllowance(a)
if err != errAllowanceZeroExpectedStorage {
t.Errorf("expected %q, got %q", errAllowanceZeroExpectedStorage, err)
}
a.ExpectedStorage = modules.DefaultAllowance.ExpectedStorage
err = c.SetAllowance(a)
if err != errAllowanceZeroExpectedUpload {
t.Errorf("expected %q, got %q", errAllowanceZeroExpectedUpload, err)
}
a.ExpectedUpload = modules.DefaultAllowance.ExpectedUpload
err = c.SetAllowance(a)
if err != errAllowanceZeroExpectedDownload {
t.Errorf("expected %q, got %q", errAllowanceZeroExpectedDownload, err)
}
a.ExpectedDownload = modules.DefaultAllowance.ExpectedDownload
err = c.SetAllowance(a)
if err != errAllowanceZeroExpectedRedundancy {
t.Errorf("expected %q, got %q", errAllowanceZeroExpectedRedundancy, err)
}
a.ExpectedRedundancy = modules.DefaultAllowance.ExpectedRedundancy
// reasonable values; should succeed
a.Funds = types.SiacoinPrecision.Mul64(100)
a.RenewWindow = 10
err = c.SetAllowance(a)
if err != nil {
t.Fatal(err)
......@@ -457,10 +481,14 @@ func TestHostMaxDuration(t *testing.T) {
// Create allowance
a := modules.Allowance{
Funds: types.SiacoinPrecision.Mul64(100),
Hosts: 1,
Period: 30,
RenewWindow: 20,
Funds: types.SiacoinPrecision.Mul64(100),
Hosts: 1,
Period: 30,
RenewWindow: 20,
ExpectedStorage: modules.DefaultAllowance.ExpectedStorage,
ExpectedUpload: modules.DefaultAllowance.ExpectedUpload,
ExpectedDownload: modules.DefaultAllowance.ExpectedDownload,
ExpectedRedundancy: modules.DefaultAllowance.ExpectedRedundancy,
}
err = c.SetAllowance(a)
if err != nil {
......@@ -566,10 +594,14 @@ func TestLinkedContracts(t *testing.T) {
// Create allowance
a := modules.Allowance{
Funds: types.SiacoinPrecision.Mul64(100),
Hosts: 1,
Period: 20,
RenewWindow: 10,
Funds: types.SiacoinPrecision.Mul64(100),
Hosts: 1,
Period: 20,
RenewWindow: 10,
ExpectedStorage: modules.DefaultAllowance.ExpectedStorage,
ExpectedUpload: modules.DefaultAllowance.ExpectedUpload,
ExpectedDownload: modules.DefaultAllowance.ExpectedDownload,
ExpectedRedundancy: modules.DefaultAllowance.ExpectedRedundancy,
}
err = c.SetAllowance(a)
if err != nil {
......
......@@ -206,6 +206,12 @@ func TestIntegrationFormContract(t *testing.T) {
t.Fatal("no entry for host in db")
}
// set an allowance but don't use SetAllowance to avoid automatic contract
// formation.
c.mu.Lock()
c.allowance = modules.DefaultAllowance
c.mu.Unlock()
// form a contract with the host
_, _, err = c.managedNewContract(hostEntry, types.SiacoinPrecision.Mul64(50), c.blockHeight+100)
if err != nil {
......@@ -234,6 +240,12 @@ func TestIntegrationReviseContract(t *testing.T) {
t.Fatal("no entry for host in db")
}
// set an allowance but don't use SetAllowance to avoid automatic contract
// formation.
c.mu.Lock()
c.allowance = modules.DefaultAllowance
c.mu.Unlock()
// form a contract with the host
_, contract, err := c.managedNewContract(hostEntry, types.SiacoinPrecision.Mul64(50), c.blockHeight+100)
if err != nil {
......@@ -277,6 +289,12 @@ func TestIntegrationUploadDownload(t *testing.T) {
t.Fatal("no entry for host in db")
}
// set an allowance but don't use SetAllowance to avoid automatic contract
// formation.
c.mu.Lock()
c.allowance = modules.DefaultAllowance
c.mu.Unlock()
// form a contract with the host