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

     1  package proto
     2  
     3  import (
     4  	"encoding/json"
     5  	"os"
     6  	"path/filepath"
     7  	"sync"
     8  
     9  	"SiaPrime/crypto"
    10  	"SiaPrime/encoding"
    11  	"SiaPrime/modules"
    12  	"SiaPrime/types"
    13  	"gitlab.com/NebulousLabs/errors"
    14  	"gitlab.com/NebulousLabs/writeaheadlog"
    15  )
    16  
    17  const (
    18  	// contractHeaderSize is the maximum amount of space that the non-Merkle-root
    19  	// portion of a contract can consume.
    20  	contractHeaderSize = writeaheadlog.MaxPayloadSize // TODO: test this
    21  
    22  	updateNameSetHeader = "setHeader"
    23  	updateNameSetRoot   = "setRoot"
    24  )
    25  
    26  type updateSetHeader struct {
    27  	ID     types.FileContractID
    28  	Header contractHeader
    29  }
    30  
    31  // v132UpdateHeader was introduced due to backwards compatibility reasons after
    32  // changing the format of the contractHeader. It contains the legacy
    33  // v132ContractHeader.
    34  type v132UpdateSetHeader struct {
    35  	ID     types.FileContractID
    36  	Header v132ContractHeader
    37  }
    38  
    39  type updateSetRoot struct {
    40  	ID    types.FileContractID
    41  	Root  crypto.Hash
    42  	Index int
    43  }
    44  
    45  type contractHeader struct {
    46  	// transaction is the signed transaction containing the most recent
    47  	// revision of the file contract.
    48  	Transaction types.Transaction
    49  
    50  	// secretKey is the key used by the renter to sign the file contract
    51  	// transaction.
    52  	SecretKey crypto.SecretKey
    53  
    54  	// Same as modules.RenterContract.
    55  	StartHeight      types.BlockHeight
    56  	DownloadSpending types.Currency
    57  	StorageSpending  types.Currency
    58  	UploadSpending   types.Currency
    59  	TotalCost        types.Currency
    60  	ContractFee      types.Currency
    61  	TxnFee           types.Currency
    62  	SiafundFee       types.Currency
    63  	Utility          modules.ContractUtility
    64  }
    65  
    66  // v132ContractHeader is a contractHeader without the Utility field. This field
    67  // was added after v132 to be able to persist contract utilities.
    68  type v132ContractHeader struct {
    69  	// transaction is the signed transaction containing the most recent
    70  	// revision of the file contract.
    71  	Transaction types.Transaction
    72  
    73  	// secretKey is the key used by the renter to sign the file contract
    74  	// transaction.
    75  	SecretKey crypto.SecretKey
    76  
    77  	// Same as modules.RenterContract.
    78  	StartHeight      types.BlockHeight
    79  	DownloadSpending types.Currency
    80  	StorageSpending  types.Currency
    81  	UploadSpending   types.Currency
    82  	TotalCost        types.Currency
    83  	ContractFee      types.Currency
    84  	TxnFee           types.Currency
    85  	SiafundFee       types.Currency
    86  }
    87  
    88  // validate returns an error if the contractHeader is invalid.
    89  func (h *contractHeader) validate() error {
    90  	if len(h.Transaction.FileContractRevisions) > 0 &&
    91  		len(h.Transaction.FileContractRevisions[0].NewValidProofOutputs) > 0 &&
    92  		len(h.Transaction.FileContractRevisions[0].UnlockConditions.PublicKeys) == 2 {
    93  		return nil
    94  	}
    95  	return errors.New("invalid contract")
    96  }
    97  
    98  func (h *contractHeader) copyTransaction() (txn types.Transaction) {
    99  	encoding.Unmarshal(encoding.Marshal(h.Transaction), &txn)
   100  	return
   101  }
   102  
   103  func (h *contractHeader) LastRevision() types.FileContractRevision {
   104  	return h.Transaction.FileContractRevisions[0]
   105  }
   106  
   107  func (h *contractHeader) ID() types.FileContractID {
   108  	return h.LastRevision().ParentID
   109  }
   110  
   111  func (h *contractHeader) HostPublicKey() types.SiaPublicKey {
   112  	return h.LastRevision().UnlockConditions.PublicKeys[1]
   113  }
   114  
   115  func (h *contractHeader) RenterFunds() types.Currency {
   116  	return h.LastRevision().NewValidProofOutputs[0].Value
   117  }
   118  
   119  func (h *contractHeader) EndHeight() types.BlockHeight {
   120  	return h.LastRevision().NewWindowStart
   121  }
   122  
   123  // A SafeContract contains the most recent revision transaction negotiated
   124  // with a host, and the secret key used to sign it.
   125  type SafeContract struct {
   126  	headerMu sync.Mutex
   127  	header   contractHeader
   128  
   129  	// merkleRoots are the sector roots covered by this contract.
   130  	merkleRoots *merkleRoots
   131  
   132  	// unappliedTxns are the transactions that were written to the WAL but not
   133  	// applied to the contract file.
   134  	unappliedTxns []*writeaheadlog.Transaction
   135  
   136  	headerFile *fileSection
   137  	wal        *writeaheadlog.WAL
   138  	mu         sync.Mutex
   139  }
   140  
   141  // Metadata returns the metadata of a renter contract
   142  func (c *SafeContract) Metadata() modules.RenterContract {
   143  	c.headerMu.Lock()
   144  	defer c.headerMu.Unlock()
   145  	h := c.header
   146  	return modules.RenterContract{
   147  		ID:               h.ID(),
   148  		Transaction:      h.copyTransaction(),
   149  		HostPublicKey:    h.HostPublicKey(),
   150  		StartHeight:      h.StartHeight,
   151  		EndHeight:        h.EndHeight(),
   152  		RenterFunds:      h.RenterFunds(),
   153  		DownloadSpending: h.DownloadSpending,
   154  		StorageSpending:  h.StorageSpending,
   155  		UploadSpending:   h.UploadSpending,
   156  		TotalCost:        h.TotalCost,
   157  		ContractFee:      h.ContractFee,
   158  		TxnFee:           h.TxnFee,
   159  		SiafundFee:       h.SiafundFee,
   160  		Utility:          h.Utility,
   161  	}
   162  }
   163  
   164  // UpdateUtility updates the utility field of a contract.
   165  func (c *SafeContract) UpdateUtility(utility modules.ContractUtility) error {
   166  	// Get current header
   167  	c.headerMu.Lock()
   168  	newHeader := c.header
   169  	c.headerMu.Unlock()
   170  
   171  	// Construct new header
   172  	newHeader.Utility = utility
   173  
   174  	// Record the intent to change the header in the wal.
   175  	t, err := c.wal.NewTransaction([]writeaheadlog.Update{
   176  		c.makeUpdateSetHeader(newHeader),
   177  	})
   178  	if err != nil {
   179  		return err
   180  	}
   181  	// Signal that the setup is completed.
   182  	if err := <-t.SignalSetupComplete(); err != nil {
   183  		return err
   184  	}
   185  	// Apply the change.
   186  	if err := c.applySetHeader(newHeader); err != nil {
   187  		return err
   188  	}
   189  	// Sync the change to disk.
   190  	if err := c.headerFile.Sync(); err != nil {
   191  		return err
   192  	}
   193  	// Signal that the update has been applied.
   194  	if err := t.SignalUpdatesApplied(); err != nil {
   195  		return err
   196  	}
   197  	return nil
   198  }
   199  
   200  // Utility returns the contract utility for the contract.
   201  func (c *SafeContract) Utility() modules.ContractUtility {
   202  	c.headerMu.Lock()
   203  	defer c.headerMu.Unlock()
   204  	return c.header.Utility
   205  }
   206  
   207  func (c *SafeContract) makeUpdateSetHeader(h contractHeader) writeaheadlog.Update {
   208  	c.headerMu.Lock()
   209  	id := c.header.ID()
   210  	c.headerMu.Unlock()
   211  	return writeaheadlog.Update{
   212  		Name: updateNameSetHeader,
   213  		Instructions: encoding.Marshal(updateSetHeader{
   214  			ID:     id,
   215  			Header: h,
   216  		}),
   217  	}
   218  }
   219  
   220  func (c *SafeContract) makeUpdateSetRoot(root crypto.Hash, index int) writeaheadlog.Update {
   221  	c.headerMu.Lock()
   222  	id := c.header.ID()
   223  	c.headerMu.Unlock()
   224  	return writeaheadlog.Update{
   225  		Name: updateNameSetRoot,
   226  		Instructions: encoding.Marshal(updateSetRoot{
   227  			ID:    id,
   228  			Root:  root,
   229  			Index: index,
   230  		}),
   231  	}
   232  }
   233  
   234  func (c *SafeContract) applySetHeader(h contractHeader) error {
   235  	headerBytes := make([]byte, contractHeaderSize)
   236  	copy(headerBytes, encoding.Marshal(h))
   237  	if _, err := c.headerFile.WriteAt(headerBytes, 0); err != nil {
   238  		return err
   239  	}
   240  	c.headerMu.Lock()
   241  	c.header = h
   242  	c.headerMu.Unlock()
   243  	return nil
   244  }
   245  
   246  func (c *SafeContract) applySetRoot(root crypto.Hash, index int) error {
   247  	return c.merkleRoots.insert(index, root)
   248  }
   249  
   250  func (c *SafeContract) recordUploadIntent(rev types.FileContractRevision, root crypto.Hash, storageCost, bandwidthCost types.Currency) (*writeaheadlog.Transaction, error) {
   251  	// construct new header
   252  	// NOTE: this header will not include the host signature
   253  	c.headerMu.Lock()
   254  	newHeader := c.header
   255  	c.headerMu.Unlock()
   256  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   257  	newHeader.StorageSpending = newHeader.StorageSpending.Add(storageCost)
   258  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   259  
   260  	t, err := c.wal.NewTransaction([]writeaheadlog.Update{
   261  		c.makeUpdateSetHeader(newHeader),
   262  		c.makeUpdateSetRoot(root, c.merkleRoots.len()),
   263  	})
   264  	if err != nil {
   265  		return nil, err
   266  	}
   267  	if err := <-t.SignalSetupComplete(); err != nil {
   268  		return nil, err
   269  	}
   270  	c.unappliedTxns = append(c.unappliedTxns, t)
   271  	return t, nil
   272  }
   273  
   274  func (c *SafeContract) commitUpload(t *writeaheadlog.Transaction, signedTxn types.Transaction, root crypto.Hash, storageCost, bandwidthCost types.Currency) error {
   275  	// construct new header
   276  	c.headerMu.Lock()
   277  	newHeader := c.header
   278  	c.headerMu.Unlock()
   279  	newHeader.Transaction = signedTxn
   280  	newHeader.StorageSpending = newHeader.StorageSpending.Add(storageCost)
   281  	newHeader.UploadSpending = newHeader.UploadSpending.Add(bandwidthCost)
   282  
   283  	if err := c.applySetHeader(newHeader); err != nil {
   284  		return err
   285  	}
   286  	if err := c.applySetRoot(root, c.merkleRoots.len()); err != nil {
   287  		return err
   288  	}
   289  	if err := c.headerFile.Sync(); err != nil {
   290  		return err
   291  	}
   292  	if err := t.SignalUpdatesApplied(); err != nil {
   293  		return err
   294  	}
   295  	c.unappliedTxns = nil
   296  	return nil
   297  }
   298  
   299  func (c *SafeContract) recordDownloadIntent(rev types.FileContractRevision, bandwidthCost types.Currency) (*writeaheadlog.Transaction, error) {
   300  	// construct new header
   301  	// NOTE: this header will not include the host signature
   302  	c.headerMu.Lock()
   303  	newHeader := c.header
   304  	c.headerMu.Unlock()
   305  	newHeader.Transaction.FileContractRevisions = []types.FileContractRevision{rev}
   306  	newHeader.DownloadSpending = newHeader.DownloadSpending.Add(bandwidthCost)
   307  
   308  	t, err := c.wal.NewTransaction([]writeaheadlog.Update{
   309  		c.makeUpdateSetHeader(newHeader),
   310  	})
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	if err := <-t.SignalSetupComplete(); err != nil {
   315  		return nil, err
   316  	}
   317  	c.unappliedTxns = append(c.unappliedTxns, t)
   318  	return t, nil
   319  }
   320  
   321  func (c *SafeContract) commitDownload(t *writeaheadlog.Transaction, signedTxn types.Transaction, bandwidthCost types.Currency) error {
   322  	// construct new header
   323  	c.headerMu.Lock()
   324  	newHeader := c.header
   325  	c.headerMu.Unlock()
   326  	newHeader.Transaction = signedTxn
   327  	newHeader.DownloadSpending = newHeader.DownloadSpending.Add(bandwidthCost)
   328  
   329  	if err := c.applySetHeader(newHeader); err != nil {
   330  		return err
   331  	}
   332  	if err := c.headerFile.Sync(); err != nil {
   333  		return err
   334  	}
   335  	if err := t.SignalUpdatesApplied(); err != nil {
   336  		return err
   337  	}
   338  	c.unappliedTxns = nil
   339  	return nil
   340  }
   341  
   342  // commitTxns commits the unapplied transactions to the contract file and marks
   343  // the transactions as applied.
   344  func (c *SafeContract) commitTxns() error {
   345  	for _, t := range c.unappliedTxns {
   346  		for _, update := range t.Updates {
   347  			switch update.Name {
   348  			case updateNameSetHeader:
   349  				var u updateSetHeader
   350  				if err := unmarshalHeader(update.Instructions, &u); err != nil {
   351  					return err
   352  				}
   353  				if err := c.applySetHeader(u.Header); err != nil {
   354  					return err
   355  				}
   356  			case updateNameSetRoot:
   357  				var u updateSetRoot
   358  				if err := encoding.Unmarshal(update.Instructions, &u); err != nil {
   359  					return err
   360  				}
   361  				if err := c.applySetRoot(u.Root, u.Index); err != nil {
   362  					return err
   363  				}
   364  			}
   365  		}
   366  		if err := c.headerFile.Sync(); err != nil {
   367  			return err
   368  		}
   369  		if err := t.SignalUpdatesApplied(); err != nil {
   370  			return err
   371  		}
   372  	}
   373  	c.unappliedTxns = nil
   374  	return nil
   375  }
   376  
   377  // unappliedHeader returns the most recent header contained within the unapplied
   378  // transactions relevant to the contract.
   379  func (c *SafeContract) unappliedHeader() (h contractHeader) {
   380  	for _, t := range c.unappliedTxns {
   381  		for _, update := range t.Updates {
   382  			if update.Name == updateNameSetHeader {
   383  				var u updateSetHeader
   384  				if err := unmarshalHeader(update.Instructions, &u); err != nil {
   385  					continue
   386  				}
   387  				h = u.Header
   388  			}
   389  		}
   390  	}
   391  	return
   392  }
   393  
   394  func (cs *ContractSet) managedInsertContract(h contractHeader, roots []crypto.Hash) (modules.RenterContract, error) {
   395  	if err := h.validate(); err != nil {
   396  		return modules.RenterContract{}, err
   397  	}
   398  	f, err := os.Create(filepath.Join(cs.dir, h.ID().String()+contractExtension))
   399  	if err != nil {
   400  		return modules.RenterContract{}, err
   401  	}
   402  	// create fileSections
   403  	headerSection := newFileSection(f, 0, contractHeaderSize)
   404  	rootsSection := newFileSection(f, contractHeaderSize, -1)
   405  	// write header
   406  	if _, err := headerSection.WriteAt(encoding.Marshal(h), 0); err != nil {
   407  		return modules.RenterContract{}, err
   408  	}
   409  	// write roots
   410  	merkleRoots := newMerkleRoots(rootsSection)
   411  	for _, root := range roots {
   412  		if err := merkleRoots.push(root); err != nil {
   413  			return modules.RenterContract{}, err
   414  		}
   415  	}
   416  	if err := f.Sync(); err != nil {
   417  		return modules.RenterContract{}, err
   418  	}
   419  	sc := &SafeContract{
   420  		header:      h,
   421  		merkleRoots: merkleRoots,
   422  		headerFile:  headerSection,
   423  		wal:         cs.wal,
   424  	}
   425  	cs.mu.Lock()
   426  	cs.contracts[sc.header.ID()] = sc
   427  	cs.pubKeys[string(h.HostPublicKey().Key)] = sc.header.ID()
   428  	cs.mu.Unlock()
   429  	return sc.Metadata(), nil
   430  }
   431  
   432  // loadSafeContract loads a contract from disk and adds it to the contractset
   433  // if it is valid.
   434  func (cs *ContractSet) loadSafeContract(filename string, walTxns []*writeaheadlog.Transaction) error {
   435  	f, err := os.OpenFile(filename, os.O_RDWR, 0600)
   436  	if err != nil {
   437  		return err
   438  	}
   439  	headerSection := newFileSection(f, 0, contractHeaderSize)
   440  	rootsSection := newFileSection(f, contractHeaderSize, remainingFile)
   441  
   442  	// read header
   443  	var header contractHeader
   444  	if err := encoding.NewDecoder(f).Decode(&header); err != nil {
   445  		return err
   446  	} else if err := header.validate(); err != nil {
   447  		return err
   448  	}
   449  
   450  	// read merkleRoots
   451  	merkleRoots, err := loadExistingMerkleRoots(rootsSection)
   452  	if err != nil {
   453  		return err
   454  	}
   455  	// add relevant unapplied transactions
   456  	var unappliedTxns []*writeaheadlog.Transaction
   457  	for _, t := range walTxns {
   458  		// NOTE: we assume here that if any of the updates apply to the
   459  		// contract, the whole transaction applies to the contract.
   460  		if len(t.Updates) == 0 {
   461  			continue
   462  		}
   463  		var id types.FileContractID
   464  		switch update := t.Updates[0]; update.Name {
   465  		case updateNameSetHeader:
   466  			var u updateSetHeader
   467  			if err := unmarshalHeader(update.Instructions, &u); err != nil {
   468  				return err
   469  			}
   470  			id = u.ID
   471  		case updateNameSetRoot:
   472  			var u updateSetRoot
   473  			if err := encoding.Unmarshal(update.Instructions, &u); err != nil {
   474  				return err
   475  			}
   476  			id = u.ID
   477  		}
   478  		if id == header.ID() {
   479  			unappliedTxns = append(unappliedTxns, t)
   480  		}
   481  	}
   482  	// add to set
   483  	sc := &SafeContract{
   484  		header:        header,
   485  		merkleRoots:   merkleRoots,
   486  		unappliedTxns: unappliedTxns,
   487  		headerFile:    headerSection,
   488  		wal:           cs.wal,
   489  	}
   490  	cs.contracts[sc.header.ID()] = sc
   491  	cs.pubKeys[string(header.HostPublicKey().Key)] = sc.header.ID()
   492  	return nil
   493  }
   494  
   495  // ConvertV130Contract creates a contract file for a v130 contract.
   496  func (cs *ContractSet) ConvertV130Contract(c V130Contract, cr V130CachedRevision) error {
   497  	m, err := cs.managedInsertContract(contractHeader{
   498  		Transaction:      c.LastRevisionTxn,
   499  		SecretKey:        c.SecretKey,
   500  		StartHeight:      c.StartHeight,
   501  		DownloadSpending: c.DownloadSpending,
   502  		StorageSpending:  c.StorageSpending,
   503  		UploadSpending:   c.UploadSpending,
   504  		TotalCost:        c.TotalCost,
   505  		ContractFee:      c.ContractFee,
   506  		TxnFee:           c.TxnFee,
   507  		SiafundFee:       c.SiafundFee,
   508  	}, c.MerkleRoots)
   509  	if err != nil {
   510  		return err
   511  	}
   512  	// if there is a cached revision, store it as an unapplied WAL transaction
   513  	if cr.Revision.NewRevisionNumber != 0 {
   514  		sc, ok := cs.Acquire(m.ID)
   515  		if !ok {
   516  			return errors.New("contract set is missing contract that was just added")
   517  		}
   518  		defer cs.Return(sc)
   519  		if len(cr.MerkleRoots) == sc.merkleRoots.len()+1 {
   520  			root := cr.MerkleRoots[len(cr.MerkleRoots)-1]
   521  			_, err = sc.recordUploadIntent(cr.Revision, root, types.ZeroCurrency, types.ZeroCurrency)
   522  		} else {
   523  			_, err = sc.recordDownloadIntent(cr.Revision, types.ZeroCurrency)
   524  		}
   525  		if err != nil {
   526  			return err
   527  		}
   528  	}
   529  	return nil
   530  }
   531  
   532  // A V130Contract specifies the v130 contract format.
   533  type V130Contract struct {
   534  	HostPublicKey    types.SiaPublicKey         `json:"hostpublickey"`
   535  	ID               types.FileContractID       `json:"id"`
   536  	LastRevision     types.FileContractRevision `json:"lastrevision"`
   537  	LastRevisionTxn  types.Transaction          `json:"lastrevisiontxn"`
   538  	MerkleRoots      MerkleRootSet              `json:"merkleroots"`
   539  	SecretKey        crypto.SecretKey           `json:"secretkey"`
   540  	StartHeight      types.BlockHeight          `json:"startheight"`
   541  	DownloadSpending types.Currency             `json:"downloadspending"`
   542  	StorageSpending  types.Currency             `json:"storagespending"`
   543  	UploadSpending   types.Currency             `json:"uploadspending"`
   544  	TotalCost        types.Currency             `json:"totalcost"`
   545  	ContractFee      types.Currency             `json:"contractfee"`
   546  	TxnFee           types.Currency             `json:"txnfee"`
   547  	SiafundFee       types.Currency             `json:"siafundfee"`
   548  }
   549  
   550  // EndHeight returns the height at which the host is no longer obligated to
   551  // store contract data.
   552  func (c *V130Contract) EndHeight() types.BlockHeight {
   553  	return c.LastRevision.NewWindowStart
   554  }
   555  
   556  // RenterFunds returns the funds remaining in the contract's Renter payout as
   557  // of the most recent revision.
   558  func (c *V130Contract) RenterFunds() types.Currency {
   559  	if len(c.LastRevision.NewValidProofOutputs) < 2 {
   560  		return types.ZeroCurrency
   561  	}
   562  	return c.LastRevision.NewValidProofOutputs[0].Value
   563  }
   564  
   565  // A V130CachedRevision contains changes that would be applied to a
   566  // RenterContract if a contract revision succeeded.
   567  type V130CachedRevision struct {
   568  	Revision    types.FileContractRevision `json:"revision"`
   569  	MerkleRoots modules.MerkleRootSet      `json:"merkleroots"`
   570  }
   571  
   572  // MerkleRootSet is a set of Merkle roots, and gets encoded more efficiently.
   573  type MerkleRootSet []crypto.Hash
   574  
   575  // MarshalJSON defines a JSON encoding for a MerkleRootSet.
   576  func (mrs MerkleRootSet) MarshalJSON() ([]byte, error) {
   577  	// Copy the whole array into a giant byte slice and then encode that.
   578  	fullBytes := make([]byte, crypto.HashSize*len(mrs))
   579  	for i := range mrs {
   580  		copy(fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize], mrs[i][:])
   581  	}
   582  	return json.Marshal(fullBytes)
   583  }
   584  
   585  // UnmarshalJSON attempts to decode a MerkleRootSet, falling back on the legacy
   586  // decoding of a []crypto.Hash if that fails.
   587  func (mrs *MerkleRootSet) UnmarshalJSON(b []byte) error {
   588  	// Decode the giant byte slice, and then split it into separate arrays.
   589  	var fullBytes []byte
   590  	err := json.Unmarshal(b, &fullBytes)
   591  	if err != nil {
   592  		// Encoding the byte slice has failed, try decoding it as a []crypto.Hash.
   593  		var hashes []crypto.Hash
   594  		err := json.Unmarshal(b, &hashes)
   595  		if err != nil {
   596  			return err
   597  		}
   598  		*mrs = MerkleRootSet(hashes)
   599  		return nil
   600  	}
   601  
   602  	umrs := make(MerkleRootSet, len(fullBytes)/32)
   603  	for i := range umrs {
   604  		copy(umrs[i][:], fullBytes[i*crypto.HashSize:(i+1)*crypto.HashSize])
   605  	}
   606  	*mrs = umrs
   607  	return nil
   608  }
   609  
   610  func unmarshalHeader(b []byte, u *updateSetHeader) error {
   611  	// Try unmarshaling the header.
   612  	if err := encoding.Unmarshal(b, u); err != nil {
   613  		// COMPATv132 try unmarshaling the header the old way.
   614  		var oldHeader v132UpdateSetHeader
   615  		if err2 := encoding.Unmarshal(b, &oldHeader); err2 != nil {
   616  			// If unmarshaling the header the old way also doesn't work we
   617  			// return the original error.
   618  			return err
   619  		}
   620  		// If unmarshaling it the old way was successful we convert it to a new
   621  		// header.
   622  		u.Header = contractHeader{
   623  			Transaction:      oldHeader.Header.Transaction,
   624  			SecretKey:        oldHeader.Header.SecretKey,
   625  			StartHeight:      oldHeader.Header.StartHeight,
   626  			DownloadSpending: oldHeader.Header.DownloadSpending,
   627  			StorageSpending:  oldHeader.Header.StorageSpending,
   628  			UploadSpending:   oldHeader.Header.UploadSpending,
   629  			TotalCost:        oldHeader.Header.TotalCost,
   630  			ContractFee:      oldHeader.Header.ContractFee,
   631  			TxnFee:           oldHeader.Header.TxnFee,
   632  			SiafundFee:       oldHeader.Header.SiafundFee,
   633  		}
   634  	}
   635  	return nil
   636  }