contractor

package
v1.4.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 12, 2019 License: MIT Imports: 20 Imported by: 0

README

Contractor

Coming Soon...

Documentation

Overview

Package contractor is responsible for forming and renewing file contracts with hosts. Its goal is to manage the low-level details of the negotiation, revision, and renewal protocols, such that the renter can operate at a higher level of abstraction. Ideally, the renter should be mostly ignorant of the Sia protocol, instead focusing on file management, redundancy, and upload/download algorithms.

Contract formation does not begin until the user first calls SetAllowance. An allowance dictates how much money the contractor is allowed to spend on file contracts during a given period. When the user calls SetAllowance for the first time, the call will block until contracts have been negotiated with the specified number of hosts. Upon subsequent calls, new contracts will only be formed if the allowance is sufficiently greater than the previous allowance, where "sufficiently greater" currently means "enough money to pay for at least one additional sector on every host." This allows the user to increase the amount of available storage immediately, at the cost of some complexity.

The contractor forms many contracts in parallel with different host, and tries to keep all the contracts "consistent" -- that is, they should all have the same storage capacity, and they should all end at the same height. Hosts are selected from the HostDB; there is no support for manually specifying hosts.

Contracts are automatically renewed by the contractor at a safe threshold before they are set to expire. When contracts are renewed, they are renewed with the current allowance, which may differ from the allowance that was used to form the initial contracts. In general, this means that allowance modifications only take effect upon the next "contract cycle" (the exception being "sufficiently greater" modifications, as defined above).

As an example, imagine that the user first sets an allowance that will cover 10 contracts of 10 sectors each for 100 blocks. The contractor will immediately form contracts with 10 hosts, paying each host enough to cover 10 sectors for 100 blocks. Then, 20 blocks later, the user increases the allowance, such that it now covers 10 contracts of 20 sectors for 200 blocks. The contractor will immediately form contracts as follows:

  • 10 contracts will be formed with the current hosts, each covering 10 sectors for 80 blocks.
  • 10 contracts will be formed with new hosts, each covering 20 sectors for 80 blocks.

Note that these newly-formed contracts are timed to expire in sync with the existing contracts. This becomes the new "contract set," totaling 30 contracts, but only 20 hosts, with 20 sectors per host. When it comes time to renew these contracts, only one contract will be renewed per host, and the contracts will be renewed for the full 200-block duration. The new contract set will thus consist of 20 contracts, 20 hosts, 20 sectors, 200 blocks.

On the other hand, if the allowance is decreased, no immediate action is taken. Why? Because the contracts have already been paid for. The new allowance will only take effect upon the next renewal.

Modifications to file contracts are mediated through the Editor interface. An Editor maintains a network connection to a host, over which is sends modification requests, such as "delete sector 12." After each modification, the Editor revises the underlying file contract and saves it to disk.

The primary challenge of the contractor is that it must be smart enough for the user to feel comfortable allowing it to spend their money. Because contract renewal is a background task, it is difficult to report errors to the user and defer to their decision. For example, what should the contractor do in the following scenarios?

  • The contract set is up for renewal, but the average host price has increased, and now the allowance is not sufficient to cover all of the user's uploaded data.
  • The user sets an allowance of 10 hosts. The contractor forms 5 contracts, but the rest fail, and the remaining hosts in the HostDB are too expensive.
  • After contract formation succeeds, 2 of 10 hosts become unresponsive. Later, another 4 become unresponsive.

Waiting for user input is dangerous because if the contract period elapses, data is permanently lost. The contractor should treat this as the worst-case scenario, and take steps to prevent it, so long as the allowance is not exceeded. However, since the contractor has no concept of redundancy, it is not well-positioned to determine which sectors to sacrifice and which to preserve. The contractor also lacks the ability to reupload data; it can download sectors, but it does not know the decryption keys or erasure coding metadata required to reconstruct the original data. It follows that these responsibilities must be delegated to the renter.

Index

Constants

This section is empty.

Variables

View Source
var (

	// MinContractFundRenewalThreshold defines the ratio of remaining funds to
	// total contract cost below which the contractor will prematurely renew a
	// contract.
	//
	// This number is deliberately a little higher than the
	// minContractFundUploadThreshold because we want to make sure that renewals
	// will kick in before uploading stops.
	MinContractFundRenewalThreshold = float64(0.06) // 6%

	// minContractFundUploadThreshold is the percentage of contract funds
	// remaining at which the contract gets marked !GoodForUpload. The number is
	// high so that there is plenty of money available for downloading, so that
	// urgent repairs can be performed and also so that user file access is not
	// interrupted until after uploading progress is interrupted. Structuring
	// things this way essentially allows the user to experience the failure
	// mode of 'can't store additional stuff' before the user experiences the
	// failure mode of 'can't retrieve stuff already uploaded'.
	MinContractFundUploadThreshold = float64(0.05) // 5%

)

Constants related to contract formation parameters.

