gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/negotiate.go (about)

     1  package modules
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/cipher"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"net"
    10  	"strings"
    11  	"time"
    12  
    13  	"gitlab.com/NebulousLabs/fastrand"
    14  	"gitlab.com/SiaPrime/SiaPrime/build"
    15  	"gitlab.com/SiaPrime/SiaPrime/crypto"
    16  	"gitlab.com/SiaPrime/SiaPrime/encoding"
    17  	"gitlab.com/SiaPrime/SiaPrime/types"
    18  	"golang.org/x/crypto/chacha20poly1305"
    19  )
    20  
    21  const (
    22  	// AcceptResponse is the response given to an RPC call to indicate
    23  	// acceptance, i.e. that the sender wishes to continue communication.
    24  	AcceptResponse = "accept"
    25  
    26  	// StopResponse is the response given to an RPC call to indicate graceful
    27  	// termination, i.e. that the sender wishes to cease communication, but
    28  	// not due to an error.
    29  	StopResponse = "stop"
    30  )
    31  
    32  const (
    33  	// NegotiateDownloadTime defines the amount of time that the renter and
    34  	// host have to negotiate a download request batch. The time is set high
    35  	// enough that two nodes behind Tor have a reasonable chance of completing
    36  	// the negotiation.
    37  	NegotiateDownloadTime = 600 * time.Second
    38  
    39  	// NegotiateFileContractRevisionTime defines the minimum amount of time
    40  	// that the renter and host have to negotiate a file contract revision. The
    41  	// time is set high enough that a full 4MB can be piped through a
    42  	// connection that is running over Tor.
    43  	NegotiateFileContractRevisionTime = 600 * time.Second
    44  
    45  	// NegotiateFileContractTime defines the amount of time that the renter and
    46  	// host have to negotiate a file contract. The time is set high enough that
    47  	// a node behind Tor has a reasonable chance at making the multiple
    48  	// required round trips to complete the negotiation.
    49  	NegotiateFileContractTime = 360 * time.Second
    50  
    51  	// NegotiateMaxDownloadActionRequestSize defines the maximum size that a
    52  	// download request can be. Note, this is not a max size for the data that
    53  	// can be requested, but instead is a max size for the definition of the
    54  	// data being requested.
    55  	NegotiateMaxDownloadActionRequestSize = 50e3
    56  
    57  	// NegotiateMaxErrorSize indicates the maximum number of bytes that can be
    58  	// used to encode an error being sent during negotiation.
    59  	NegotiateMaxErrorSize = 256
    60  
    61  	// NegotiateMaxFileContractRevisionSize specifies the maximum size that a
    62  	// file contract revision is allowed to have when being sent over the wire
    63  	// during negotiation.
    64  	NegotiateMaxFileContractRevisionSize = 3e3
    65  
    66  	// NegotiateMaxFileContractSetLen determines the maximum allowed size of a
    67  	// transaction set that can be sent when trying to negotiate a file
    68  	// contract. The transaction set will contain all of the unconfirmed
    69  	// dependencies of the file contract, meaning that it can be quite large.
    70  	// The transaction pool's size limit for transaction sets has been chosen
    71  	// as a reasonable guideline for determining what is too large.
    72  	NegotiateMaxFileContractSetLen = TransactionSetSizeLimit - 1e3
    73  
    74  	// NegotiateMaxHostExternalSettingsLen is the maximum allowed size of an
    75  	// encoded HostExternalSettings.
    76  	NegotiateMaxHostExternalSettingsLen = 16000
    77  
    78  	// NegotiateMaxSiaPubkeySize defines the maximum size that a SiaPubkey is
    79  	// allowed to be when being sent over the wire during negotiation.
    80  	NegotiateMaxSiaPubkeySize = 1e3
    81  
    82  	// NegotiateMaxTransactionSignatureSize defines the maximum size that a
    83  	// transaction signature is allowed to be when being sent over the wire
    84  	// during negotiation.
    85  	NegotiateMaxTransactionSignatureSize = 2e3
    86  
    87  	// NegotiateMaxTransactionSignaturesSize defines the maximum size that a
    88  	// transaction signature slice is allowed to be when being sent over the
    89  	// wire during negotiation.
    90  	NegotiateMaxTransactionSignaturesSize = 5e3
    91  
    92  	// NegotiateRecentRevisionTime establishes the minimum amount of time that
    93  	// the connection deadline is expected to be set to when a recent file
    94  	// contract revision is being requested from the host. The deadline is long
    95  	// enough that the connection should be successful even if both parties are
    96  	// running Tor.
    97  	NegotiateRecentRevisionTime = 120 * time.Second
    98  
    99  	// NegotiateRenewContractTime defines the minimum amount of time that the
   100  	// renter and host have to negotiate a final contract renewal. The time is
   101  	// high enough that the negotiation can occur over a Tor connection, and
   102  	// that both the host and the renter can have time to process large Merkle
   103  	// tree calculations that may be involved with renewing a file contract.
   104  	NegotiateRenewContractTime = 600 * time.Second
   105  )
   106  
   107  var (
   108  	// ErrInsufficientStorageForSector is returned if the host tries to add a
   109  	// sector when there is not enough storage remaining on the host to accept
   110  	// the sector.
   111  	//
   112  	// Ideally, the host will adjust pricing as the host starts to fill up, so
   113  	// this error should be pretty rare. Demand should drive the price up
   114  	// faster than the Host runs out of space, such that the host is always
   115  	// hovering around 95% capacity and rarely over 98% or under 90% capacity.
   116  	ErrInsufficientStorageForSector = errors.New("not enough storage remaining to accept sector")
   117  )
   118  
   119  var (
   120  	// NegotiateSettingsTime establishes the minimum amount of time that the
   121  	// connection deadline is expected to be set to when settings are being
   122  	// requested from the host. The deadline is long enough that the connection
   123  	// should be successful even if both parties are on Tor.
   124  	NegotiateSettingsTime = build.Select(build.Var{
   125  		Dev:      120 * time.Second,
   126  		Standard: 120 * time.Second,
   127  		Testing:  3 * time.Second,
   128  	}).(time.Duration)
   129  )
   130  
   131  var (
   132  	// ActionDelete is the specifier for a RevisionAction that deletes a
   133  	// sector.
   134  	ActionDelete = types.Specifier{'D', 'e', 'l', 'e', 't', 'e'}
   135  
   136  	// ActionInsert is the specifier for a RevisionAction that inserts a
   137  	// sector.
   138  	ActionInsert = types.Specifier{'I', 'n', 's', 'e', 'r', 't'}
   139  
   140  	// ActionModify is the specifier for a RevisionAction that modifies sector
   141  	// data.
   142  	ActionModify = types.Specifier{'M', 'o', 'd', 'i', 'f', 'y'}
   143  
   144  	// ErrAnnNotAnnouncement indicates that the provided host announcement does
   145  	// not use a recognized specifier, indicating that it's either not a host
   146  	// announcement or it's not a recognized version of a host announcement.
   147  	ErrAnnNotAnnouncement = errors.New("provided data does not form a recognized host announcement")
   148  
   149  	// ErrAnnUnrecognizedSignature is returned when the signature in a host
   150  	// announcement is not a type of signature that is recognized.
   151  	ErrAnnUnrecognizedSignature = errors.New("the signature provided in the host announcement is not recognized")
   152  
   153  	// ErrRevisionCoveredFields is returned if there is a covered fields object
   154  	// in a transaction signature which has the 'WholeTransaction' field set to
   155  	// true, meaning that miner fees cannot be added to the transaction without
   156  	// invalidating the signature.
   157  	ErrRevisionCoveredFields = errors.New("file contract revision transaction signature does not allow miner fees to be added")
   158  
   159  	// ErrRevisionSigCount is returned when a file contract revision has the
   160  	// wrong number of transaction signatures.
   161  	ErrRevisionSigCount = errors.New("file contract revision has the wrong number of transaction signatures")
   162  
   163  	// ErrStopResponse is the error returned by ReadNegotiationAcceptance when
   164  	// it reads the StopResponse string.
   165  	ErrStopResponse = errors.New("sender wishes to stop communicating")
   166  
   167  	// PrefixHostAnnouncement is used to indicate that a transaction's
   168  	// Arbitrary Data field contains a host announcement. The encoded
   169  	// announcement will follow this prefix.
   170  	PrefixHostAnnouncement = types.Specifier{'H', 'o', 's', 't', 'A', 'n', 'n', 'o', 'u', 'n', 'c', 'e', 'm', 'e', 'n', 't'}
   171  
   172  	// PrefixFileContractIdentifier is used to indicate that a transaction's
   173  	// Arbitrary Data field contains a file contract identifier. The identifier
   174  	// and its signature will follow this prefix.
   175  	PrefixFileContractIdentifier = types.Specifier{'F', 'C', 'I', 'd', 'e', 'n', 't', 'i', 'f', 'i', 'e', 'r'}
   176  
   177  	// RPCDownload is the specifier for downloading a file from a host.
   178  	RPCDownload = types.Specifier{'D', 'o', 'w', 'n', 'l', 'o', 'a', 'd', 2}
   179  
   180  	// RPCFormContract is the specifier for forming a contract with a host.
   181  	RPCFormContract = types.Specifier{'F', 'o', 'r', 'm', 'C', 'o', 'n', 't', 'r', 'a', 'c', 't', 2}
   182  
   183  	// RPCRenewContract is the specifier to renewing an existing contract.
   184  	RPCRenewContract = types.Specifier{'R', 'e', 'n', 'e', 'w', 'C', 'o', 'n', 't', 'r', 'a', 'c', 't', 2}
   185  
   186  	// RPCReviseContract is the specifier for revising an existing file
   187  	// contract.
   188  	RPCReviseContract = types.Specifier{'R', 'e', 'v', 'i', 's', 'e', 'C', 'o', 'n', 't', 'r', 'a', 'c', 't', 2}
   189  
   190  	// RPCSettings is the specifier for requesting settings from the host.
   191  	RPCSettings = types.Specifier{'S', 'e', 't', 't', 'i', 'n', 'g', 's', 2}
   192  
   193  	// SectorSize defines how large a sector should be in bytes. The sector
   194  	// size needs to be a power of two to be compatible with package
   195  	// merkletree. 4MB has been chosen for the live network because large
   196  	// sectors significantly reduce the tracking overhead experienced by the
   197  	// renter and the host.
   198  	SectorSize = build.Select(build.Var{
   199  		Dev:      uint64(1 << 18), // 256 KiB
   200  		Standard: uint64(1 << 22), // 4 MiB
   201  		Testing:  uint64(1 << 12), // 4 KiB
   202  	}).(uint64)
   203  )
   204  
   205  type (
   206  	// A DownloadAction is a description of a download that the renter would
   207  	// like to make. The MerkleRoot indicates the root of the sector, the
   208  	// offset indicates what portion of the sector is being downloaded, and the
   209  	// length indicates how many bytes should be grabbed starting from the
   210  	// offset.
   211  	DownloadAction struct {
   212  		MerkleRoot crypto.Hash
   213  		Offset     uint64
   214  		Length     uint64
   215  	}
   216  
   217  	// HostAnnouncement is an announcement by the host that appears in the
   218  	// blockchain. 'Specifier' is always 'PrefixHostAnnouncement'. The
   219  	// announcement is always followed by a signature from the public key of
   220  	// the whole announcement.
   221  	HostAnnouncement struct {
   222  		Specifier  types.Specifier
   223  		NetAddress NetAddress
   224  		PublicKey  types.SiaPublicKey
   225  	}
   226  
   227  	// HostExternalSettings are the parameters advertised by the host. These
   228  	// are the values that the renter will request from the host in order to
   229  	// build its database.
   230  	HostExternalSettings struct {
   231  		// MaxBatchSize indicates the maximum size in bytes that a batch is
   232  		// allowed to be. A batch is an array of revision actions; each
   233  		// revision action can have a different number of bytes, depending on
   234  		// the action, so the number of revision actions allowed depends on the
   235  		// sizes of each.
   236  		AcceptingContracts   bool              `json:"acceptingcontracts"`
   237  		MaxDownloadBatchSize uint64            `json:"maxdownloadbatchsize"`
   238  		MaxDuration          types.BlockHeight `json:"maxduration"`
   239  		MaxReviseBatchSize   uint64            `json:"maxrevisebatchsize"`
   240  		NetAddress           NetAddress        `json:"netaddress"`
   241  		RemainingStorage     uint64            `json:"remainingstorage"`
   242  		SectorSize           uint64            `json:"sectorsize"`
   243  		TotalStorage         uint64            `json:"totalstorage"`
   244  		UnlockHash           types.UnlockHash  `json:"unlockhash"`
   245  		WindowSize           types.BlockHeight `json:"windowsize"`
   246  
   247  		// Collateral is the amount of collateral that the host will put up for
   248  		// storage in 'bytes per block', as an assurance to the renter that the
   249  		// host really is committed to keeping the file. But, because the file
   250  		// contract is created with no data available, this does leave the host
   251  		// exposed to an attack by a wealthy renter whereby the renter causes
   252  		// the host to lockup in-advance a bunch of funds that the renter then
   253  		// never uses, meaning the host will not have collateral for other
   254  		// clients.
   255  		//
   256  		// MaxCollateral indicates the maximum number of coins that a host is
   257  		// willing to put into a file contract.
   258  		Collateral    types.Currency `json:"collateral"`
   259  		MaxCollateral types.Currency `json:"maxcollateral"`
   260  
   261  		// ContractPrice is the number of coins that the renter needs to pay to
   262  		// the host just to open a file contract with them. Generally, the price
   263  		// is only to cover the siacoin fees that the host will suffer when
   264  		// submitting the file contract revision and storage proof to the
   265  		// blockchain.
   266  		//
   267  		// BaseRPC price is a flat per-RPC fee charged by the host for any
   268  		// non-free RPC.
   269  		//
   270  		// 'Download' bandwidth price is the cost per byte of downloading data
   271  		// from the host. This includes metadata such as Merkle proofs.
   272  		//
   273  		// SectorAccessPrice is the cost per sector of data accessed when
   274  		// downloading data.
   275  		//
   276  		// StoragePrice is the cost per-byte-per-block in hastings of storing
   277  		// data on the host.
   278  		//
   279  		// 'Upload' bandwidth price is the cost per byte of uploading data to
   280  		// the host.
   281  		BaseRPCPrice           types.Currency `json:"baserpcprice"`
   282  		ContractPrice          types.Currency `json:"contractprice"`
   283  		DownloadBandwidthPrice types.Currency `json:"downloadbandwidthprice"`
   284  		SectorAccessPrice      types.Currency `json:"sectoraccessprice"`
   285  		StoragePrice           types.Currency `json:"storageprice"`
   286  		UploadBandwidthPrice   types.Currency `json:"uploadbandwidthprice"`
   287  
   288  		// Because the host has a public key, and settings are signed, and
   289  		// because settings may be MITM'd, settings need a revision number so
   290  		// that a renter can compare multiple sets of settings and determine
   291  		// which is the most recent.
   292  		RevisionNumber uint64 `json:"revisionnumber"`
   293  		Version        string `json:"version"`
   294  	}
   295  
   296  	// HostOldExternalSettings are the pre-v1.4.0 host settings.
   297  	HostOldExternalSettings struct {
   298  		AcceptingContracts     bool              `json:"acceptingcontracts"`
   299  		MaxDownloadBatchSize   uint64            `json:"maxdownloadbatchsize"`
   300  		MaxDuration            types.BlockHeight `json:"maxduration"`
   301  		MaxReviseBatchSize     uint64            `json:"maxrevisebatchsize"`
   302  		NetAddress             NetAddress        `json:"netaddress"`
   303  		RemainingStorage       uint64            `json:"remainingstorage"`
   304  		SectorSize             uint64            `json:"sectorsize"`
   305  		TotalStorage           uint64            `json:"totalstorage"`
   306  		UnlockHash             types.UnlockHash  `json:"unlockhash"`
   307  		WindowSize             types.BlockHeight `json:"windowsize"`
   308  		Collateral             types.Currency    `json:"collateral"`
   309  		MaxCollateral          types.Currency    `json:"maxcollateral"`
   310  		ContractPrice          types.Currency    `json:"contractprice"`
   311  		DownloadBandwidthPrice types.Currency    `json:"downloadbandwidthprice"`
   312  		StoragePrice           types.Currency    `json:"storageprice"`
   313  		UploadBandwidthPrice   types.Currency    `json:"uploadbandwidthprice"`
   314  		RevisionNumber         uint64            `json:"revisionnumber"`
   315  		Version                string            `json:"version"`
   316  	}
   317  
   318  	// A RevisionAction is a description of an edit to be performed on a file
   319  	// contract. Three types are allowed, 'ActionDelete', 'ActionInsert', and
   320  	// 'ActionModify'. ActionDelete just takes a sector index, indicating which
   321  	// sector is going to be deleted. ActionInsert takes a sector index, and a
   322  	// full sector of data, indicating that a sector at the index should be
   323  	// inserted with the provided data. 'Modify' revises the sector at the
   324  	// given index, rewriting it with the provided data starting from the
   325  	// 'offset' within the sector.
   326  	//
   327  	// Modify could be simulated with an insert and a delete, however an insert
   328  	// requires a full sector to be uploaded, and a modify can be just a few
   329  	// kb, which can be significantly faster.
   330  	RevisionAction struct {
   331  		Type        types.Specifier
   332  		SectorIndex uint64
   333  		Offset      uint64
   334  		Data        []byte
   335  	}
   336  )
   337  
   338  // New RPC IDs
   339  var (
   340  	RPCLoopEnter         = types.Specifier{'L', 'o', 'o', 'p', 'E', 'n', 't', 'e', 'r'}
   341  	RPCLoopExit          = types.Specifier{'L', 'o', 'o', 'p', 'E', 'x', 'i', 't'}
   342  	RPCLoopFormContract  = types.Specifier{'L', 'o', 'o', 'p', 'F', 'o', 'r', 'm', 'C', 'o', 'n', 't', 'r', 'a', 'c', 't'}
   343  	RPCLoopLock          = types.Specifier{'L', 'o', 'o', 'p', 'L', 'o', 'c', 'k'}
   344  	RPCLoopRead          = types.Specifier{'L', 'o', 'o', 'p', 'R', 'e', 'a', 'd'}
   345  	RPCLoopRenewContract = types.Specifier{'L', 'o', 'o', 'p', 'R', 'e', 'n', 'e', 'w'}
   346  	RPCLoopSectorRoots   = types.Specifier{'L', 'o', 'o', 'p', 'S', 'e', 'c', 't', 'o', 'r', 'R', 'o', 'o', 't', 's'}
   347  	RPCLoopSettings      = types.Specifier{'L', 'o', 'o', 'p', 'S', 'e', 't', 't', 'i', 'n', 'g', 's'}
   348  	RPCLoopUnlock        = types.Specifier{'L', 'o', 'o', 'p', 'U', 'n', 'l', 'o', 'c', 'k'}
   349  	RPCLoopWrite         = types.Specifier{'L', 'o', 'o', 'p', 'W', 'r', 'i', 't', 'e'}
   350  )
   351  
   352  // RPC ciphers
   353  var (
   354  	CipherChaCha20Poly1305 = types.Specifier{'C', 'h', 'a', 'C', 'h', 'a', '2', '0', 'P', 'o', 'l', 'y', '1', '3', '0', '5'}
   355  	CipherNoOverlap        = types.Specifier{'N', 'o', 'O', 'v', 'e', 'r', 'l', 'a', 'p'}
   356  )
   357  
   358  // Write actions
   359  var (
   360  	WriteActionAppend = types.Specifier{'A', 'p', 'p', 'e', 'n', 'd'}
   361  	WriteActionTrim   = types.Specifier{'T', 'r', 'i', 'm'}
   362  	WriteActionSwap   = types.Specifier{'S', 'w', 'a', 'p'}
   363  	WriteActionUpdate = types.Specifier{'U', 'p', 'd', 'a', 't', 'e'}
   364  )
   365  
   366  // Read interrupt
   367  var (
   368  	RPCLoopReadStop = types.Specifier{'R', 'e', 'a', 'd', 'S', 't', 'o', 'p'}
   369  )
   370  
   371  var (
   372  	// RPCChallengePrefix is the prefix prepended to the challenge data
   373  	// supplied by the host when proving ownership of a contract's secret key.
   374  	RPCChallengePrefix = types.Specifier{'c', 'h', 'a', 'l', 'l', 'e', 'n', 'g', 'e'}
   375  )
   376  
   377  // New RPC request and response types
   378  type (
   379  	// An RPCError may be sent instead of a Response to any RPC.
   380  	RPCError struct {
   381  		Type        types.Specifier
   382  		Data        []byte // structure depends on Type
   383  		Description string // human-readable error string
   384  	}
   385  
   386  	// LoopKeyExchangeRequest is the first object sent when initializing the
   387  	// renter-host protocol.
   388  	LoopKeyExchangeRequest struct {
   389  		// The renter's ephemeral X25519 public key.
   390  		PublicKey crypto.X25519PublicKey
   391  
   392  		// Encryption ciphers that the renter supports.
   393  		Ciphers []types.Specifier
   394  	}
   395  
   396  	// LoopKeyExchangeResponse contains the host's response to the
   397  	// KeyExchangeRequest.
   398  	LoopKeyExchangeResponse struct {
   399  		// The host's ephemeral X25519 public key.
   400  		PublicKey crypto.X25519PublicKey
   401  
   402  		// Signature of (Host's Public Key | Renter's Public Key). Note that this
   403  		// also serves to authenticate the host.
   404  		Signature []byte
   405  
   406  		// Cipher selected by the host. Must be one of the ciphers offered in
   407  		// the key exchange request.
   408  		Cipher types.Specifier
   409  	}
   410  
   411  	// LoopChallengeRequest contains a challenge for the renter to prove their
   412  	// identity. It is the host's first encrypted message, and immediately
   413  	// follows KeyExchangeResponse.
   414  	LoopChallengeRequest struct {
   415  		// Entropy signed by the renter to prove that it controls the secret key
   416  		// used to sign contract revisions. The actual data signed should be:
   417  		//
   418  		//    blake2b(RPCChallengePrefix | Challenge)
   419  		Challenge [16]byte
   420  	}
   421  
   422  	// LoopLockRequest contains the request parameters for RPCLoopLock.
   423  	LoopLockRequest struct {
   424  		// The contract to lock; implicitly referenced by subsequent RPCs.
   425  		ContractID types.FileContractID
   426  
   427  		// The host's challenge, signed by the renter's contract key.
   428  		Signature []byte
   429  
   430  		// Lock timeout, in milliseconds.
   431  		Timeout uint64
   432  	}
   433  
   434  	// LoopLockResponse contains the response data for RPCLoopLock.
   435  	LoopLockResponse struct {
   436  		Acquired     bool
   437  		NewChallenge [16]byte
   438  		Revision     types.FileContractRevision
   439  		Signatures   []types.TransactionSignature
   440  	}
   441  
   442  	// LoopReadRequestSection is a section requested in LoopReadRequest.
   443  	LoopReadRequestSection struct {
   444  		MerkleRoot [32]byte
   445  		Offset     uint32
   446  		Length     uint32
   447  	}
   448  
   449  	// LoopReadRequest contains the request parameters for RPCLoopRead.
   450  	LoopReadRequest struct {
   451  		Sections    []LoopReadRequestSection
   452  		MerkleProof bool
   453  
   454  		NewRevisionNumber    uint64
   455  		NewValidProofValues  []types.Currency
   456  		NewMissedProofValues []types.Currency
   457  		Signature            []byte
   458  	}
   459  
   460  	// LoopReadResponse contains the response data for RPCLoopRead.
   461  	LoopReadResponse struct {
   462  		Signature   []byte
   463  		Data        []byte
   464  		MerkleProof []crypto.Hash
   465  	}
   466  
   467  	// LoopSectorRootsRequest contains the request parameters for RPCLoopSectorRoots.
   468  	LoopSectorRootsRequest struct {
   469  		RootOffset uint64
   470  		NumRoots   uint64
   471  
   472  		NewRevisionNumber    uint64
   473  		NewValidProofValues  []types.Currency
   474  		NewMissedProofValues []types.Currency
   475  		Signature            []byte
   476  	}
   477  
   478  	// LoopSectorRootsResponse contains the response data for RPCLoopSectorRoots.
   479  	LoopSectorRootsResponse struct {
   480  		Signature   []byte
   481  		SectorRoots []crypto.Hash
   482  		MerkleProof []crypto.Hash
   483  	}
   484  
   485  	// LoopFormContractRequest contains the request parameters for RPCLoopFormContract.
   486  	LoopFormContractRequest struct {
   487  		Transactions []types.Transaction
   488  		RenterKey    types.SiaPublicKey
   489  	}
   490  
   491  	// LoopContractAdditions contains the parent transaction, inputs, and
   492  	// outputs added by the host when negotiating a file contract.
   493  	LoopContractAdditions struct {
   494  		Parents []types.Transaction
   495  		Inputs  []types.SiacoinInput
   496  		Outputs []types.SiacoinOutput
   497  	}
   498  
   499  	// LoopContractSignatures contains the signatures for a contract
   500  	// transaction and initial revision. These signatures are sent by both the
   501  	// renter and host during contract formation and renewal.
   502  	LoopContractSignatures struct {
   503  		ContractSignatures []types.TransactionSignature
   504  		RevisionSignature  types.TransactionSignature
   505  	}
   506  
   507  	// LoopRenewContractRequest contains the request parameters for RPCLoopRenewContract.
   508  	LoopRenewContractRequest struct {
   509  		Transactions []types.Transaction
   510  		RenterKey    types.SiaPublicKey
   511  	}
   512  
   513  	// LoopSettingsResponse contains the response data for RPCLoopSettingsResponse.
   514  	LoopSettingsResponse struct {
   515  		Settings []byte // actually a JSON-encoded HostExternalSettings
   516  	}
   517  
   518  	// LoopWriteRequest contains the request parameters for RPCLoopWrite.
   519  	LoopWriteRequest struct {
   520  		Actions     []LoopWriteAction
   521  		MerkleProof bool
   522  
   523  		NewRevisionNumber    uint64
   524  		NewValidProofValues  []types.Currency
   525  		NewMissedProofValues []types.Currency
   526  	}
   527  
   528  	// LoopWriteAction is a generic Write action. The meaning of each field
   529  	// depends on the Type of the action.
   530  	LoopWriteAction struct {
   531  		Type types.Specifier
   532  		A, B uint64
   533  		Data []byte
   534  	}
   535  
   536  	// LoopWriteMerkleProof contains the optional Merkle proof for response data
   537  	// for RPCLoopWrite.
   538  	LoopWriteMerkleProof struct {
   539  		OldSubtreeHashes []crypto.Hash
   540  		OldLeafHashes    []crypto.Hash
   541  		NewMerkleRoot    crypto.Hash
   542  	}
   543  
   544  	// LoopWriteResponse contains the response data for RPCLoopWrite.
   545  	LoopWriteResponse struct {
   546  		Signature []byte
   547  	}
   548  )
   549  
   550  // Error implements the error interface.
   551  func (e *RPCError) Error() string {
   552  	return e.Description
   553  }
   554  
   555  // RPCMinLen is the minimum size of an RPC message. If an encoded message
   556  // would be smaller than RPCMinLen, it is padded with random data.
   557  const RPCMinLen = 4096
   558  
   559  // WriteRPCMessage writes an encrypted RPC message.
   560  func WriteRPCMessage(w io.Writer, aead cipher.AEAD, obj interface{}) error {
   561  	payload := encoding.Marshal(obj)
   562  	// pad the payload to RPCMinLen bytes to prevent eavesdroppers from
   563  	// identifying RPCs by their size.
   564  	minLen := RPCMinLen - aead.Overhead() - aead.NonceSize()
   565  	if len(payload) < minLen {
   566  		payload = append(payload, fastrand.Bytes(minLen-len(payload))...)
   567  	}
   568  	return encoding.WritePrefixedBytes(w, crypto.EncryptWithNonce(payload, aead))
   569  }
   570  
   571  // ReadRPCMessage reads an encrypted RPC message.
   572  func ReadRPCMessage(r io.Reader, aead cipher.AEAD, obj interface{}, maxLen uint64) error {
   573  	ciphertext, err := encoding.ReadPrefixedBytes(r, maxLen)
   574  	if err != nil {
   575  		return err
   576  	}
   577  	plaintext, err := crypto.DecryptWithNonce(ciphertext, aead)
   578  	if err != nil {
   579  		return err
   580  	}
   581  	return encoding.Unmarshal(plaintext, obj)
   582  }
   583  
   584  // WriteRPCRequest writes an encrypted RPC request using the new loop
   585  // protocol.
   586  func WriteRPCRequest(w io.Writer, aead cipher.AEAD, rpcID types.Specifier, req interface{}) error {
   587  	if err := WriteRPCMessage(w, aead, rpcID); err != nil {
   588  		return err
   589  	}
   590  	if req != nil {
   591  		return WriteRPCMessage(w, aead, req)
   592  	}
   593  	return nil
   594  }
   595  
   596  // rpcResponse is a helper type for encoding and decoding RPC response messages.
   597  type rpcResponse struct {
   598  	err  *RPCError
   599  	data interface{}
   600  }
   601  
   602  func (resp *rpcResponse) MarshalSia(w io.Writer) error {
   603  	if resp.data == nil {
   604  		resp.data = struct{}{}
   605  	}
   606  	return encoding.NewEncoder(w).EncodeAll(resp.err, resp.data)
   607  }
   608  
   609  func (resp *rpcResponse) UnmarshalSia(r io.Reader) error {
   610  	// NOTE: no allocation limit is required because this method is always
   611  	// called via encoding.Unmarshal, which already imposes an allocation limit.
   612  	d := encoding.NewDecoder(r, 0)
   613  	if err := d.Decode(&resp.err); err != nil {
   614  		return err
   615  	} else if resp.err != nil {
   616  		return resp.err
   617  	}
   618  	return d.Decode(resp.data)
   619  }
   620  
   621  // WriteRPCResponse writes an RPC response or error using the new loop
   622  // protocol. Either resp or err must be nil. If err is an *RPCError, it is
   623  // sent directly; otherwise, a generic RPCError is created from err's Error
   624  // string.
   625  func WriteRPCResponse(w io.Writer, aead cipher.AEAD, resp interface{}, err error) error {
   626  	re, ok := err.(*RPCError)
   627  	if err != nil && !ok {
   628  		re = &RPCError{Description: err.Error()}
   629  	}
   630  	return WriteRPCMessage(w, aead, &rpcResponse{re, resp})
   631  }
   632  
   633  // ReadRPCID reads an RPC request ID using the new loop protocol.
   634  func ReadRPCID(r io.Reader, aead cipher.AEAD) (rpcID types.Specifier, err error) {
   635  	err = ReadRPCMessage(r, aead, &rpcID, RPCMinLen)
   636  	return
   637  }
   638  
   639  // ReadRPCRequest reads an RPC request using the new loop protocol.
   640  func ReadRPCRequest(r io.Reader, aead cipher.AEAD, req interface{}, maxLen uint64) error {
   641  	return ReadRPCMessage(r, aead, req, maxLen)
   642  }
   643  
   644  // ReadRPCResponse reads an RPC response using the new loop protocol.
   645  func ReadRPCResponse(r io.Reader, aead cipher.AEAD, resp interface{}, maxLen uint64) error {
   646  	if maxLen < RPCMinLen {
   647  		build.Critical("maxLen must be at least RPCMinLen")
   648  		maxLen = RPCMinLen
   649  	}
   650  	return ReadRPCMessage(r, aead, &rpcResponse{nil, resp}, maxLen)
   651  }
   652  
   653  // A RenterHostSession is a session of the new renter-host protocol.
   654  type RenterHostSession struct {
   655  	aead cipher.AEAD
   656  	conn net.Conn
   657  }
   658  
   659  // WriteRequest writes an encrypted RPC request using the new loop
   660  // protocol.
   661  func (s *RenterHostSession) WriteRequest(rpcID types.Specifier, req interface{}) error {
   662  	return WriteRPCRequest(s.conn, s.aead, rpcID, req)
   663  }
   664  
   665  // WriteResponse writes an RPC response or error using the new loop
   666  // protocol. Either resp or err must be nil. If err is an *RPCError, it is
   667  // sent directly; otherwise, a generic RPCError is created from err's Error
   668  // string.
   669  func (s *RenterHostSession) WriteResponse(resp interface{}, err error) error {
   670  	return WriteRPCResponse(s.conn, s.aead, resp, err)
   671  }
   672  
   673  // ReadRPCID reads an RPC request ID using the new loop protocol.
   674  func (s *RenterHostSession) ReadRPCID() (rpcID types.Specifier, err error) {
   675  	return ReadRPCID(s.conn, s.aead)
   676  }
   677  
   678  // ReadRequest reads an RPC request using the new loop protocol.
   679  func (s *RenterHostSession) ReadRequest(req interface{}, maxLen uint64) error {
   680  	return ReadRPCRequest(s.conn, s.aead, req, maxLen)
   681  }
   682  
   683  // ReadResponse reads an RPC response using the new loop protocol.
   684  func (s *RenterHostSession) ReadResponse(resp interface{}, maxLen uint64) error {
   685  	return ReadRPCResponse(s.conn, s.aead, resp, maxLen)
   686  }
   687  
   688  // NewRenterSession returns a new renter-side session of the renter-host
   689  // protocol.
   690  func NewRenterSession(conn net.Conn, hostPublicKey types.SiaPublicKey) (*RenterHostSession, LoopChallengeRequest, error) {
   691  	// generate a session key
   692  	xsk, xpk := crypto.GenerateX25519KeyPair()
   693  
   694  	// send our half of the key exchange
   695  	req := LoopKeyExchangeRequest{
   696  		PublicKey: xpk,
   697  		Ciphers:   []types.Specifier{CipherChaCha20Poly1305},
   698  	}
   699  	if err := encoding.NewEncoder(conn).EncodeAll(RPCLoopEnter, req); err != nil {
   700  		return nil, LoopChallengeRequest{}, err
   701  	}
   702  	// read host's half of the key exchange
   703  	var resp LoopKeyExchangeResponse
   704  	if err := encoding.NewDecoder(conn, encoding.DefaultAllocLimit).Decode(&resp); err != nil {
   705  		return nil, LoopChallengeRequest{}, err
   706  	}
   707  	// validate the signature before doing anything else; don't want to punish
   708  	// the "host" if we're talking to an imposter
   709  	var hpk crypto.PublicKey
   710  	copy(hpk[:], hostPublicKey.Key)
   711  	var sig crypto.Signature
   712  	copy(sig[:], resp.Signature)
   713  	if err := crypto.VerifyHash(crypto.HashAll(req.PublicKey, resp.PublicKey), hpk, sig); err != nil {
   714  		return nil, LoopChallengeRequest{}, err
   715  	}
   716  	// check for compatible cipher
   717  	if resp.Cipher != CipherChaCha20Poly1305 {
   718  		return nil, LoopChallengeRequest{}, errors.New("host selected unsupported cipher")
   719  	}
   720  	// derive shared secret, which we'll use as an encryption key
   721  	cipherKey := crypto.DeriveSharedSecret(xsk, resp.PublicKey)
   722  
   723  	// use cipherKey to initialize an AEAD cipher
   724  	aead, err := chacha20poly1305.New(cipherKey[:])
   725  	if err != nil {
   726  		build.Critical("could not create cipher")
   727  		return nil, LoopChallengeRequest{}, err
   728  	}
   729  
   730  	// read host's challenge
   731  	var challengeReq LoopChallengeRequest
   732  	if err := ReadRPCMessage(conn, aead, &challengeReq, RPCMinLen); err != nil {
   733  		return nil, LoopChallengeRequest{}, err
   734  	}
   735  	return &RenterHostSession{
   736  		aead: aead,
   737  		conn: conn,
   738  	}, challengeReq, nil
   739  }
   740  
   741  // ReadNegotiationAcceptance reads an accept/reject response from r (usually a
   742  // net.Conn). If the response is not AcceptResponse, ReadNegotiationAcceptance
   743  // returns the response as an error. If the response is StopResponse,
   744  // ErrStopResponse is returned, allowing for direct error comparison.
   745  //
   746  // Note that since errors returned by ReadNegotiationAcceptance are newly
   747  // allocated, they cannot be compared to other errors in the traditional
   748  // fashion.
   749  func ReadNegotiationAcceptance(r io.Reader) error {
   750  	var resp string
   751  	err := encoding.ReadObject(r, &resp, NegotiateMaxErrorSize)
   752  	if err != nil {
   753  		return err
   754  	}
   755  	switch resp {
   756  	case AcceptResponse:
   757  		return nil
   758  	case StopResponse:
   759  		return ErrStopResponse
   760  	default:
   761  		return errors.New(resp)
   762  	}
   763  }
   764  
   765  // WriteNegotiationAcceptance writes the 'accept' response to w (usually a
   766  // net.Conn).
   767  func WriteNegotiationAcceptance(w io.Writer) error {
   768  	return encoding.WriteObject(w, AcceptResponse)
   769  }
   770  
   771  // WriteNegotiationRejection will write a rejection response to w (usually a
   772  // net.Conn) and return the input error. If the write fails, the write error
   773  // is joined with the input error.
   774  func WriteNegotiationRejection(w io.Writer, err error) error {
   775  	writeErr := encoding.WriteObject(w, err.Error())
   776  	if writeErr != nil {
   777  		return build.JoinErrors([]error{err, writeErr}, "; ")
   778  	}
   779  	return err
   780  }
   781  
   782  // WriteNegotiationStop writes the 'stop' response to w (usually a
   783  // net.Conn).
   784  func WriteNegotiationStop(w io.Writer) error {
   785  	return encoding.WriteObject(w, StopResponse)
   786  }
   787  
   788  // CreateAnnouncement will take a host announcement and encode it, returning
   789  // the exact []byte that should be added to the arbitrary data of a
   790  // transaction.
   791  func CreateAnnouncement(addr NetAddress, pk types.SiaPublicKey, sk crypto.SecretKey) (signedAnnouncement []byte, err error) {
   792  	if err := addr.IsValid(); err != nil {
   793  		return nil, err
   794  	}
   795  
   796  	// Create the HostAnnouncement and marshal it.
   797  	annBytes := encoding.Marshal(HostAnnouncement{
   798  		Specifier:  PrefixHostAnnouncement,
   799  		NetAddress: addr,
   800  		PublicKey:  pk,
   801  	})
   802  
   803  	// Create a signature for the announcement.
   804  	annHash := crypto.HashBytes(annBytes)
   805  	sig := crypto.SignHash(annHash, sk)
   806  	// Return the signed announcement.
   807  	return append(annBytes, sig[:]...), nil
   808  }
   809  
   810  // DecodeAnnouncement decodes announcement bytes into a host announcement,
   811  // verifying the prefix and the signature.
   812  func DecodeAnnouncement(fullAnnouncement []byte) (na NetAddress, spk types.SiaPublicKey, err error) {
   813  	// Read the first part of the announcement to get the intended host
   814  	// announcement.
   815  	var ha HostAnnouncement
   816  	dec := encoding.NewDecoder(bytes.NewReader(fullAnnouncement), len(fullAnnouncement)*3)
   817  	err = dec.Decode(&ha)
   818  	if err != nil {
   819  		return "", types.SiaPublicKey{}, err
   820  	}
   821  
   822  	// Check that the announcement was registered as a host announcement.
   823  	if ha.Specifier != PrefixHostAnnouncement {
   824  		return "", types.SiaPublicKey{}, ErrAnnNotAnnouncement
   825  	}
   826  	// Check that the public key is a recognized type of public key.
   827  	if ha.PublicKey.Algorithm != types.SignatureEd25519 {
   828  		return "", types.SiaPublicKey{}, ErrAnnUnrecognizedSignature
   829  	}
   830  
   831  	// Read the signature out of the reader.
   832  	var sig crypto.Signature
   833  	err = dec.Decode(&sig)
   834  	if err != nil {
   835  		return "", types.SiaPublicKey{}, err
   836  	}
   837  	// Verify the signature.
   838  	var pk crypto.PublicKey
   839  	copy(pk[:], ha.PublicKey.Key)
   840  	annHash := crypto.HashObject(ha)
   841  	err = crypto.VerifyHash(annHash, pk, sig)
   842  	if err != nil {
   843  		return "", types.SiaPublicKey{}, err
   844  	}
   845  	return ha.NetAddress, ha.PublicKey, nil
   846  }
   847  
   848  // IsOOSErr is a helper function to determine whether an error is a
   849  // ErrInsufficientStorageForSector.
   850  func IsOOSErr(err error) bool {
   851  	return strings.Contains(err.Error(), ErrInsufficientStorageForSector.Error())
   852  }
   853  
   854  // VerifyFileContractRevisionTransactionSignatures checks that the signatures
   855  // on a file contract revision are valid and cover the right fields.
   856  func VerifyFileContractRevisionTransactionSignatures(fcr types.FileContractRevision, tsigs []types.TransactionSignature, height types.BlockHeight) error {
   857  	if len(tsigs) != 2 {
   858  		return ErrRevisionSigCount
   859  	}
   860  	for _, tsig := range tsigs {
   861  		// The transaction needs to be malleable so that miner fees can be
   862  		// added. If the whole transaction is covered, it is doomed to have no
   863  		// fees.
   864  		if tsig.CoveredFields.WholeTransaction {
   865  			return ErrRevisionCoveredFields
   866  		}
   867  	}
   868  	txn := types.Transaction{
   869  		FileContractRevisions: []types.FileContractRevision{fcr},
   870  		TransactionSignatures: tsigs,
   871  	}
   872  	// Check that the signatures verify. This will also check that the covered
   873  	// fields object is not over-aggressive, because if the object is pointing
   874  	// to elements that haven't been added to the transaction, verification
   875  	// will fail.
   876  	return txn.StandaloneValid(height)
   877  }
   878  
   879  // RenterPayoutsPreTax calculates the renterPayout before tax and the hostPayout
   880  // given a host, the available renter funding, the expected txnFee for the
   881  // transaction and an optional basePrice in case this helper is used for a
   882  // renewal. It also returns the hostCollateral.
   883  func RenterPayoutsPreTax(host HostDBEntry, funding, txnFee, basePrice, baseCollateral types.Currency, period types.BlockHeight, expectedStorage uint64) (renterPayout, hostPayout, hostCollateral types.Currency, err error) {
   884  	// Divide by zero check.
   885  	if host.StoragePrice.IsZero() {
   886  		host.StoragePrice = types.NewCurrency64(1)
   887  	}
   888  	// Underflow check.
   889  	if funding.Cmp(host.ContractPrice.Add(txnFee).Add(basePrice)) <= 0 {
   890  		err = fmt.Errorf("contract price (%v) plus transaction fee (%v) plus base price (%v) exceeds funding (%v)",
   891  			host.ContractPrice.HumanString(), txnFee.HumanString(), basePrice.HumanString(), funding.HumanString())
   892  		return
   893  	}
   894  	// Calculate renterPayout.
   895  	renterPayout = funding.Sub(host.ContractPrice).Sub(txnFee).Sub(basePrice)
   896  	// Calculate hostCollateral by calculating the maximum amount of storage
   897  	// the renter can afford with 'funding' and calculating how much collateral
   898  	// the host wouldl have to put into the contract for that. We also add a
   899  	// potential baseCollateral.
   900  	maxStorageSizeTime := renterPayout.Div(host.StoragePrice)
   901  	hostCollateral = maxStorageSizeTime.Mul(host.Collateral).Add(baseCollateral)
   902  	// Don't add more collateral than 10x the collateral for the expected
   903  	// storage to save on fees.
   904  	maxRenterCollateral := host.Collateral.Mul64(uint64(period)).Mul64(expectedStorage).Mul64(5)
   905  	if hostCollateral.Cmp(maxRenterCollateral) > 0 {
   906  		hostCollateral = maxRenterCollateral
   907  	}
   908  	// Don't add more collateral than the host is willing to put into a single
   909  	// contract.
   910  	if hostCollateral.Cmp(host.MaxCollateral) > 0 {
   911  		hostCollateral = host.MaxCollateral
   912  	}
   913  	// Calculate hostPayout.
   914  	hostPayout = hostCollateral.Add(host.ContractPrice).Add(basePrice)
   915  	return
   916  }