github.com/johnathanhowell/sia@v0.5.1-beta.0.20160524050156-83dcc3d37c94/modules/host/persist.go (about)

     1  package host
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  	"sync/atomic"
     7  
     8  	"github.com/NebulousLabs/Sia/crypto"
     9  	"github.com/NebulousLabs/Sia/modules"
    10  	"github.com/NebulousLabs/Sia/persist"
    11  	"github.com/NebulousLabs/Sia/types"
    12  
    13  	"github.com/NebulousLabs/bolt"
    14  )
    15  
    16  // persistence is the data that is kept when the host is restarted.
    17  type persistence struct {
    18  	// RPC Metrics.
    19  	DownloadCalls       uint64
    20  	ErroredCalls        uint64
    21  	FormContractCalls   uint64
    22  	RenewCalls          uint64
    23  	ReviseCalls         uint64
    24  	RecentRevisionCalls uint64
    25  	SettingsCalls       uint64
    26  	UnrecognizedCalls   uint64
    27  
    28  	// Consensus Tracking.
    29  	BlockHeight  types.BlockHeight
    30  	RecentChange modules.ConsensusChangeID
    31  
    32  	// Host Identity.
    33  	Announced        bool
    34  	AutoAddress      modules.NetAddress
    35  	FinancialMetrics modules.HostFinancialMetrics
    36  	PublicKey        types.SiaPublicKey
    37  	RevisionNumber   uint64
    38  	SecretKey        crypto.SecretKey
    39  	Settings         modules.HostInternalSettings
    40  	UnlockHash       types.UnlockHash
    41  }
    42  
    43  // persistData returns the data in the Host that will be saved to disk.
    44  func (h *Host) persistData() persistence {
    45  	return persistence{
    46  		// RPC Metrics.
    47  		DownloadCalls:       atomic.LoadUint64(&h.atomicDownloadCalls),
    48  		ErroredCalls:        atomic.LoadUint64(&h.atomicErroredCalls),
    49  		FormContractCalls:   atomic.LoadUint64(&h.atomicFormContractCalls),
    50  		RenewCalls:          atomic.LoadUint64(&h.atomicRenewCalls),
    51  		ReviseCalls:         atomic.LoadUint64(&h.atomicReviseCalls),
    52  		RecentRevisionCalls: atomic.LoadUint64(&h.atomicRecentRevisionCalls),
    53  		SettingsCalls:       atomic.LoadUint64(&h.atomicSettingsCalls),
    54  		UnrecognizedCalls:   atomic.LoadUint64(&h.atomicUnrecognizedCalls),
    55  
    56  		// Consensus Tracking.
    57  		BlockHeight:  h.blockHeight,
    58  		RecentChange: h.recentChange,
    59  
    60  		// Host Identity.
    61  		Announced:        h.announced,
    62  		AutoAddress:      h.autoAddress,
    63  		FinancialMetrics: h.financialMetrics,
    64  		PublicKey:        h.publicKey,
    65  		RevisionNumber:   h.revisionNumber,
    66  		SecretKey:        h.secretKey,
    67  		Settings:         h.settings,
    68  		UnlockHash:       h.unlockHash,
    69  	}
    70  }
    71  
    72  // establishDefaults configures the default settings for the host, overwriting
    73  // any existing settings.
    74  func (h *Host) establishDefaults() error {
    75  	// Configure the settings object.
    76  	h.settings = modules.HostInternalSettings{
    77  		MaxDownloadBatchSize: uint64(defaultMaxDownloadBatchSize),
    78  		MaxDuration:          defaultMaxDuration,
    79  		MaxReviseBatchSize:   uint64(defaultMaxReviseBatchSize),
    80  		WindowSize:           defaultWindowSize,
    81  
    82  		Collateral:       defaultCollateral,
    83  		CollateralBudget: defaultCollateralBudget,
    84  		MaxCollateral:    defaultMaxCollateral,
    85  
    86  		MinimumStoragePrice:           defaultStoragePrice,
    87  		MinimumContractPrice:          defaultContractPrice,
    88  		MinimumDownloadBandwidthPrice: defaultDownloadBandwidthPrice,
    89  		MinimumUploadBandwidthPrice:   defaultUploadBandwidthPrice,
    90  	}
    91  
    92  	// Generate signing key, for revising contracts.
    93  	sk, pk, err := crypto.GenerateKeyPair()
    94  	if err != nil {
    95  		return err
    96  	}
    97  	h.secretKey = sk
    98  	h.publicKey = types.SiaPublicKey{
    99  		Algorithm: types.SignatureEd25519,
   100  		Key:       pk[:],
   101  	}
   102  
   103  	// Subscribe to the consensus set.
   104  	err = h.initConsensusSubscription()
   105  	if err != nil {
   106  		return err
   107  	}
   108  	return h.save()
   109  }
   110  
   111  // initDB will check that the database has been initialized and if not, will
   112  // initialize the database.
   113  func (h *Host) initDB() error {
   114  	return h.db.Update(func(tx *bolt.Tx) error {
   115  		// The storage obligation bucket does not exist, which means the
   116  		// database needs to be initialized. Create the database buckets.
   117  		buckets := [][]byte{
   118  			bucketActionItems,
   119  			bucketStorageObligations,
   120  		}
   121  		for _, bucket := range buckets {
   122  			_, err := tx.CreateBucketIfNotExists(bucket)
   123  			if err != nil {
   124  				return err
   125  			}
   126  		}
   127  		return nil
   128  	})
   129  }
   130  
   131  // load loads the Hosts's persistent data from disk.
   132  func (h *Host) load() error {
   133  	p := new(persistence)
   134  	err := h.dependencies.loadFile(persistMetadata, p, filepath.Join(h.persistDir, settingsFile))
   135  	if os.IsNotExist(err) {
   136  		// There is no host.json file, set up sane defaults.
   137  		return h.establishDefaults()
   138  	} else if err != nil {
   139  		return err
   140  	}
   141  
   142  	// Copy over rpc tracking.
   143  	atomic.StoreUint64(&h.atomicDownloadCalls, p.DownloadCalls)
   144  	atomic.StoreUint64(&h.atomicErroredCalls, p.ErroredCalls)
   145  	atomic.StoreUint64(&h.atomicFormContractCalls, p.FormContractCalls)
   146  	atomic.StoreUint64(&h.atomicRenewCalls, p.RenewCalls)
   147  	atomic.StoreUint64(&h.atomicReviseCalls, p.ReviseCalls)
   148  	atomic.StoreUint64(&h.atomicRecentRevisionCalls, p.RecentRevisionCalls)
   149  	atomic.StoreUint64(&h.atomicSettingsCalls, p.SettingsCalls)
   150  	atomic.StoreUint64(&h.atomicUnrecognizedCalls, p.UnrecognizedCalls)
   151  
   152  	// Copy over consensus tracking.
   153  	h.blockHeight = p.BlockHeight
   154  	h.recentChange = p.RecentChange
   155  
   156  	// Copy over host identity.
   157  	h.announced = p.Announced
   158  	h.autoAddress = p.AutoAddress
   159  	if err := p.AutoAddress.IsValid(); err != nil {
   160  		h.log.Printf("WARN: AutoAddress '%v' loaded from persist is invalid: %v", p.AutoAddress, err)
   161  		h.autoAddress = ""
   162  	}
   163  	h.financialMetrics = p.FinancialMetrics
   164  	h.publicKey = p.PublicKey
   165  	h.revisionNumber = p.RevisionNumber
   166  	h.secretKey = p.SecretKey
   167  	h.settings = p.Settings
   168  	if err := p.Settings.NetAddress.IsValid(); err != nil {
   169  		h.log.Printf("WARN: NetAddress '%v' loaded from persist is invalid: %v", p.Settings.NetAddress, err)
   170  		h.settings.NetAddress = ""
   171  	}
   172  	h.unlockHash = p.UnlockHash
   173  
   174  	err = h.initConsensusSubscription()
   175  	if err != nil {
   176  		return err
   177  	}
   178  	return nil
   179  }
   180  
   181  // save stores all of the persist data to disk.
   182  func (h *Host) save() error {
   183  	return persist.SaveFile(persistMetadata, h.persistData(), filepath.Join(h.persistDir, settingsFile))
   184  }
   185  
   186  // saveSync stores all of the persist data to disk and then syncs to disk.
   187  func (h *Host) saveSync() error {
   188  	return persist.SaveFileSync(persistMetadata, h.persistData(), filepath.Join(h.persistDir, settingsFile))
   189  }