View Source
var (

	// ErrAllowanceZeroWindow is returned when the caller requests a
	// zero-length renewal window. This will happen if the caller sets the
	// period to 1 block, since RenewWindow := period / 2.
	ErrAllowanceZeroWindow = errors.New("renew window must be non-zero")
)
View Source
var (
	// ErrInsufficientAllowance indicates that the renter's allowance is less
	// than the amount necessary to store at least one sector
	ErrInsufficientAllowance = errors.New("allowance is not large enough to cover fees of contract creation")
)

Functions

func NewPersist added in v1.3.3

func NewPersist(dir string) *stdPersist

NewPersist create a new stdPersist.

Types

type Contractor

type Contractor struct {
	// contains filtered or unexported fields
}

A Contractor negotiates, revises, renews, and provides access to file contracts.

func New

func New(cs consensusSet, wallet walletShim, tpool transactionPool, hdb hostDB, persistDir string) (*Contractor, error)

New returns a new Contractor.

func NewCustomContractor added in v1.3.3

func NewCustomContractor(cs consensusSet, w wallet, tp transactionPool, hdb hostDB, contractSet *proto.ContractSet, p persister, l *persist.Logger, deps modules.Dependencies) (*Contractor, error)

NewCustomContractor creates a Contractor using the provided dependencies.

func (*Contractor) Allowance

func (c *Contractor) Allowance() modules.Allowance

Allowance returns the current allowance.

func (*Contractor) CancelContract added in v1.3.4

func (c *Contractor) CancelContract(id types.FileContractID) error

CancelContract cancels the Contractor's contract by marking it !GoodForRenew and !GoodForUpload

func (*Contractor) Close added in v1.1.1

func (c *Contractor) Close() error

Close closes the Contractor.

func (*Contractor) ContractByPublicKey added in v1.3.4

func (c *Contractor) ContractByPublicKey(pk types.SiaPublicKey) (modules.RenterContract, bool)

ContractByPublicKey returns the contract with the key specified, if it exists. The contract will be resolved if possible to the most recent child contract.

func (*Contractor) ContractUtility added in v1.3.1

func (c *Contractor) ContractUtility(pk types.SiaPublicKey) (modules.ContractUtility, bool)

ContractUtility returns the utility fields for the given contract.

func (*Contractor) Contracts

func (c *Contractor) Contracts() []modules.RenterContract

Contracts returns the contracts formed by the contractor in the current allowance period. Only contracts formed with currently online hosts are returned.

func (*Contractor) CurrentPeriod added in v1.1.0

func (c *Contractor) CurrentPeriod() types.BlockHeight

CurrentPeriod returns the height at which the current allowance period began.

func (*Contractor) Downloader

func (c *Contractor) Downloader(pk types.SiaPublicKey, cancel <-chan struct{}) (_ Downloader, err error)

Downloader returns a Downloader object that can be used to download sectors from a host.

func (*Contractor) Editor

func (c *Contractor) Editor(pk types.SiaPublicKey, cancel <-chan struct{}) (_ Editor, err error)

Editor returns a Editor object that can be used to upload, modify, and delete sectors on a host.

func (*Contractor) InitRecoveryScan added in v1.4.0

func (c *Contractor) InitRecoveryScan() (err error)

InitRecoveryScan starts scanning the whole blockchain for recoverable contracts within a separate thread.

func (*Contractor) IsOffline added in v1.1.0

func (c *Contractor) IsOffline(pk types.SiaPublicKey) bool

IsOffline indicates whether a contract's host should be considered offline, based on its scan metrics.

func (*Contractor) OldContracts added in v1.3.4

func (c *Contractor) OldContracts() []modules.RenterContract

OldContracts returns the contracts formed by the contractor that have expired

func (*Contractor) PeriodSpending added in v1.3.1

func (c *Contractor) PeriodSpending() modules.ContractorSpending

PeriodSpending returns the amount spent on contracts during the current billing period.

func (*Contractor) ProcessConsensusChange

func (c *Contractor) ProcessConsensusChange(cc modules.ConsensusChange)

ProcessConsensusChange will be called by the consensus set every time there is a change in the blockchain. Updates will always be called in order.

func (*Contractor) RateLimits added in v1.3.3

func (c *Contractor) RateLimits() (readBPW int64, writeBPS int64, packetSize uint64)

RateLimits sets the bandwidth limits for connections created by the contractSet.

func (*Contractor) RecoverableContracts added in v1.4.0

func (c *Contractor) RecoverableContracts() []modules.RecoverableContract

RecoverableContracts returns the contracts that the contractor deems recoverable. That means they are not expired yet and also not part of the active contracts. Usually this should return an empty slice unless the host isn't available for recovery or something went wrong.

func (*Contractor) RecoveryScanStatus added in v1.4.0

func (c *Contractor) RecoveryScanStatus() (bool, types.BlockHeight)

