github.com/fozzysec/SiaPrime@v0.0.0-20190612043147-66c8e8d11fe3/modules/renter.go (about)

     1  package modules
     2  
     3  import (
     4  	"encoding/json"
     5  	"io"
     6  	"time"
     7  
     8  	"SiaPrime/build"
     9  	"SiaPrime/crypto"
    10  	"SiaPrime/types"
    11  
    12  	"gitlab.com/NebulousLabs/errors"
    13  )
    14  
    15  var (
    16  	// DefaultAllowance is the set of default allowance settings that will be
    17  	// used when allowances are not set or not fully set
    18  	DefaultAllowance = Allowance{
    19  		Funds:       types.SiacoinPrecision.Mul64(500),
    20  		Hosts:       uint64(PriceEstimationScope),
    21  		Period:      types.BlockHeight(12096),
    22  		RenewWindow: types.BlockHeight(4032),
    23  	}
    24  
    25  	// ErrHostFault is an error that is usually extended to indicate that an error
    26  	// is the host's fault.
    27  	ErrHostFault = errors.New("host has returned an error")
    28  
    29  	// PriceEstimationScope is the number of hosts that get queried by the
    30  	// renter when providing price estimates. Especially for the 'Standard'
    31  	// variable, there should be congruence with the number of contracts being
    32  	// used in the renter allowance.
    33  	PriceEstimationScope = build.Select(build.Var{
    34  		Standard: int(50),
    35  		Dev:      int(12),
    36  		Testing:  int(4),
    37  	}).(int)
    38  
    39  	// DefaultUsageGuideLines is a sane set of guidelines.
    40  	DefaultUsageGuideLines = UsageGuidelines{
    41  		ExpectedStorage:           25e9,
    42  		ExpectedUploadFrequency:   24192,
    43  		ExpectedDownloadFrequency: 12096,
    44  		ExpectedRedundancy:        3.0,
    45  	}
    46  )
    47  
    48  // UsageGuidelines is a temporary helper struct.
    49  // TODO: These values should be rolled into the allowance, instead of being a
    50  // separate struct that we pass in.
    51  //
    52  // expectedStorage is the amount of data that we expect to have in a contract.
    53  //
    54  // expectedUploadFrequency is the expected number of blocks between each
    55  // complete re-upload of the filesystem. This will be a combination of the rate
    56  // at which a user uploads files, the rate at which a user replaces files, and
    57  // the rate at which a user has to repair files due to host churn. If the
    58  // expected storage is 25 GB and the expected upload frequency is 24 weeks, it
    59  // means the user is expected to do about 1 GB of upload per week on average
    60  // throughout the life of the contract.
    61  //
    62  // expectedDownloadFrequency is the expected number of blocks between each
    63  // complete download of the filesystem. This should include the user
    64  // downloading, streaming, and repairing files.
    65  //
    66  // expectedDataPieces and expectedParityPieces are used to give information
    67  // about the redundancy of the files being uploaded.
    68  type UsageGuidelines struct {
    69  	ExpectedStorage           uint64
    70  	ExpectedUploadFrequency   uint64
    71  	ExpectedDownloadFrequency uint64
    72  	ExpectedRedundancy        float64
    73  }
    74  
    75  // IsHostsFault indicates if a returned error is the host's fault.
    76  func IsHostsFault(err error) bool {
    77  	return errors.Contains(err, ErrHostFault)
    78  }
    79  
    80  const (
    81  	// RenterDir is the name of the directory that is used to store the
    82  	// renter's persistent data.
    83  	RenterDir = "renter"
    84  
    85  	// EstimatedFileContractTransactionSetSize is the estimated blockchain size
    86  	// of a transaction set between a renter and a host that contains a file
    87  	// contract. This transaction set will contain a setup transaction from each
    88  	// the host and the renter, and will also contain a file contract and file
    89  	// contract revision that have each been signed by all parties.
    90  	EstimatedFileContractTransactionSetSize = 2048
    91  )
    92  
    93  // An ErasureCoder is an error-correcting encoder and decoder.
    94  type ErasureCoder interface {
    95  	// NumPieces is the number of pieces returned by Encode.
    96  	NumPieces() int
    97  
    98  	// MinPieces is the minimum number of pieces that must be present to
    99  	// recover the original data.
   100  	MinPieces() int
   101  
   102  	// Encode splits data into equal-length pieces, with some pieces
   103  	// containing parity data.
   104  	Encode(data []byte) ([][]byte, error)
   105  
   106  	// EncodeShards encodes the input data like Encode but accepts an already
   107  	// sharded input.
   108  	EncodeShards(data [][]byte) ([][]byte, error)
   109  
   110  	// Recover recovers the original data from pieces and writes it to w.
   111  	// pieces should be identical to the slice returned by Encode (length and
   112  	// order must be preserved), but with missing elements set to nil. n is
   113  	// the number of bytes to be written to w; this is necessary because
   114  	// pieces may have been padded with zeros during encoding.
   115  	Recover(pieces [][]byte, n uint64, w io.Writer) error
   116  }
   117  
   118  // An Allowance dictates how much the Renter is allowed to spend in a given
   119  // period. Note that funds are spent on both storage and bandwidth.
   120  type Allowance struct {
   121  	Funds       types.Currency    `json:"funds"`
   122  	Hosts       uint64            `json:"hosts"`
   123  	Period      types.BlockHeight `json:"period"`
   124  	RenewWindow types.BlockHeight `json:"renewwindow"`
   125  }
   126  
   127  // ContractUtility contains metrics internal to the contractor that reflect the
   128  // utility of a given contract.
   129  type ContractUtility struct {
   130  	GoodForUpload bool
   131  	GoodForRenew  bool
   132  	Locked        bool // Locked utilities can only be set to false.
   133  }
   134  
   135  // DownloadInfo provides information about a file that has been requested for
   136  // download.
   137  type DownloadInfo struct {
   138  	Destination     string `json:"destination"`     // The destination of the download.
   139  	DestinationType string `json:"destinationtype"` // Can be "file", "memory buffer", or "http stream".
   140  	Length          uint64 `json:"length"`          // The length requested for the download.
   141  	Offset          uint64 `json:"offset"`          // The offset within the siafile requested for the download.
   142  	SiaPath         string `json:"siapath"`         // The siapath of the file used for the download.
   143  
   144  	Completed            bool      `json:"completed"`            // Whether or not the download has completed.
   145  	EndTime              time.Time `json:"endtime"`              // The time when the download fully completed.
   146  	Error                string    `json:"error"`                // Will be the empty string unless there was an error.
   147  	Received             uint64    `json:"received"`             // Amount of data confirmed and decoded.
   148  	StartTime            time.Time `json:"starttime"`            // The time when the download was started.
   149  	StartTimeUnix        int64     `json:"starttimeunix"`        // The time when the download was started in unix format.
   150  	TotalDataTransferred uint64    `json:"totaldatatransferred"` // Total amount of data transferred, including negotiation, etc.
   151  }
   152  
   153  // FileUploadParams contains the information used by the Renter to upload a
   154  // file.
   155  type FileUploadParams struct {
   156  	Source      string
   157  	SiaPath     string
   158  	ErasureCode ErasureCoder
   159  }
   160  
   161  // FileInfo provides information about a file.
   162  type FileInfo struct {
   163  	SiaPath        string            `json:"siapath"`
   164  	LocalPath      string            `json:"localpath"`
   165  	Filesize       uint64            `json:"filesize"`
   166  	Available      bool              `json:"available"`
   167  	Renewing       bool              `json:"renewing"`
   168  	Redundancy     float64           `json:"redundancy"`
   169  	UploadedBytes  uint64            `json:"uploadedbytes"`
   170  	UploadProgress float64           `json:"uploadprogress"`
   171  	Expiration     types.BlockHeight `json:"expiration"`
   172  	OnDisk         bool              `json:"ondisk"`
   173  	Recoverable    bool              `json:"recoverable"`
   174  }
   175  
   176  // A HostDBEntry represents one host entry in the Renter's host DB. It
   177  // aggregates the host's external settings and metrics with its public key.
   178  type HostDBEntry struct {
   179  	HostExternalSettings
   180  
   181  	// FirstSeen is the last block height at which this host was announced.
   182  	FirstSeen types.BlockHeight `json:"firstseen"`
   183  
   184  	// Measurements that have been taken on the host. The most recent
   185  	// measurements are kept in full detail, historic ones are compressed into
   186  	// the historic values.
   187  	HistoricDowntime time.Duration `json:"historicdowntime"`
   188  	HistoricUptime   time.Duration `json:"historicuptime"`
   189  	ScanHistory      HostDBScans   `json:"scanhistory"`
   190  
   191  	// Measurements that are taken whenever we interact with a host.
   192  	HistoricFailedInteractions     float64 `json:"historicfailedinteractions"`
   193  	HistoricSuccessfulInteractions float64 `json:"historicsuccessfulinteractions"`
   194  	RecentFailedInteractions       float64 `json:"recentfailedinteractions"`
   195  	RecentSuccessfulInteractions   float64 `json:"recentsuccessfulinteractions"`
   196  
   197  	LastHistoricUpdate types.BlockHeight `json:"lasthistoricupdate"`
   198  
   199  	// Measurements related to the IP subnet mask.
   200  	IPNets          []string  `json:"ipnets"`
   201  	LastIPNetChange time.Time `json:"lastipnetchange"`
   202  
   203  	// The public key of the host, stored separately to minimize risk of certain
   204  	// MitM based vulnerabilities.
   205  	PublicKey types.SiaPublicKey `json:"publickey"`
   206  }
   207  
   208  // HostDBScan represents a single scan event.
   209  type HostDBScan struct {
   210  	Timestamp time.Time `json:"timestamp"`
   211  	Success   bool      `json:"success"`
   212  }
   213  
   214  // HostScoreBreakdown provides a piece-by-piece explanation of why a host has
   215  // the score that they do.
   216  //
   217  // NOTE: Renters are free to use whatever scoring they feel appropriate for
   218  // hosts. Some renters will outright blacklist or whitelist sets of hosts. The
   219  // results provided by this struct can only be used as a guide, and may vary
   220  // significantly from machine to machine.
   221  type HostScoreBreakdown struct {
   222  	Score          types.Currency `json:"score"`
   223  	ConversionRate float64        `json:"conversionrate"`
   224  
   225  	AgeAdjustment              float64 `json:"ageadjustment"`
   226  	BurnAdjustment             float64 `json:"burnadjustment"`
   227  	CollateralAdjustment       float64 `json:"collateraladjustment"`
   228  	InteractionAdjustment      float64 `json:"interactionadjustment"`
   229  	PriceAdjustment            float64 `json:"pricesmultiplier"`
   230  	StorageRemainingAdjustment float64 `json:"storageremainingadjustment"`
   231  	UptimeAdjustment           float64 `json:"uptimeadjustment"`
   232  	VersionAdjustment          float64 `json:"versionadjustment"`
   233  }
   234  
   235  // RenterPriceEstimation contains a bunch of files estimating the costs of
   236  // various operations on the network.
   237  type RenterPriceEstimation struct {
   238  	// The cost of downloading 1 TB of data.
   239  	DownloadTerabyte types.Currency `json:"downloadterabyte"`
   240  
   241  	// The cost of forming a set of contracts using the defaults.
   242  	FormContracts types.Currency `json:"formcontracts"`
   243  
   244  	// The cost of storing 1 TB for a month, including redundancy.
   245  	StorageTerabyteMonth types.Currency `json:"storageterabytemonth"`
   246  
   247  	// The cost of consuming 1 TB of upload bandwidth from the host, including
   248  	// redundancy.
   249  	UploadTerabyte types.Currency `json:"uploadterabyte"`
   250  }
   251  
   252  // RenterSettings control the behavior of the Renter.
   253  type RenterSettings struct {
   254  	Allowance        Allowance `json:"allowance"`
   255  	MaxUploadSpeed   int64     `json:"maxuploadspeed"`
   256  	MaxDownloadSpeed int64     `json:"maxdownloadspeed"`
   257  	StreamCacheSize  uint64    `json:"streamcachesize"`
   258  }
   259  
   260  // HostDBScans represents a sortable slice of scans.
   261  type HostDBScans []HostDBScan
   262  
   263  func (s HostDBScans) Len() int           { return len(s) }
   264  func (s HostDBScans) Less(i, j int) bool { return s[i].Timestamp.Before(s[j].Timestamp) }
   265  func (s HostDBScans) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   266  
   267  // MerkleRootSet is a set of Merkle roots, and gets encoded more efficiently.
   268  type MerkleRootSet []crypto.Hash
   269  
   270  // MarshalJSON defines a JSON encoding for a MerkleRootSet.
   271  func (mrs MerkleRootSet) MarshalJSON() ([]byte, error) {
   272  	// Copy the whole array into a giant byte slice and then encode that.
   273  	fullBytes := make([]byte, crypto.HashSize*len(mrs))
   274  	for i := range mrs {
   275  		copy(fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize], mrs[i][:])
   276  	}
   277  	return json.Marshal(fullBytes)
   278  }
   279  
   280  // UnmarshalJSON attempts to decode a MerkleRootSet, falling back on the legacy
   281  // decoding of a []crypto.Hash if that fails.
   282  func (mrs *MerkleRootSet) UnmarshalJSON(b []byte) error {
   283  	// Decode the giant byte slice, and then split it into separate arrays.
   284  	var fullBytes []byte
   285  	err := json.Unmarshal(b, &fullBytes)
   286  	if err != nil {
   287  		// Encoding the byte slice has failed, try decoding it as a []crypto.Hash.
   288  		var hashes []crypto.Hash
   289  		err := json.Unmarshal(b, &hashes)
   290  		if err != nil {
   291  			return err
   292  		}
   293  		*mrs = MerkleRootSet(hashes)
   294  		return nil
   295  	}
   296  
   297  	umrs := make(MerkleRootSet, len(fullBytes)/32)
   298  	for i := range umrs {
   299  		copy(umrs[i][:], fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize])
   300  	}
   301  	*mrs = umrs
   302  	return nil
   303  }
   304  
   305  // A RenterContract contains metadata about a file contract. It is read-only;
   306  // modifying a RenterContract does not modify the actual file contract.
   307  type RenterContract struct {
   308  	ID            types.FileContractID
   309  	HostPublicKey types.SiaPublicKey
   310  	Transaction   types.Transaction
   311  
   312  	StartHeight types.BlockHeight
   313  	EndHeight   types.BlockHeight
   314  
   315  	// RenterFunds is the amount remaining in the contract that the renter can
   316  	// spend.
   317  	RenterFunds types.Currency
   318  
   319  	// The FileContract does not indicate what funds were spent on, so we have
   320  	// to track the various costs manually.
   321  	DownloadSpending types.Currency
   322  	StorageSpending  types.Currency
   323  	UploadSpending   types.Currency
   324  
   325  	// Utility contains utility information about the renter.
   326  	Utility ContractUtility
   327  
   328  	// TotalCost indicates the amount of money that the renter spent and/or
   329  	// locked up while forming a contract. This includes fees, and includes
   330  	// funds which were allocated (but not necessarily committed) to spend on
   331  	// uploads/downloads/storage.
   332  	TotalCost types.Currency
   333  
   334  	// ContractFee is the amount of money paid to the host to cover potential
   335  	// future transaction fees that the host may incur, and to cover any other
   336  	// overheads the host may have.
   337  	//
   338  	// TxnFee is the amount of money spent on the transaction fee when putting
   339  	// the renter contract on the blockchain.
   340  	//
   341  	// SiafundFee is the amount of money spent on siafund fees when creating the
   342  	// contract. The siafund fee that the renter pays covers both the renter and
   343  	// the host portions of the contract, and therefore can be unexpectedly high
   344  	// if the the host collateral is high.
   345  	ContractFee types.Currency
   346  	TxnFee      types.Currency
   347  	SiafundFee  types.Currency
   348  }
   349  
   350  // ContractorSpending contains the metrics about how much the Contractor has
   351  // spent during the current billing period.
   352  type ContractorSpending struct {
   353  	// ContractFees are the sum of all fees in the contract. This means it
   354  	// includes the ContractFee, TxnFee and SiafundFee
   355  	ContractFees types.Currency `json:"contractfees"`
   356  	// DownloadSpending is the money currently spent on downloads.
   357  	DownloadSpending types.Currency `json:"downloadspending"`
   358  	// StorageSpending is the money currently spent on storage.
   359  	StorageSpending types.Currency `json:"storagespending"`
   360  	// ContractSpending is the total amount of money that the renter has put
   361  	// into contracts, whether it's locked and the renter gets that money
   362  	// back or whether it's spent and the renter won't get the money back.
   363  	TotalAllocated types.Currency `json:"totalallocated"`
   364  	// UploadSpending is the money currently spent on uploads.
   365  	UploadSpending types.Currency `json:"uploadspending"`
   366  	// Unspent is locked-away, unspent money.
   367  	Unspent types.Currency `json:"unspent"`
   368  	// ContractSpendingDeprecated was renamed to TotalAllocated and always has the
   369  	// same value as TotalAllocated.
   370  	ContractSpendingDeprecated types.Currency `json:"contractspending"`
   371  	// WithheldFunds are the funds from the previous period that are tied up
   372  	// in contracts and have not been released yet
   373  	WithheldFunds types.Currency `json:"withheldfunds"`
   374  	// ReleaseBlock is the block at which the WithheldFunds should be
   375  	// released to the renter, based on worst case.
   376  	// Contract End Height + Host Window Size + Maturity Delay
   377  	ReleaseBlock types.BlockHeight `json:"releaseblock"`
   378  	// PreviousSpending is the total spend funds from old contracts
   379  	// that are not included in the current period spending
   380  	PreviousSpending types.Currency `json:"previousspending"`
   381  }
   382  
   383  // A Renter uploads, tracks, repairs, and downloads a set of files for the
   384  // user.
   385  type Renter interface {
   386  	// ActiveHosts provides the list of hosts that the renter is selecting,
   387  	// sorted by preference.
   388  	ActiveHosts() []HostDBEntry
   389  
   390  	// AllHosts returns the full list of hosts known to the renter.
   391  	AllHosts() []HostDBEntry
   392  
   393  	// Close closes the Renter.
   394  	Close() error
   395  
   396  	// CancelContract cancels a specific contract of the renter.
   397  	CancelContract(id types.FileContractID) error
   398  
   399  	// Contracts returns the staticContracts of the renter's hostContractor.
   400  	Contracts() []RenterContract
   401  
   402  	// OldContracts returns the oldContracts of the renter's hostContractor.
   403  	OldContracts() []RenterContract
   404  
   405  	// ContractUtility provides the contract utility for a given host key.
   406  	ContractUtility(pk types.SiaPublicKey) (ContractUtility, bool)
   407  
   408  	// CurrentPeriod returns the height at which the current allowance period
   409  	// began.
   410  	CurrentPeriod() types.BlockHeight
   411  
   412  	// PeriodSpending returns the amount spent on contracts in the current
   413  	// billing period.
   414  	PeriodSpending() ContractorSpending
   415  
   416  	// DeleteFile deletes a file entry from the renter.
   417  	DeleteFile(path string) error
   418  
   419  	// Download performs a download according to the parameters passed, including
   420  	// downloads of `offset` and `length` type.
   421  	Download(params RenterDownloadParameters) error
   422  
   423  	// Download performs a download according to the parameters passed without
   424  	// blocking, including downloads of `offset` and `length` type.
   425  	DownloadAsync(params RenterDownloadParameters) error
   426  
   427  	// ClearDownloadHistory clears the download history of the renter
   428  	// inclusive for before and after times.
   429  	ClearDownloadHistory(after, before time.Time) error
   430  
   431  	// DownloadHistory lists all the files that have been scheduled for download.
   432  	DownloadHistory() []DownloadInfo
   433  
   434  	// File returns information on specific file queried by user
   435  	File(siaPath string) (FileInfo, error)
   436  
   437  	// FileList returns information on all of the files stored by the renter.
   438  	FileList() []FileInfo
   439  
   440  	// Host provides the DB entry and score breakdown for the requested host.
   441  	Host(pk types.SiaPublicKey) (HostDBEntry, bool)
   442  
   443  	// InitialScanComplete returns a boolean indicating if the initial scan of the
   444  	// hostdb is completed.
   445  	InitialScanComplete() (bool, error)
   446  
   447  	// LoadSharedFiles loads a '.sia' file into the renter. A .sia file may
   448  	// contain multiple files. The paths of the added files are returned.
   449  	LoadSharedFiles(source string) ([]string, error)
   450  
   451  	// LoadSharedFilesASCII loads an ASCII-encoded '.sia' file into the
   452  	// renter.
   453  	LoadSharedFilesASCII(asciiSia string) ([]string, error)
   454  
   455  	// PriceEstimation estimates the cost in siacoins of performing various
   456  	// storage and data operations.
   457  	PriceEstimation(allowance Allowance) (RenterPriceEstimation, Allowance, error)
   458  
   459  	// RenameFile changes the path of a file.
   460  	RenameFile(path, newPath string) error
   461  
   462  	// EstimateHostScore will return the score for a host with the provided
   463  	// settings, assuming perfect age and uptime adjustments
   464  	EstimateHostScore(entry HostDBEntry, allowance Allowance) HostScoreBreakdown
   465  
   466  	// ScoreBreakdown will return the score for a host db entry using the
   467  	// hostdb's weighting algorithm.
   468  	ScoreBreakdown(entry HostDBEntry) HostScoreBreakdown
   469  
   470  	// Settings returns the Renter's current settings.
   471  	Settings() RenterSettings
   472  
   473  	// SetSettings sets the Renter's settings.
   474  	SetSettings(RenterSettings) error
   475  
   476  	// SetFileTrackingPath sets the on-disk location of an uploaded file to a
   477  	// new value. Useful if files need to be moved on disk.
   478  	SetFileTrackingPath(siaPath, newPath string) error
   479  
   480  	// ShareFiles creates a '.sia' file that can be shared with others.
   481  	ShareFiles(paths []string, shareDest string) error
   482  
   483  	// ShareFilesAscii creates an ASCII-encoded '.sia' file.
   484  	ShareFilesASCII(paths []string) (asciiSia string, err error)
   485  
   486  	// Streamer creates a io.ReadSeeker that can be used to stream downloads
   487  	// from the Sia network and also returns the fileName of the streamed
   488  	// resource.
   489  	Streamer(siaPath string) (string, io.ReadSeeker, error)
   490  
   491  	// Upload uploads a file using the input parameters.
   492  	Upload(FileUploadParams) error
   493  }
   494  
   495  // RenterDownloadParameters defines the parameters passed to the Renter's
   496  // Download method.
   497  type RenterDownloadParameters struct {
   498  	Async       bool
   499  	Httpwriter  io.Writer
   500  	Length      uint64
   501  	Offset      uint64
   502  	SiaPath     string
   503  	Destination string
   504  }