gitlab.com/SiaPrime/SiaPrime@v1.4.1/modules/renter/contractor/persist.go (about)

     1  package contractor
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"reflect"
     7  
     8  	"gitlab.com/SiaPrime/SiaPrime/modules"
     9  	"gitlab.com/SiaPrime/SiaPrime/modules/renter/proto"
    10  	"gitlab.com/SiaPrime/SiaPrime/persist"
    11  	"gitlab.com/SiaPrime/SiaPrime/types"
    12  
    13  	"gitlab.com/NebulousLabs/errors"
    14  )
    15  
    16  // contractorPersist defines what Contractor data persists across sessions.
    17  type contractorPersist struct {
    18  	Allowance            modules.Allowance               `json:"allowance"`
    19  	BlockHeight          types.BlockHeight               `json:"blockheight"`
    20  	CurrentPeriod        types.BlockHeight               `json:"currentperiod"`
    21  	LastChange           modules.ConsensusChangeID       `json:"lastchange"`
    22  	RecentRecoveryChange modules.ConsensusChangeID       `json:"recentrecoverychange"`
    23  	OldContracts         []modules.RenterContract        `json:"oldcontracts"`
    24  	RecoverableContracts []modules.RecoverableContract   `json:"recoverablecontracts"`
    25  	RenewedFrom          map[string]types.FileContractID `json:"renewedfrom"`
    26  	RenewedTo            map[string]types.FileContractID `json:"renewedto"`
    27  }
    28  
    29  // persistData returns the data in the Contractor that will be saved to disk.
    30  func (c *Contractor) persistData() contractorPersist {
    31  	data := contractorPersist{
    32  		Allowance:            c.allowance,
    33  		BlockHeight:          c.blockHeight,
    34  		CurrentPeriod:        c.currentPeriod,
    35  		LastChange:           c.lastChange,
    36  		RecentRecoveryChange: c.recentRecoveryChange,
    37  		RenewedFrom:          make(map[string]types.FileContractID),
    38  		RenewedTo:            make(map[string]types.FileContractID),
    39  	}
    40  	for k, v := range c.renewedFrom {
    41  		data.RenewedFrom[k.String()] = v
    42  	}
    43  	for k, v := range c.renewedTo {
    44  		data.RenewedTo[k.String()] = v
    45  	}
    46  	for _, contract := range c.oldContracts {
    47  		data.OldContracts = append(data.OldContracts, contract)
    48  	}
    49  	for _, contract := range c.recoverableContracts {
    50  		data.RecoverableContracts = append(data.RecoverableContracts, contract)
    51  	}
    52  	return data
    53  }
    54  
    55  // load loads the Contractor persistence data from disk.
    56  func (c *Contractor) load() error {
    57  	var data contractorPersist
    58  	err := c.persist.load(&data)
    59  	if err != nil {
    60  		return err
    61  	}
    62  
    63  	// COMPATv136 if the allowance is not the empty allowance and "Expected"
    64  	// fields are not set, set them to the default values.
    65  	if !reflect.DeepEqual(data.Allowance, modules.Allowance{}) {
    66  		if data.Allowance.ExpectedStorage == 0 && data.Allowance.ExpectedUpload == 0 &&
    67  			data.Allowance.ExpectedDownload == 0 && data.Allowance.ExpectedRedundancy == 0 {
    68  			// Set the fields to the defaults.
    69  			data.Allowance.ExpectedStorage = modules.DefaultAllowance.ExpectedStorage
    70  			data.Allowance.ExpectedUpload = modules.DefaultAllowance.ExpectedUpload
    71  			data.Allowance.ExpectedDownload = modules.DefaultAllowance.ExpectedDownload
    72  			data.Allowance.ExpectedRedundancy = modules.DefaultAllowance.ExpectedRedundancy
    73  		}
    74  	}
    75  
    76  	c.allowance = data.Allowance
    77  	c.blockHeight = data.BlockHeight
    78  	c.currentPeriod = data.CurrentPeriod
    79  	c.lastChange = data.LastChange
    80  	c.recentRecoveryChange = data.RecentRecoveryChange
    81  	var fcid types.FileContractID
    82  	for k, v := range data.RenewedFrom {
    83  		if err := fcid.LoadString(k); err != nil {
    84  			return err
    85  		}
    86  		c.renewedFrom[fcid] = v
    87  	}
    88  	for k, v := range data.RenewedTo {
    89  		if err := fcid.LoadString(k); err != nil {
    90  			return err
    91  		}
    92  		c.renewedTo[fcid] = v
    93  	}
    94  	for _, contract := range data.OldContracts {
    95  		c.oldContracts[contract.ID] = contract
    96  	}
    97  	for _, contract := range data.RecoverableContracts {
    98  		c.recoverableContracts[contract.ID] = contract
    99  	}
   100  
   101  	return nil
   102  }
   103  
   104  // save saves the Contractor persistence data to disk.
   105  func (c *Contractor) save() error {
   106  	return c.persist.save(c.persistData())
   107  }
   108  
   109  // convertPersist converts the pre-v1.3.1 contractor persist formats to the new
   110  // formats.
   111  func convertPersist(dir string) error {
   112  	// Try loading v1.3.1 persist. If it has the correct version number, no
   113  	// further action is necessary.
   114  	persistPath := filepath.Join(dir, "contractor.json")
   115  	err := persist.LoadJSON(persistMeta, nil, persistPath)
   116  	if err == nil {
   117  		return nil
   118  	}
   119  
   120  	// Try loading v1.3.0 persist (journal).
   121  	journalPath := filepath.Join(dir, "contractor.journal")
   122  	if _, err := os.Stat(journalPath); os.IsNotExist(err) {
   123  		// no journal file found; assume this is a fresh install
   124  		return nil
   125  	}
   126  	var p journalPersist
   127  	j, err := openJournal(journalPath, &p)
   128  	if err != nil {
   129  		return err
   130  	}
   131  	j.Close()
   132  	// convert to v1.3.1 format and save
   133  	data := contractorPersist{
   134  		Allowance:     p.Allowance,
   135  		BlockHeight:   p.BlockHeight,
   136  		CurrentPeriod: p.CurrentPeriod,
   137  		LastChange:    p.LastChange,
   138  	}
   139  	for _, c := range p.OldContracts {
   140  		data.OldContracts = append(data.OldContracts, modules.RenterContract{
   141  			ID:               c.ID,
   142  			HostPublicKey:    c.HostPublicKey,
   143  			StartHeight:      c.StartHeight,
   144  			EndHeight:        c.EndHeight(),
   145  			RenterFunds:      c.RenterFunds(),
   146  			DownloadSpending: c.DownloadSpending,
   147  			StorageSpending:  c.StorageSpending,
   148  			UploadSpending:   c.UploadSpending,
   149  			TotalCost:        c.TotalCost,
   150  			ContractFee:      c.ContractFee,
   151  			TxnFee:           c.TxnFee,
   152  			SiafundFee:       c.SiafundFee,
   153  		})
   154  	}
   155  	err = persist.SaveJSON(persistMeta, data, persistPath)
   156  	if err != nil {
   157  		return err
   158  	}
   159  
   160  	// create the contracts directory if it does not yet exist
   161  	cs, err := proto.NewContractSet(filepath.Join(dir, "contracts"), modules.ProdDependencies)
   162  	if err != nil {
   163  		return err
   164  	}
   165  	defer cs.Close()
   166  
   167  	// convert contracts to contract files
   168  	for _, c := range p.Contracts {
   169  		cachedRev := p.CachedRevisions[c.ID.String()]
   170  		if err := cs.ConvertV130Contract(c, cachedRev); err != nil {
   171  			return err
   172  		}
   173  	}
   174  
   175  	// delete the journal file
   176  	return errors.AddContext(os.Remove(journalPath), "failed to remove journal file")
   177  }