RecoveryScanStatus returns a bool indicating if a scan for recoverable contracts is in progress and if it is, the current progress of the scan.

func (*Contractor) RefreshedContract added in v1.4.1

func (c *Contractor) RefreshedContract(fcid types.FileContractID) bool

RefreshedContract returns a bool indicating if the contract was a refreshed contract. A refreshed contract refers to a contract that ran out of funds prior to the end height and so was renewed with the host in the same period. Both the old and the new contract have the same end height

func (*Contractor) Session added in v1.4.0

func (c *Contractor) Session(pk types.SiaPublicKey, cancel <-chan struct{}) (_ Session, err error)

Session returns a Session object that can be used to upload, modify, and delete sectors on a host.

func (*Contractor) SetAllowance

func (c *Contractor) SetAllowance(a modules.Allowance) error

SetAllowance sets the amount of money the Contractor is allowed to spend on contracts over a given time period, divided among the number of hosts specified. Note that Contractor can start forming contracts as soon as SetAllowance is called; that is, it may block.

In most cases, SetAllowance will renew existing contracts instead of forming new ones. This preserves the data on those hosts. When this occurs, the renewed contracts will atomically replace their previous versions. If SetAllowance is interrupted, renewed contracts may be lost, though the allocated funds will eventually be returned.

If a is the empty allowance, SetAllowance will archive the current contract set. The contracts cannot be used to create Editors or Downloads, and will not be renewed.

NOTE: At this time, transaction fees are not counted towards the allowance. This means the contractor may spend more than allowance.Funds.

func (*Contractor) SetRateLimits added in v1.3.3

func (c *Contractor) SetRateLimits(readBPS int64, writeBPS int64, packetSize uint64)

SetRateLimits sets the bandwidth limits for connections created by the contractSet.

type Downloader

type Downloader interface {
	// Download requests the specified sector data.
	Download(root crypto.Hash, offset, length uint32) ([]byte, error)

	// Close terminates the connection to the host.
	Close() error
}

An Downloader retrieves sectors from with a host. It requests one sector at a time, and revises the file contract to transfer money to the host proportional to the data retrieved.

type Editor

type Editor interface {
	// Upload revises the underlying contract to store the new data. It
	// returns the Merkle root of the data.
	Upload(data []byte) (root crypto.Hash, err error)

	// Address returns the address of the host.
	Address() modules.NetAddress

	// ContractID returns the FileContractID of the contract.
	ContractID() types.FileContractID

	// EndHeight returns the height at which the contract ends.
	EndHeight() types.BlockHeight

	// Close terminates the connection to the host.
	Close() error
}

An Editor modifies a Contract by communicating with a host. It uses the contract revision protocol to send modification requests to the host. Editors are the means by which the renter uploads data to hosts.

type Session added in v1.4.0

type Session interface {
	// Address returns the address of the host.
	Address() modules.NetAddress

	// Close terminates the connection to the host.
	Close() error

	// ContractID returns the FileContractID of the contract.
	ContractID() types.FileContractID

	// Download requests the specified sector data.
	Download(root crypto.Hash, offset, length uint32) ([]byte, error)

	// DownloadIndex requests data from the sector with the specified index
	// within the contract.
	DownloadIndex(index uint64, offset, length uint32) ([]byte, error)

	// EndHeight returns the height at which the contract ends.
	EndHeight() types.BlockHeight

	// Upload revises the underlying contract to store the new data. It
	// returns the Merkle root of the data.
	Upload(data []byte) (crypto.Hash, error)

	// Replace replaces the sector at the specified index with data. The old
	// sector is swapped to the end of the contract data, and is deleted if the
	// trim flag is set.
	Replace(data []byte, sectorIndex uint64, trim bool) (crypto.Hash, error)
}

A Session modifies a Contract by communicating with a host. It uses the renter-host protocol to send modification requests to the host. Among other things, Sessions are the means by which the renter transfers file data to and from hosts.

type WalletBridge added in v1.3.3

type WalletBridge struct {
	W walletShim
}

WalletBridge is a bridge for the wallet because wallet is not directly compatible with modules.Wallet (wrong type signature for StartTransaction), we must provide a bridge type.

func (*WalletBridge) NextAddress added in v1.3.3

func (ws *WalletBridge) NextAddress() (types.UnlockConditions, error)

NextAddress computes and returns the next address of the wallet.

func (*WalletBridge) PrimarySeed added in v1.4.0

func (ws *WalletBridge) PrimarySeed() (modules.Seed, uint64, error)

PrimarySeed returns the primary wallet seed.

func (*WalletBridge) StartTransaction added in v1.3.3

func (ws *WalletBridge) StartTransaction() (transactionBuilder, error)

StartTransaction creates a new transactionBuilder that can be used to create and sign a transaction.

func (*WalletBridge) Unlocked added in v1.4.1

func (ws *WalletBridge) Unlocked() (bool, error)

Unlocked reports whether the wallet bridge is unlocked.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL