github.com/dmmcquay/sia@v1.3.1-0.20180712220038-9f8d535311b9/modules/renter.go (about)

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