gitlab.com/SkynetLabs/skyd@v1.6.9/skymodules/renter/proto/contract.go (about)

     1  package proto
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"reflect"
    11  	"sync"
    12  
    13  	"gitlab.com/NebulousLabs/errors"
    14  	"gitlab.com/NebulousLabs/writeaheadlog"
    15  
    16  	"gitlab.com/NebulousLabs/encoding"
    17  	"gitlab.com/SkynetLabs/skyd/build"
    18  	"gitlab.com/SkynetLabs/skyd/skymodules"
    19  	"go.sia.tech/siad/crypto"
    20  	"go.sia.tech/siad/modules"
    21  	"go.sia.tech/siad/types"
    22  )
    23  
    24  const (
    25  	updateNameInsertContract = "insertContract"
    26  	updateNameSetHeader      = "setHeader"
    27  	updateNameSetRoot        = "setRoot"
    28  
    29  	// decodeMaxSizeMultiplier is multiplied with the size of an encoded object
    30  	// to allocated a bit of extra space for decoding.
    31  	decodeMaxSizeMultiplier = 3
    32  )
    33  
    34  // updateInsertContract is an update that inserts a contract into the
    35  // contractset with the given header and roots.
    36  type updateInsertContract struct {
    37  	Header contractHeader
    38  	Roots  []crypto.Hash
    39  }
    40  
    41  // updateSetHeader is an update that updates the header of the filecontract with
    42  // the given id.
    43  type updateSetHeader struct {
    44  	ID     types.FileContractID
    45  	Header contractHeader
    46  }
    47  
    48  // updateSetRoot is an update which updates the sector root at the given index
    49  // of a filecontract with the specified id.
    50  type updateSetRoot struct {
    51  	ID    types.FileContractID
    52  	Root  crypto.Hash
    53  	Index int
    54  }
    55  
    56  // contractHeader holds all the information about a contract apart from the
    57  // sector roots themselves.
    58  type contractHeader struct {
    59  	// transaction is the signed transaction containing the most recent
    60  	// revision of the file contract.
    61  	Transaction types.Transaction
    62  
    63  	// secretKey is the key used by the renter to sign the file contract
    64  	// transaction.
    65  	SecretKey crypto.SecretKey
    66  
    67  	// Same as skymodules.RenterContract.
    68  	StartHeight         types.BlockHeight
    69  	DownloadSpending    types.Currency
    70  	FundAccountSpending types.Currency
    71  	MaintenanceSpending skymodules.MaintenanceSpending
    72  	StorageSpending     types.Currency
    73  	UploadSpending      types.Currency
    74  	TotalCost           types.Currency
    75  	ContractFee         types.Currency
    76  	TxnFee              types.Currency
    77  	SiafundFee          types.Currency
    78  	Utility             skymodules.ContractUtility
    79  }
    80  
    81  // rootUpdate is a helper type that specifies an update to a root.
    82  type rootUpdate struct {
    83  	// appended means the root didn't exist before and will be appended to the
    84  	// contract. Otherwise the update updates an existing root. This field is
    85  	// useful in combination with trim because a new root that is also trimmed
    86  	// doesn't require an update on disk since the root didn't exist before
    87  	// anyway.
    88  	appended bool
    89  	// trim indicates that the root is supposed to be trimmed.
    90  	trim bool
    91  	// root is the new value of the root. This may be the empty hash if the root
    92  	// is meant to be trimmed.
    93  	root crypto.Hash
    94  }
    95  
    96  // newRootUpdateTrimRoot creates a trim update.
    97  func newRootUpdateTrimRoot() rootUpdate {
    98  	return rootUpdate{trim: true}
    99  }
   100  
   101  // newRootUpdateAppendRoot creates an append update.
   102  func newRootUpdateAppendRoot(root crypto.Hash) rootUpdate {
   103  	return rootUpdate{root: root, appended: true}
   104  }
   105  
   106  // newRootUpdateUpdateRoot creates a regular update.
   107  func newRootUpdateUpdateRoot(root crypto.Hash) rootUpdate {
   108  	return rootUpdate{root: root, appended: false}
   109  }
   110  
   111  // validate returns an error if the contractHeader is invalid.
   112  func (h *contractHeader) validate() error {
   113  	if len(h.Transaction.FileContractRevisions) == 0 {
   114  		return errors.New("no file contract revisions")
   115  	}
   116  	if len(h.Transaction.FileContractRevisions[0].NewValidProofOutputs) == 0 {
   117  		return errors.New("not enough valid proof outputs")
   118  	}
   119  	if len(h.Transaction.FileContractRevisions[0].UnlockConditions.PublicKeys) != 2 {
   120  		return errors.New("wrong number of pubkeys")
   121  	}
   122  	return nil
   123  }
   124  
   125  // copyTransaction creates a deep copy of the txn struct.
   126  func (h *contractHeader) copyTransaction() (txn types.Transaction) {
   127  	encoding.Unmarshal(encoding.Marshal(h.Transaction), &txn)
   128  	return
   129  }
   130  
   131  // LastRevision returns the last revision of the contract.
   132  func (h *contractHeader) LastRevision() types.FileContractRevision {
   133  	return h.Transaction.FileContractRevisions[0]
   134  }
   135  
   136  // ID returns the contract's ID.
   137  func (h *contractHeader) ID() types.FileContractID {
   138  	return h.LastRevision().ID()
   139  }
   140  
   141  // HostPublicKey returns the host's public key from the last contract revision.
   142  func (h *contractHeader) HostPublicKey() types.SiaPublicKey {
   143  	return h.LastRevision().HostPublicKey()
   144  }
   145  
   146  // RenterFunds returns the remaining renter funds as per the last contract
   147  // revision.
   148  func (h *contractHeader) RenterFunds() types.Currency {
   149  	return h.LastRevision().ValidRenterPayout()
   150  }
   151  
   152  // EndHeight returns the block height of the last constract revision.
   153  func (h *contractHeader) EndHeight() types.BlockHeight {
   154  	return h.LastRevision().EndHeight()
   155  }
   156  
   157  // unappliedWalTxn is a wrapper around writeaheadlog.Transaction that guarantees
   158  // we only call `SignalUpdatesApplied` once.
   159  type unappliedWalTxn struct {
   160  	err  error
   161  	once sync.Once
   162  	*writeaheadlog.Transaction
   163  }
   164  
   165  // newUnappliedWalTxn wraps a `writeaheadlog.Transaction` in an unappliedWalTxn.
   166  func newUnappliedWalTxn(t *writeaheadlog.Transaction) *unappliedWalTxn {
   167  	return &unappliedWalTxn{
   168  		Transaction: t,
   169  	}
   170  }
   171  
   172  // SignalUpdatesApplied calls `SignalUpdatesApplied` on the wrapped wal. It will
   173  // do so only once.
   174  func (t *unappliedWalTxn) SignalUpdatesApplied() error {
   175  	t.once.Do(func() {
   176  		t.err = t.Transaction.SignalUpdatesApplied()
   177  	})
   178  	return t.err
   179  }
   180  
   181  // newWalTxn creates a new wal transaction and automatically wraps it in an
   182  // unappliedWalTxn.
   183  func (c *SafeContract) newWalTxn(updates []writeaheadlog.Update) (*unappliedWalTxn, error) {
   184  	wtxn, err := c.staticWal.NewTransaction(updates)
   185  	if err != nil {
   186  		return nil, err
   187  	}
   188  	return newUnappliedWalTxn(wtxn), nil
   189  }
   190  
   191  // A SafeContract contains the most recent revision transaction negotiated
   192  // with a host, and the secret key used to sign it.
   193  type SafeContract struct {
   194  	header contractHeader
   195  
   196  	// merkleRoots are the sector roots covered by this contract.
   197  	merkleRoots *merkleRoots
   198  
   199  	// unappliedTxns are the transactions that were written to the WAL but not
   200  	// applied to the contract file.
   201  	unappliedTxns []*unappliedWalTxn
   202  
   203  	staticDeps       modules.Dependencies
   204  	staticHeaderFile *os.File
   205  	staticWal        *writeaheadlog.WAL
   206  	mu               sync.Mutex
   207  
   208  	staticRC *refCounter
   209  
   210  	// revisionMu serializes revisions to the contract. It is acquired by
   211  	// (ContractSet).Acquire and released by (ContractSet).Return. When holding
   212  	// revisionMu, it is still necessary to lock mu when modifying fields
   213  	// of the SafeContract.
   214  	revisionMu sync.Mutex
   215  }
   216  
   217  // CommitPaymentIntent will commit the intent to pay a host for an rpc by
   218  // committing the signed txn in the contract's header.
   219  func (c *SafeContract) CommitPaymentIntent(t *unappliedWalTxn, signedTxn types.Transaction, amount types.Currency, details skymodules.SpendingDetails) error {
   220  	c.mu.Lock()
   221  	defer c.mu.Unlock()
   222  
   223  	// construct new header
   224  	newHeader := c.header
   225  	newHeader.Transaction = signedTxn
   226  	newHeader.FundAccountSpending = newHeader.FundAccountSpending.Add(details.FundAccountSpending)
   227  	newHeader.MaintenanceSpending = newHeader.MaintenanceSpending.Add(details.MaintenanceSpending)
   228  
   229  	if err := c.applySetHeader(newHeader); err != nil {
   230  		return err
   231  	}
   232  	if err := c.staticHeaderFile.Sync(); err != nil {
   233  		return err
   234  	}
   235  	if err := t.SignalUpdatesApplied(); err != nil {
   236  		return err
   237  	}
   238  	return c.clearUnappliedTxns()
   239  }
   240  
   241  // clearUnappliedTxns marks all unapplied transactions as completed without
   242  // applying them.
   243  func (c *SafeContract) clearUnappliedTxns() error {
   244  	for len(c.unappliedTxns) > 0 {
   245  		// Fetch next txn.
   246  		txn := c.unappliedTxns[0]
   247  
   248  		// Mark it as applied.
   249  		err := txn.SignalUpdatesApplied()
   250  		if err != nil {
   251  			return err
   252  		}
   253  
   254  		// Remove it from the contract. In case we crash, we at least won't
   255  		// start at the beginning again.
   256  		c.unappliedTxns = c.unappliedTxns[1:]
   257  	}
   258  
   259  	// Set the slice to nil to free memory.
   260  	c.unappliedTxns = nil
   261  	return nil
   262  }
   263  
   264  // metadata returns the metadata of a renter contract
   265  func (c *SafeContract) metadata() skymodules.RenterContract {
   266  	h := c.header
   267  	return skymodules.RenterContract{
   268  		ID:                  h.ID(),
   269  		Transaction:         h.copyTransaction(),
   270  		HostPublicKey:       h.HostPublicKey(),
   271  		StartHeight:         h.StartHeight,
   272  		EndHeight:           h.EndHeight(),
   273  		RenterFunds:         h.RenterFunds(),
   274  		DownloadSpending:    h.DownloadSpending,
   275  		FundAccountSpending: h.FundAccountSpending,
   276  		MaintenanceSpending: h.MaintenanceSpending,
   277  		StorageSpending:     h.StorageSpending,
   278  		UploadSpending:      h.UploadSpending,
   279  		TotalCost:           h.TotalCost,
   280  		ContractFee:         h.ContractFee,
   281  		TxnFee:              h.TxnFee,
   282  		SiafundFee:          h.SiafundFee,
   283  		Utility:             h.Utility,
   284  	}
   285  }
   286  
   287  // LastRevision returns the most recent revision
   288  func (c *SafeContract) LastRevision() types.FileContractRevision {
   289  	c.mu.Lock()
   290  	h := c.header
   291  	c.mu.Unlock()
   292  	return h.LastRevision()
   293  }
   294  
   295  // Metadata returns the metadata of a renter contract
   296  func (c *SafeContract) Metadata() skymodules.RenterContract {
   297  	c.mu.Lock()
   298  	defer c.mu.Unlock()
   299  	return c.metadata()
   300  }
   301  
   302  // PublicKey returns the public key capable of verifying the renter's signature
   303  // on a contract.
   304  func (c *SafeContract) PublicKey() crypto.PublicKey {
   305  	c.mu.Lock()
   306  	defer c.mu.Unlock()
   307  	return c.header.SecretKey.PublicKey()
   308  }
   309  
   310  // RecordPaymentIntent will records the changes we are about to make to the
   311  // revision in order to pay a host for an RPC.
   312  func (c *SafeContract) RecordPaymentIntent(rev types.FileContractRevision, amount types.Currency, details skymodules.SpendingDetails) (*unappliedWalTxn, error) {
   313  	c.mu.Lock()
   314  	defer c.mu.Unlock()
   315  
   316  	newHeader := c.header
   317  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   318  	newHeader.Transaction.TransactionSignatures = nil
   319  	newHeader.FundAccountSpending = newHeader.FundAccountSpending.Add(details.FundAccountSpending)
   320  	newHeader.MaintenanceSpending = newHeader.MaintenanceSpending.Add(details.MaintenanceSpending)
   321  
   322  	t, err := c.newWalTxn([]writeaheadlog.Update{
   323  		c.makeUpdateSetHeader(newHeader),
   324  	})
   325  	if err != nil {
   326  		return nil, err
   327  	}
   328  	if err := <-t.SignalSetupComplete(); err != nil {
   329  		return nil, err
   330  	}
   331  	c.unappliedTxns = append(c.unappliedTxns, t)
   332  	return t, nil
   333  }
   334  
   335  // Sign will sign the given hash using the safecontract's secret key
   336  func (c *SafeContract) Sign(hash crypto.Hash) crypto.Signature {
   337  	c.mu.Lock()
   338  	defer c.mu.Unlock()
   339  	return crypto.SignHash(hash, c.header.SecretKey)
   340  }
   341  
   342  // UpdateUtility updates the utility field of a contract.
   343  func (c *SafeContract) UpdateUtility(utility skymodules.ContractUtility) error {
   344  	c.mu.Lock()
   345  	defer c.mu.Unlock()
   346  	return c.updateUtility(utility)
   347  }
   348  
   349  // updateUtility updates the utility field of a contract.
   350  func (c *SafeContract) updateUtility(utility skymodules.ContractUtility) error {
   351  	// If the utility didn't change, this is a no-op.
   352  	if reflect.DeepEqual(c.header.Utility, utility) {
   353  		return nil
   354  	}
   355  
   356  	// Construct new header
   357  	newHeader := c.header
   358  	newHeader.Utility = utility
   359  
   360  	// Record the intent to change the header in the wal.
   361  	t, err := c.newWalTxn([]writeaheadlog.Update{
   362  		c.makeUpdateSetHeader(newHeader),
   363  	})
   364  	if err != nil {
   365  		return err
   366  	}
   367  	// Signal that the setup is completed.
   368  	if err := <-t.SignalSetupComplete(); err != nil {
   369  		return err
   370  	}
   371  	// Apply the change.
   372  	if err := c.applySetHeader(newHeader); err != nil {
   373  		return err
   374  	}
   375  	// Sync the change to disk.
   376  	if err := c.staticHeaderFile.Sync(); err != nil {
   377  		return err
   378  	}
   379  	// Signal that the update has been applied.
   380  	if err := t.SignalUpdatesApplied(); err != nil {
   381  		return err
   382  	}
   383  	return nil
   384  }
   385  
   386  // Utility returns the contract utility for the contract.
   387  func (c *SafeContract) Utility() skymodules.ContractUtility {
   388  	c.mu.Lock()
   389  	defer c.mu.Unlock()
   390  	return c.header.Utility
   391  }
   392  
   393  // makeUpdateInsertContract creates a writeaheadlog.Update to insert a new
   394  // contract into the contractset.
   395  func makeUpdateInsertContract(h contractHeader, roots []crypto.Hash) (writeaheadlog.Update, error) {
   396  	// Validate header.
   397  	if err := h.validate(); err != nil {
   398  		return writeaheadlog.Update{}, err
   399  	}
   400  	// Create update.
   401  	return writeaheadlog.Update{
   402  		Name: updateNameInsertContract,
   403  		Instructions: encoding.Marshal(updateInsertContract{
   404  			Header: h,
   405  			Roots:  roots,
   406  		}),
   407  	}, nil
   408  }
   409  
   410  // makeUpdateSetHeader creates an update that changes the header.
   411  func (c *SafeContract) makeUpdateSetHeader(h contractHeader) writeaheadlog.Update {
   412  	id := c.header.ID()
   413  	return writeaheadlog.Update{
   414  		Name: updateNameSetHeader,
   415  		Instructions: encoding.Marshal(updateSetHeader{
   416  			ID:     id,
   417  			Header: h,
   418  		}),
   419  	}
   420  }
   421  
   422  // makeUpdateSetRoot creates an update that sets a given root, existing or not.
   423  func (c *SafeContract) makeUpdateSetRoot(root crypto.Hash, index int) writeaheadlog.Update {
   424  	id := c.header.ID()
   425  	return writeaheadlog.Update{
   426  		Name: updateNameSetRoot,
   427  		Instructions: encoding.Marshal(updateSetRoot{
   428  			ID:    id,
   429  			Root:  root,
   430  			Index: index,
   431  		}),
   432  	}
   433  }
   434  
   435  // makeUpdateRefCounterAppend creates a WAL update that sets a given
   436  // refcounter value. If there is no open refcounter update session this method
   437  // will open one. This update session will be closed when we apply the update.
   438  func (c *SafeContract) makeUpdateRefCounterAppend() (writeaheadlog.Update, error) {
   439  	if build.Release != "testing" {
   440  		return writeaheadlog.Update{}, nil // no update needed
   441  	}
   442  	// TODO This hidden retry is a problem that we need to refactor away, most
   443  	// 	probably by refactoring the entire `contract` workflow. The same applies
   444  	// 	to `applyRefCounterUpdate`.
   445  	u, err := c.staticRC.callAppend()
   446  	// If we don't have an update session open one and try again.
   447  	if errors.Contains(err, ErrUpdateWithoutUpdateSession) {
   448  		if err = c.staticRC.callStartUpdate(); err != nil {
   449  			return writeaheadlog.Update{}, err
   450  		}
   451  		u, err = c.staticRC.callAppend()
   452  	}
   453  	return u, err
   454  }
   455  
   456  // applyRefCounterUpdate applies a refcounter WAL update. If there is no open
   457  // update session, it will open one and it will leave it open. This update
   458  // session must be closed by the calling method.
   459  func (c *SafeContract) applyRefCounterUpdate(u writeaheadlog.Update) error {
   460  	if build.Release != "testing" {
   461  		return nil
   462  	}
   463  	err := c.staticRC.callCreateAndApplyTransaction(u)
   464  	// If we don't have an open update session open one and try again.
   465  	if errors.Contains(err, ErrUpdateWithoutUpdateSession) {
   466  		if err = c.staticRC.callStartUpdate(); err != nil {
   467  			return err
   468  		}
   469  		err = c.staticRC.callCreateAndApplyTransaction(u)
   470  	}
   471  	return err
   472  }
   473  
   474  // applySetHeader directly makes changes to the contract header on disk without
   475  // going through a WAL transaction.
   476  func (c *SafeContract) applySetHeader(h contractHeader) error {
   477  	if build.DEBUG {
   478  		// read the existing header on disk, to make sure we aren't overwriting
   479  		// it with an older revision
   480  		var oldHeader contractHeader
   481  		_, err := c.staticHeaderFile.Seek(0, io.SeekStart)
   482  		if err != nil {
   483  			build.Critical(err)
   484  		}
   485  		headerBytes, err := ioutil.ReadAll(c.staticHeaderFile)
   486  		if err == nil {
   487  			if err := encoding.Unmarshal(headerBytes, &oldHeader); err == nil {
   488  				if oldHeader.LastRevision().NewRevisionNumber > h.LastRevision().NewRevisionNumber {
   489  					build.Critical("overwriting a newer revision:", oldHeader.LastRevision().NewRevisionNumber, h.LastRevision().NewRevisionNumber)
   490  				}
   491  			}
   492  		}
   493  	}
   494  	headerBytes := encoding.Marshal(h)
   495  	if _, err := c.staticHeaderFile.WriteAt(headerBytes, 0); err != nil {
   496  		return err
   497  	}
   498  	c.header = h
   499  	return nil
   500  }
   501  
   502  // applySetRoot directly sets a given root hash at a given index on disk without
   503  // going through a WAL transaction.
   504  func (c *SafeContract) applySetRoot(root crypto.Hash, index int) error {
   505  	return c.merkleRoots.insert(index, root)
   506  }
   507  
   508  // managedRecordRootUpdates creates a WAL update that applies a number of
   509  // updates to contract roots.
   510  func (c *SafeContract) managedRecordRootUpdates(rev types.FileContractRevision, rootUpdates map[uint64]rootUpdate, storageCost, bandwidthCost types.Currency) (*unappliedWalTxn, error) {
   511  	c.mu.Lock()
   512  	defer c.mu.Unlock()
   513  	// construct new header
   514  	// NOTE: this header will not include the host signature
   515  	newHeader := c.header
   516  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   517  	newHeader.Transaction.TransactionSignatures = nil
   518  	newHeader.StorageSpending = newHeader.StorageSpending.Add(storageCost)
   519  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   520  
   521  	updates := []writeaheadlog.Update{
   522  		c.makeUpdateSetHeader(newHeader),
   523  	}
   524  	for rootIdx, update := range rootUpdates {
   525  		if !update.trim {
   526  			updates = append(updates, c.makeUpdateSetRoot(update.root, int(rootIdx)))
   527  		} else if update.trim && !update.appended {
   528  			err := errors.New("trimming from a contract is not yet supported")
   529  			build.Critical(err)
   530  			return nil, err
   531  		}
   532  	}
   533  	if build.Release == "testing" {
   534  		rcUpdate, err := c.makeUpdateRefCounterAppend()
   535  		if err != nil {
   536  			return nil, errors.AddContext(err, "failed to create a refcounter update")
   537  		}
   538  		updates = append(updates, rcUpdate)
   539  	}
   540  	t, err := c.newWalTxn(updates)
   541  	if err != nil {
   542  		return nil, err
   543  	}
   544  	if err := <-t.SignalSetupComplete(); err != nil {
   545  		return nil, err
   546  	}
   547  	c.unappliedTxns = append(c.unappliedTxns, t)
   548  	return t, nil
   549  }
   550  
   551  // managedCommitAppend ignores the header update in the given transaction and
   552  // instead applies a new one based on the provided signedTxn. This is necessary
   553  // if we run into a desync of contract revisions between renter and host.
   554  func (c *SafeContract) managedCommitAppend(t *unappliedWalTxn, signedTxn types.Transaction, storageCost, bandwidthCost types.Currency) error {
   555  	c.mu.Lock()
   556  	defer c.mu.Unlock()
   557  	// construct new header
   558  	newHeader := c.header
   559  	newHeader.Transaction = signedTxn
   560  	newHeader.StorageSpending = newHeader.StorageSpending.Add(storageCost)
   561  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   562  
   563  	// we need this declaration so we don't shadow useful variables further down
   564  	var err error
   565  	if err = c.applySetHeader(newHeader); err != nil {
   566  		return err
   567  	}
   568  
   569  	// pluck the refcounter and setRoot updates from the WAL txn
   570  	for _, u := range t.Updates {
   571  		switch u.Name {
   572  		case updateNameSetHeader:
   573  			// do nothing - we already applied a new version of this update
   574  		case updateNameSetRoot:
   575  			var sru updateSetRoot
   576  			if err := encoding.Unmarshal(u.Instructions, &sru); err != nil {
   577  				return err
   578  			}
   579  			if err := c.applySetRoot(sru.Root, sru.Index); err != nil {
   580  				return err
   581  			}
   582  		case updateNameRCWriteAt:
   583  			if err = c.applyRefCounterUpdate(u); err != nil {
   584  				return errors.AddContext(err, "failed to apply refcounter update")
   585  			}
   586  			if err = c.staticRC.callUpdateApplied(); err != nil {
   587  				return err
   588  			}
   589  		default:
   590  			build.Critical("unexpected update", u.Name)
   591  		}
   592  	}
   593  
   594  	if err = c.staticHeaderFile.Sync(); err != nil {
   595  		return err
   596  	}
   597  	if err = t.SignalUpdatesApplied(); err != nil {
   598  		return err
   599  	}
   600  	if err := c.clearUnappliedTxns(); err != nil {
   601  		return errors.AddContext(err, "failed to clear unapplied txns")
   602  	}
   603  	return nil
   604  }
   605  
   606  // managedRecordDownloadIntent creates a WAL update that updates the header with
   607  // the new download costs.
   608  func (c *SafeContract) managedRecordDownloadIntent(rev types.FileContractRevision, bandwidthCost types.Currency) (*unappliedWalTxn, error) {
   609  	c.mu.Lock()
   610  	defer c.mu.Unlock()
   611  	// construct new header
   612  	// NOTE: this header will not include the host signature
   613  	newHeader := c.header
   614  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   615  	newHeader.Transaction.TransactionSignatures = nil
   616  	newHeader.DownloadSpending = newHeader.DownloadSpending.Add(bandwidthCost)
   617  
   618  	t, err := c.newWalTxn([]writeaheadlog.Update{
   619  		c.makeUpdateSetHeader(newHeader),
   620  	})
   621  	if err != nil {
   622  		return nil, err
   623  	}
   624  	if err := <-t.SignalSetupComplete(); err != nil {
   625  		return nil, err
   626  	}
   627  	c.unappliedTxns = append(c.unappliedTxns, t)
   628  	return t, nil
   629  }
   630  
   631  // managedCommitDownload *ignores* all updates in the given transaction and
   632  // instead applies the provided signedTxn. See managedCommitAppend.
   633  func (c *SafeContract) managedCommitDownload(t *unappliedWalTxn, signedTxn types.Transaction, bandwidthCost types.Currency) error {
   634  	c.mu.Lock()
   635  	defer c.mu.Unlock()
   636  	// construct new header
   637  	newHeader := c.header
   638  	newHeader.Transaction = signedTxn
   639  	newHeader.DownloadSpending = newHeader.DownloadSpending.Add(bandwidthCost)
   640  
   641  	if err := c.applySetHeader(newHeader); err != nil {
   642  		return err
   643  	}
   644  	if err := c.staticHeaderFile.Sync(); err != nil {
   645  		return err
   646  	}
   647  	if err := t.SignalUpdatesApplied(); err != nil {
   648  		return err
   649  	}
   650  	if err := c.clearUnappliedTxns(); err != nil {
   651  		return errors.AddContext(err, "failed to clear unapplied txns")
   652  	}
   653  	return nil
   654  }
   655  
   656  // managedRecordClearContractIntent records the changes we are about to make to
   657  // the revision in the WAL of the contract.
   658  func (c *SafeContract) managedRecordClearContractIntent(rev types.FileContractRevision, bandwidthCost types.Currency) (*unappliedWalTxn, error) {
   659  	c.mu.Lock()
   660  	defer c.mu.Unlock()
   661  	// construct new header
   662  	// NOTE: this header will not include the host signature
   663  	newHeader := c.header
   664  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   665  	newHeader.Transaction.TransactionSignatures = nil
   666  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   667  
   668  	t, err := c.newWalTxn([]writeaheadlog.Update{
   669  		c.makeUpdateSetHeader(newHeader),
   670  	})
   671  	if err != nil {
   672  		return nil, err
   673  	}
   674  	if err := <-t.SignalSetupComplete(); err != nil {
   675  		return nil, err
   676  	}
   677  	c.unappliedTxns = append(c.unappliedTxns, t)
   678  	return t, nil
   679  }
   680  
   681  // managedCommitClearContract commits the changes we made to the revision when
   682  // clearing a contract to the WAL of the contract.
   683  func (c *SafeContract) managedCommitClearContract(t *unappliedWalTxn, signedTxn types.Transaction, bandwidthCost types.Currency) error {
   684  	c.mu.Lock()
   685  	defer c.mu.Unlock()
   686  	// construct new header
   687  	newHeader := c.header
   688  	newHeader.Transaction = signedTxn
   689  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   690  	newHeader.Utility.GoodForRefresh = false
   691  	newHeader.Utility.GoodForRenew = false
   692  	newHeader.Utility.GoodForUpload = false
   693  	newHeader.Utility.Locked = true
   694  
   695  	if err := c.applySetHeader(newHeader); err != nil {
   696  		return err
   697  	}
   698  	if err := c.staticHeaderFile.Sync(); err != nil {
   699  		return err
   700  	}
   701  	if err := t.SignalUpdatesApplied(); err != nil {
   702  		return err
   703  	}
   704  	if err := c.clearUnappliedTxns(); err != nil {
   705  		return errors.AddContext(err, "failed to clear unapplied txns")
   706  	}
   707  	return nil
   708  }
   709  
   710  // managedCommitTxns commits the unapplied transactions to the contract file and marks
   711  // the transactions as applied.
   712  func (c *SafeContract) managedCommitTxns() error {
   713  	c.mu.Lock()
   714  	defer c.mu.Unlock()
   715  	// We need a way of finding out whether we need to close the refcounter's
   716  	// update session here. This will only be necessary if there are refcounter
   717  	// updates in the queue. We don't want to close the session in other cases
   718  	// because that can close someone else's session.
   719  	rcUpdatesApplied := false
   720  	for _, t := range c.unappliedTxns {
   721  		for _, update := range t.Updates {
   722  			switch update.Name {
   723  			case updateNameSetHeader:
   724  				var u updateSetHeader
   725  				if err := unmarshalHeader(update.Instructions, &u); err != nil {
   726  					return err
   727  				}
   728  				if err := c.applySetHeader(u.Header); err != nil {
   729  					return err
   730  				}
   731  			case updateNameSetRoot:
   732  				var u updateSetRoot
   733  				if err := encoding.Unmarshal(update.Instructions, &u); err != nil {
   734  					return err
   735  				}
   736  				if err := c.applySetRoot(u.Root, u.Index); err != nil {
   737  					return err
   738  				}
   739  			case updateNameRCWriteAt:
   740  				if err := c.applyRefCounterUpdate(update); err != nil {
   741  					return err
   742  				}
   743  				rcUpdatesApplied = true
   744  			}
   745  		}
   746  		if err := c.staticHeaderFile.Sync(); err != nil {
   747  			return err
   748  		}
   749  		if err := t.SignalUpdatesApplied(); err != nil {
   750  			return err
   751  		}
   752  	}
   753  	if rcUpdatesApplied {
   754  		if err := c.staticRC.callUpdateApplied(); err != nil {
   755  			return err
   756  		}
   757  	}
   758  	c.unappliedTxns = nil
   759  	return nil
   760  }
   761  
   762  // managedSyncRevision checks whether rev accords with the SafeContract's most
   763  // recent revision; if it does not, managedSyncRevision attempts to synchronize
   764  // with rev by committing any uncommitted WAL transactions. If the revisions
   765  // still do not match, and the host's revision is ahead of the renter's,
   766  // managedSyncRevision uses the host's revision. Alongside a possible error this
   767  // function returns a boolean that indicates whether a resync was attempted.
   768  func (c *SafeContract) managedSyncRevision(rev types.FileContractRevision, sigs []types.TransactionSignature) error {
   769  	c.mu.Lock()
   770  	defer c.mu.Unlock()
   771  
   772  	// Our current revision should always be signed. If it isn't, we have no
   773  	// choice but to accept the host's revision.
   774  	if len(c.header.Transaction.TransactionSignatures) == 0 {
   775  		err := errors.New("renter has unsigned revision, this should never happen")
   776  		build.Critical(err)
   777  		return err
   778  	}
   779  
   780  	ourRev := c.header.LastRevision()
   781  
   782  	// If the revision number and Merkle root match, we don't need to do
   783  	// anything.
   784  	if rev.NewRevisionNumber == ourRev.NewRevisionNumber && rev.NewFileMerkleRoot == ourRev.NewFileMerkleRoot {
   785  		// If any other fields mismatch, it must be our fault, since we signed
   786  		// the revision reported by the host. So, to ensure things are
   787  		// consistent, we blindly overwrite our revision with the host's.
   788  		c.header.Transaction.FileContractRevisions[0] = rev
   789  		c.header.Transaction.TransactionSignatures = sigs
   790  		return nil
   791  	}
   792  
   793  	// The host should never report a lower revision number than ours. If they
   794  	// do, it may mean they are intentionally (and maliciously) trying to
   795  	// "rewind" the contract to an earlier state. Even if the host does not have
   796  	// ill intent, this would mean that they failed to commit one or more
   797  	// revisions to durable storage, which reflects very poorly on them.
   798  	if rev.NewRevisionNumber < ourRev.NewRevisionNumber {
   799  		return &revisionNumberMismatchError{ourRev.NewRevisionNumber, rev.NewRevisionNumber}
   800  	}
   801  
   802  	// At this point, we know that either the host's revision number is above
   803  	// ours, or their Merkle root differs. Search our unapplied WAL transactions
   804  	// for one that might synchronize us with the host.
   805  	for _, t := range c.unappliedTxns {
   806  		for _, update := range t.Updates {
   807  			if update.Name == updateNameSetHeader {
   808  				var u updateSetHeader
   809  				if err := unmarshalHeader(update.Instructions, &u); err != nil {
   810  					return err
   811  				}
   812  				unappliedRev := u.Header.LastRevision()
   813  				if unappliedRev.NewRevisionNumber != rev.NewRevisionNumber || unappliedRev.NewFileMerkleRoot != rev.NewFileMerkleRoot {
   814  					continue
   815  				}
   816  
   817  				// found a matching header, but it still won't have the host's
   818  				// signatures, since those aren't added until the transaction is
   819  				// committed. Add the signatures supplied by the host and commit
   820  				// the header.
   821  				u.Header.Transaction.TransactionSignatures = sigs
   822  				if err := c.applySetHeader(u.Header); err != nil {
   823  					return err
   824  				}
   825  
   826  				// pluck the refcounter and setRoot updates from the WAL txn as
   827  				// well.
   828  				for _, u := range t.Updates {
   829  					switch u.Name {
   830  					case updateNameSetHeader:
   831  						// do nothing - we already applied a new version of this update
   832  					case updateNameSetRoot:
   833  						var sru updateSetRoot
   834  						if err := encoding.Unmarshal(u.Instructions, &sru); err != nil {
   835  							return err
   836  						}
   837  						if err := c.applySetRoot(sru.Root, sru.Index); err != nil {
   838  							return err
   839  						}
   840  					case updateNameRCWriteAt:
   841  						if err := c.applyRefCounterUpdate(u); err != nil {
   842  							return errors.AddContext(err, "failed to apply refcounter update")
   843  						}
   844  						if err := c.staticRC.callUpdateApplied(); err != nil {
   845  							build.Critical(err)
   846  							return err
   847  						}
   848  					default:
   849  						build.Critical("unexpected update", u.Name)
   850  					}
   851  				}
   852  				// Sync header.
   853  				if err := c.staticHeaderFile.Sync(); err != nil {
   854  					// If syncing to disk fails, panic to avoid further
   855  					// corruption.
   856  					panic(err)
   857  				}
   858  				// drop all unapplied transactions
   859  				if err := c.clearUnappliedTxns(); err != nil {
   860  					return errors.AddContext(err, "failed to clear unapplied txns")
   861  				}
   862  				return nil
   863  			}
   864  		}
   865  	}
   866  
   867  	// Drop the WAL transactions, since they can't conceivably help us.
   868  	if err := c.clearUnappliedTxns(); err != nil {
   869  		return errors.AddContext(err, "failed to clear unapplied txns")
   870  	}
   871  
   872  	// Under certain conditions in testing we want to ignore the fact that we
   873  	// can't fix the mismatch and simply accept the host's revision.
   874  	if c.staticDeps.Disrupt("AcceptHostRevision") {
   875  		c.header.Transaction.FileContractRevisions[0] = rev
   876  		c.header.Transaction.TransactionSignatures = sigs
   877  		return nil
   878  	}
   879  
   880  	// The revision mismatch is not fixable since we don't have an open wal txn
   881  	// that can fix it. Mark the contract as bad for it to be swapped out. This
   882  	// should never happen.
   883  	u := c.header.Utility
   884  	u.GoodForUpload = false
   885  	u.GoodForRefresh = false
   886  	u.GoodForRenew = false
   887  	u.BadContract = true
   888  	err := fmt.Errorf("revision mismatch unfixable for contract: %v", c.metadata().ID)
   889  	build.Critical(err)
   890  	return errors.Compose(c.updateUtility(u), err)
   891  }
   892  
   893  // managedInsertContract inserts a contract into the set in an ACID fashion
   894  // using the set's WAL.
   895  func (cs *ContractSet) managedInsertContract(h contractHeader, roots []crypto.Hash) (skymodules.RenterContract, error) {
   896  	insertUpdate, err := makeUpdateInsertContract(h, roots)
   897  	if err != nil {
   898  		return skymodules.RenterContract{}, err
   899  	}
   900  	txn, err := cs.staticWal.NewTransaction([]writeaheadlog.Update{insertUpdate})
   901  	if err != nil {
   902  		return skymodules.RenterContract{}, err
   903  	}
   904  	err = <-txn.SignalSetupComplete()
   905  	if err != nil {
   906  		return skymodules.RenterContract{}, err
   907  	}
   908  	rc, err := cs.managedApplyInsertContractUpdate(insertUpdate)
   909  	if err != nil {
   910  		return skymodules.RenterContract{}, err
   911  	}
   912  	err = txn.SignalUpdatesApplied()
   913  	if err != nil {
   914  		return skymodules.RenterContract{}, err
   915  	}
   916  	return rc, nil
   917  }
   918  
   919  // managedApplyInsertContractUpdate applies the update to insert a contract into
   920  // a set. This will overwrite existing contracts of the same name to make sure
   921  // the update is idempotent.
   922  func (cs *ContractSet) managedApplyInsertContractUpdate(update writeaheadlog.Update) (skymodules.RenterContract, error) {
   923  	// Sanity check update.
   924  	if update.Name != updateNameInsertContract {
   925  		return skymodules.RenterContract{}, fmt.Errorf("can't call managedApplyInsertContractUpdate on update of type '%v'", update.Name)
   926  	}
   927  	// Decode update.
   928  	var insertUpdate updateInsertContract
   929  	if err := encoding.UnmarshalAll(update.Instructions, &insertUpdate); err != nil {
   930  		return skymodules.RenterContract{}, err
   931  	}
   932  	h := insertUpdate.Header
   933  	roots := insertUpdate.Roots
   934  	// Validate header.
   935  	if err := h.validate(); err != nil {
   936  		return skymodules.RenterContract{}, err
   937  	}
   938  	headerFilePath := filepath.Join(cs.staticDir, h.ID().String()+contractHeaderExtension)
   939  	rootsFilePath := filepath.Join(cs.staticDir, h.ID().String()+contractRootsExtension)
   940  	rcFilePath := filepath.Join(cs.staticDir, h.ID().String()+refCounterExtension)
   941  	// create the files.
   942  	headerFile, err := os.OpenFile(headerFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, skymodules.DefaultFilePerm)
   943  	if err != nil {
   944  		return skymodules.RenterContract{}, err
   945  	}
   946  	rootsFile, err := os.OpenFile(rootsFilePath, os.O_RDWR|os.O_CREATE|os.O_TRUNC, skymodules.DefaultFilePerm)
   947  	if err != nil {
   948  		return skymodules.RenterContract{}, err
   949  	}
   950  	// write header
   951  	if _, err := headerFile.Write(encoding.Marshal(h)); err != nil {
   952  		return skymodules.RenterContract{}, err
   953  	}
   954  	// Interrupt if necessary.
   955  	if cs.staticDeps.Disrupt("InterruptContractInsertion") {
   956  		return skymodules.RenterContract{}, errors.New("interrupted")
   957  	}
   958  	// write roots
   959  	merkleRoots := newMerkleRoots(rootsFile)
   960  	for _, root := range roots {
   961  		if err := merkleRoots.push(root); err != nil {
   962  			return skymodules.RenterContract{}, err
   963  		}
   964  	}
   965  	// sync both files
   966  	if err := headerFile.Sync(); err != nil {
   967  		return skymodules.RenterContract{}, err
   968  	}
   969  	if err := rootsFile.Sync(); err != nil {
   970  		return skymodules.RenterContract{}, err
   971  	}
   972  	var rc *refCounter
   973  	if build.Release == "testing" {
   974  		rc, err = newRefCounter(rcFilePath, uint64(len(roots)), cs.staticWal)
   975  		if err != nil {
   976  			return skymodules.RenterContract{}, errors.AddContext(err, "failed to create a refcounter")
   977  		}
   978  	}
   979  	sc := &SafeContract{
   980  		header:           h,
   981  		merkleRoots:      merkleRoots,
   982  		staticDeps:       cs.staticDeps,
   983  		staticHeaderFile: headerFile,
   984  		staticWal:        cs.staticWal,
   985  		staticRC:         rc,
   986  	}
   987  	// Compatv144 fix missing void output.
   988  	cs.mu.Lock()
   989  	if _, exists := cs.contracts[sc.header.ID()]; exists {
   990  		build.Critical("trying to overwrite existing contract")
   991  	}
   992  	cs.contracts[sc.header.ID()] = sc
   993  	cs.pubKeys[h.HostPublicKey().String()] = sc.header.ID()
   994  	cs.mu.Unlock()
   995  	return sc.Metadata(), nil
   996  }
   997  
   998  // loadSafeContractHeader will load a contract from disk, checking for legacy
   999  // encodings if initial attempts fail.
  1000  func loadSafeContractHeader(f io.ReadSeeker, decodeMaxSize int) (contractHeader, error) {
  1001  	var header contractHeader
  1002  	err := encoding.NewDecoder(f, decodeMaxSize).Decode(&header)
  1003  	if err != nil {
  1004  		// Try the v160 header.
  1005  		var v160DecodeErr, v1412DecodeErr error
  1006  		header, v160DecodeErr = contractHeaderDecodeV1420ToV160(f, decodeMaxSize)
  1007  		if v160DecodeErr != nil {
  1008  			// Try the v1412 header.
  1009  			header, v1412DecodeErr = contractHeaderDecodeV1412ToV160(f, decodeMaxSize)
  1010  			if v1412DecodeErr != nil {
  1011  				return contractHeader{}, errors.AddContext(errors.Compose(err, v160DecodeErr, v1412DecodeErr), "unable to decode contract header")
  1012  			}
  1013  		}
  1014  	}
  1015  	if err := header.validate(); err != nil {
  1016  		return contractHeader{}, errors.AddContext(err, "unable to validate contract header")
  1017  	}
  1018  	return header, nil
  1019  }
  1020  
  1021  // loadSafeContract loads a contract from disk and adds it to the contractset
  1022  // if it is valid.
  1023  func (cs *ContractSet) loadSafeContract(headerFileName, rootsFileName, refCountFileName string, walTxns map[types.FileContractID][]*unappliedWalTxn) (err error) {
  1024  	headerFile, err := os.OpenFile(headerFileName, os.O_RDWR, skymodules.DefaultFilePerm)
  1025  	if err != nil {
  1026  		return err
  1027  	}
  1028  	rootsFile, err := os.OpenFile(rootsFileName, os.O_RDWR, skymodules.DefaultFilePerm)
  1029  	if err != nil {
  1030  		return err
  1031  	}
  1032  	defer func() {
  1033  		if err != nil {
  1034  			err = errors.Compose(err, headerFile.Close(), rootsFile.Close())
  1035  		}
  1036  	}()
  1037  	headerStat, err := headerFile.Stat()
  1038  	if err != nil {
  1039  		return err
  1040  	}
  1041  	header, err := loadSafeContractHeader(headerFile, int(headerStat.Size())*decodeMaxSizeMultiplier)
  1042  	if err != nil {
  1043  		return errors.AddContext(err, "unable to load contract header")
  1044  	}
  1045  
  1046  	// read merkleRoots
  1047  	merkleRoots, applyTxns, err := loadExistingMerkleRoots(rootsFile)
  1048  	if err != nil {
  1049  		return errors.AddContext(err, "unable to load the merkle roots of the contract")
  1050  	}
  1051  	var rc *refCounter
  1052  	if build.Release == "testing" {
  1053  		// load the reference counter or create a new one if it doesn't exist
  1054  		rc, err = loadRefCounter(refCountFileName, cs.staticWal)
  1055  		if errors.Contains(err, ErrRefCounterNotExist) {
  1056  			rc, err = newRefCounter(refCountFileName, uint64(merkleRoots.numMerkleRoots), cs.staticWal)
  1057  		}
  1058  		if err != nil {
  1059  			return errors.AddContext(err, "failed to load or create a refcounter")
  1060  		}
  1061  	}
  1062  	// add to set
  1063  	sc := &SafeContract{
  1064  		header:           header,
  1065  		merkleRoots:      merkleRoots,
  1066  		unappliedTxns:    walTxns[header.ID()],
  1067  		staticDeps:       cs.staticDeps,
  1068  		staticHeaderFile: headerFile,
  1069  		staticWal:        cs.staticWal,
  1070  		staticRC:         rc,
  1071  	}
  1072  
  1073  	// apply the wal txns if necessary.
  1074  	if applyTxns {
  1075  		if err := sc.managedCommitTxns(); err != nil {
  1076  			return errors.AddContext(err, "unable to commit the wal transactions during contractset recovery")
  1077  		}
  1078  	}
  1079  	if _, exists := cs.contracts[sc.header.ID()]; exists {
  1080  		build.Critical("trying to overwrite existing contract")
  1081  	}
  1082  	cs.contracts[sc.header.ID()] = sc
  1083  	cs.pubKeys[header.HostPublicKey().String()] = sc.header.ID()
  1084  	return nil
  1085  }
  1086  
  1087  // ConvertV130Contract creates a contract file for a v130 contract.
  1088  func (cs *ContractSet) ConvertV130Contract(c V130Contract, cr V130CachedRevision) error {
  1089  	m, err := cs.managedInsertContract(contractHeader{
  1090  		Transaction:      c.LastRevisionTxn,
  1091  		SecretKey:        c.SecretKey,
  1092  		StartHeight:      c.StartHeight,
  1093  		DownloadSpending: c.DownloadSpending,
  1094  		StorageSpending:  c.StorageSpending,
  1095  		UploadSpending:   c.UploadSpending,
  1096  		TotalCost:        c.TotalCost,
  1097  		ContractFee:      c.ContractFee,
  1098  		TxnFee:           c.TxnFee,
  1099  		SiafundFee:       c.SiafundFee,
  1100  	}, c.MerkleRoots)
  1101  	if err != nil {
  1102  		return err
  1103  	}
  1104  	// if there is a cached revision, store it as an unapplied WAL transaction
  1105  	if cr.Revision.NewRevisionNumber != 0 {
  1106  		sc, ok := cs.Acquire(m.ID)
  1107  		if !ok {
  1108  			return errors.New("contract set is missing contract that was just added")
  1109  		}
  1110  		defer cs.Return(sc)
  1111  		if len(cr.MerkleRoots) == sc.merkleRoots.len()+1 {
  1112  			root := cr.MerkleRoots[len(cr.MerkleRoots)-1]
  1113  			_, err = sc.managedRecordRootUpdates(cr.Revision, map[uint64]rootUpdate{
  1114  				uint64(len(cr.MerkleRoots)): newRootUpdateAppendRoot(root),
  1115  			}, types.ZeroCurrency, types.ZeroCurrency)
  1116  		} else {
  1117  			_, err = sc.managedRecordDownloadIntent(cr.Revision, types.ZeroCurrency)
  1118  		}
  1119  		if err != nil {
  1120  			return err
  1121  		}
  1122  	}
  1123  	return nil
  1124  }
  1125  
  1126  // A V130Contract specifies the v130 contract format.
  1127  type V130Contract struct {
  1128  	HostPublicKey    types.SiaPublicKey         `json:"hostpublickey"`
  1129  	ID               types.FileContractID       `json:"id"`
  1130  	LastRevision     types.FileContractRevision `json:"lastrevision"`
  1131  	LastRevisionTxn  types.Transaction          `json:"lastrevisiontxn"`
  1132  	MerkleRoots      MerkleRootSet              `json:"merkleroots"`
  1133  	SecretKey        crypto.SecretKey           `json:"secretkey"`
  1134  	StartHeight      types.BlockHeight          `json:"startheight"`
  1135  	DownloadSpending types.Currency             `json:"downloadspending"`
  1136  	StorageSpending  types.Currency             `json:"storagespending"`
  1137  	UploadSpending   types.Currency             `json:"uploadspending"`
  1138  	TotalCost        types.Currency             `json:"totalcost"`
  1139  	ContractFee      types.Currency             `json:"contractfee"`
  1140  	TxnFee           types.Currency             `json:"txnfee"`
  1141  	SiafundFee       types.Currency             `json:"siafundfee"`
  1142  }
  1143  
  1144  // EndHeight returns the height at which the host is no longer obligated to
  1145  // store contract data.
  1146  func (c *V130Contract) EndHeight() types.BlockHeight {
  1147  	return c.LastRevision.NewWindowStart
  1148  }
  1149  
  1150  // RenterFunds returns the funds remaining in the contract's Renter payout as
  1151  // of the most recent revision.
  1152  func (c *V130Contract) RenterFunds() types.Currency {
  1153  	if len(c.LastRevision.NewValidProofOutputs) < 2 {
  1154  		return types.ZeroCurrency
  1155  	}
  1156  	return c.LastRevision.ValidRenterPayout()
  1157  }
  1158  
  1159  // A V130CachedRevision contains changes that would be applied to a
  1160  // RenterContract if a contract revision succeeded.
  1161  type V130CachedRevision struct {
  1162  	Revision    types.FileContractRevision `json:"revision"`
  1163  	MerkleRoots skymodules.MerkleRootSet   `json:"merkleroots"`
  1164  }
  1165  
  1166  // MerkleRootSet is a set of Merkle roots, and gets encoded more efficiently.
  1167  type MerkleRootSet []crypto.Hash
  1168  
  1169  // MarshalJSON defines a JSON encoding for a MerkleRootSet.
  1170  func (mrs MerkleRootSet) MarshalJSON() ([]byte, error) {
  1171  	// Copy the whole array into a giant byte slice and then encode that.
  1172  	fullBytes := make([]byte, crypto.HashSize*len(mrs))
  1173  	for i := range mrs {
  1174  		copy(fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize], mrs[i][:])
  1175  	}
  1176  	return json.Marshal(fullBytes)
  1177  }
  1178  
  1179  // UnmarshalJSON attempts to decode a MerkleRootSet, falling back on the legacy
  1180  // decoding of a []crypto.Hash if that fails.
  1181  func (mrs *MerkleRootSet) UnmarshalJSON(b []byte) error {
  1182  	// Decode the giant byte slice, and then split it into separate arrays.
  1183  	var fullBytes []byte
  1184  	err := json.Unmarshal(b, &fullBytes)
  1185  	if err != nil {
  1186  		// Encoding the byte slice has failed, try decoding it as a []crypto.Hash.
  1187  		var hashes []crypto.Hash
  1188  		err := json.Unmarshal(b, &hashes)
  1189  		if err != nil {
  1190  			return err
  1191  		}
  1192  		*mrs = MerkleRootSet(hashes)
  1193  		return nil
  1194  	}
  1195  
  1196  	umrs := make(MerkleRootSet, len(fullBytes)/32)
  1197  	for i := range umrs {
  1198  		copy(umrs[i][:], fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize])
  1199  	}
  1200  	*mrs = umrs
  1201  	return nil
  1202  }
  1203  
  1204  // unmarshalHeader loads the header of a file contract. The load processes
  1205  // starts by attempting to load the contract assuming it is the most recent
  1206  // version of the contract. If that fails, it'll try increasingly older versions
  1207  // of the contract until it either succeeds or it runs out of decoding
  1208  // strategies to try.
  1209  func unmarshalHeader(b []byte, u *updateSetHeader) error {
  1210  	// Try unmarshalling the header.
  1211  	if err := encoding.Unmarshal(b, u); err != nil {
  1212  		// Try unmarshalling the update
  1213  		v1420Err := updateSetHeaderUnmarshalV1420ToV160(b, u)
  1214  		if v1420Err != nil {
  1215  			v132Err := updateSetHeaderUnmarshalV132ToV160(b, u)
  1216  			if v132Err != nil {
  1217  				return errors.AddContext(errors.Compose(err, v1420Err, v132Err), "unable to unmarshal update set header")
  1218  			}
  1219  		}
  1220  	}
  1221  	return nil
  1222  }