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 }