github.com/dim4egster/coreth@v0.10.2/core/rawdb/accessors_metadata.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2018 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package rawdb 28 29 import ( 30 "encoding/json" 31 "time" 32 33 "github.com/dim4egster/coreth/ethdb" 34 "github.com/dim4egster/coreth/params" 35 "github.com/ethereum/go-ethereum/common" 36 "github.com/ethereum/go-ethereum/log" 37 "github.com/ethereum/go-ethereum/rlp" 38 ) 39 40 // ReadDatabaseVersion retrieves the version number of the database. 41 func ReadDatabaseVersion(db ethdb.KeyValueReader) *uint64 { 42 var version uint64 43 44 enc, _ := db.Get(databaseVersionKey) 45 if len(enc) == 0 { 46 return nil 47 } 48 if err := rlp.DecodeBytes(enc, &version); err != nil { 49 return nil 50 } 51 52 return &version 53 } 54 55 // WriteDatabaseVersion stores the version number of the database 56 func WriteDatabaseVersion(db ethdb.KeyValueWriter, version uint64) { 57 enc, err := rlp.EncodeToBytes(version) 58 if err != nil { 59 log.Crit("Failed to encode database version", "err", err) 60 } 61 if err = db.Put(databaseVersionKey, enc); err != nil { 62 log.Crit("Failed to store the database version", "err", err) 63 } 64 } 65 66 // ReadChainConfig retrieves the consensus settings based on the given genesis hash. 67 func ReadChainConfig(db ethdb.KeyValueReader, hash common.Hash) *params.ChainConfig { 68 data, _ := db.Get(configKey(hash)) 69 if len(data) == 0 { 70 return nil 71 } 72 var config params.ChainConfig 73 if err := json.Unmarshal(data, &config); err != nil { 74 log.Error("Invalid chain config JSON", "hash", hash, "err", err) 75 return nil 76 } 77 return &config 78 } 79 80 // WriteChainConfig writes the chain config settings to the database. 81 func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.ChainConfig) { 82 if cfg == nil { 83 return 84 } 85 data, err := json.Marshal(cfg) 86 if err != nil { 87 log.Crit("Failed to JSON encode chain config", "err", err) 88 } 89 if err := db.Put(configKey(hash), data); err != nil { 90 log.Crit("Failed to store chain config", "err", err) 91 } 92 } 93 94 // crashList is a list of unclean-shutdown-markers, for rlp-encoding to the 95 // database 96 type crashList struct { 97 Discarded uint64 // how many ucs have we deleted 98 Recent []uint64 // unix timestamps of 10 latest unclean shutdowns 99 } 100 101 const crashesToKeep = 10 102 103 // PushUncleanShutdownMarker appends a new unclean shutdown marker and returns 104 // the previous data 105 // - a list of timestamps 106 // - a count of how many old unclean-shutdowns have been discarded 107 func PushUncleanShutdownMarker(db ethdb.KeyValueStore) ([]uint64, uint64, error) { 108 var uncleanShutdowns crashList 109 // Read old data 110 if data, err := db.Get(uncleanShutdownKey); err != nil { 111 log.Warn("Error reading unclean shutdown markers", "error", err) 112 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 113 return nil, 0, err 114 } 115 var discarded = uncleanShutdowns.Discarded 116 var previous = make([]uint64, len(uncleanShutdowns.Recent)) 117 copy(previous, uncleanShutdowns.Recent) 118 // Add a new (but cap it) 119 uncleanShutdowns.Recent = append(uncleanShutdowns.Recent, uint64(time.Now().Unix())) 120 if count := len(uncleanShutdowns.Recent); count > crashesToKeep+1 { 121 numDel := count - (crashesToKeep + 1) 122 uncleanShutdowns.Recent = uncleanShutdowns.Recent[numDel:] 123 uncleanShutdowns.Discarded += uint64(numDel) 124 } 125 // And save it again 126 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 127 if err := db.Put(uncleanShutdownKey, data); err != nil { 128 log.Warn("Failed to write unclean-shutdown marker", "err", err) 129 return nil, 0, err 130 } 131 return previous, discarded, nil 132 } 133 134 // PopUncleanShutdownMarker removes the last unclean shutdown marker 135 func PopUncleanShutdownMarker(db ethdb.KeyValueStore) { 136 var uncleanShutdowns crashList 137 // Read old data 138 if data, err := db.Get(uncleanShutdownKey); err != nil { 139 log.Warn("Error reading unclean shutdown markers", "error", err) 140 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 141 log.Error("Error decoding unclean shutdown markers", "error", err) // Should mos def _not_ happen 142 } 143 if l := len(uncleanShutdowns.Recent); l > 0 { 144 uncleanShutdowns.Recent = uncleanShutdowns.Recent[:l-1] 145 } 146 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 147 if err := db.Put(uncleanShutdownKey, data); err != nil { 148 log.Warn("Failed to clear unclean-shutdown marker", "err", err) 149 } 150 } 151 152 // UpdateUncleanShutdownMarker updates the last marker's timestamp to now. 153 func UpdateUncleanShutdownMarker(db ethdb.KeyValueStore) { 154 var uncleanShutdowns crashList 155 // Read old data 156 if data, err := db.Get(uncleanShutdownKey); err != nil { 157 log.Warn("Error reading unclean shutdown markers", "error", err) 158 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 159 log.Warn("Error decoding unclean shutdown markers", "error", err) 160 } 161 // This shouldn't happen because we push a marker on Backend instantiation 162 count := len(uncleanShutdowns.Recent) 163 if count == 0 { 164 log.Warn("No unclean shutdown marker to update") 165 return 166 } 167 uncleanShutdowns.Recent[count-1] = uint64(time.Now().Unix()) 168 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 169 if err := db.Put(uncleanShutdownKey, data); err != nil { 170 log.Warn("Failed to write unclean-shutdown marker", "err", err) 171 } 172 } 173 174 // WriteTimeMarker writes a marker of the current time in the db at [key] 175 func WriteTimeMarker(db ethdb.KeyValueStore, key []byte) error { 176 data, err := rlp.EncodeToBytes(uint64(time.Now().Unix())) 177 if err != nil { 178 return err 179 } 180 return db.Put(key, data) 181 } 182 183 // ReadTimeMarker reads the timestamp stored at [key] 184 func ReadTimeMarker(db ethdb.KeyValueStore, key []byte) (time.Time, error) { 185 data, err := db.Get(key) 186 if err != nil { 187 return time.Time{}, err 188 } 189 190 var lastRun uint64 191 if err := rlp.DecodeBytes(data, &lastRun); err != nil { 192 return time.Time{}, err 193 } 194 195 return time.Unix(int64(lastRun), 0), nil 196 } 197 198 // DeleteTimeMarker deletes any value stored at [key] 199 func DeleteTimeMarker(db ethdb.KeyValueStore, key []byte) error { 200 return db.Delete(key) 201 } 202 203 // WriteOfflinePruning writes a marker of the last attempt to run offline pruning 204 // The marker is written when offline pruning completes and is deleted when the node 205 // is started successfully with offline pruning disabled. This ensures users must 206 // disable offline pruning and start their node successfully between runs of offline 207 // pruning. 208 func WriteOfflinePruning(db ethdb.KeyValueStore) error { 209 return WriteTimeMarker(db, offlinePruningKey) 210 } 211 212 // ReadOfflinePruning reads the most recent timestamp of an attempt to run offline 213 // pruning if present. 214 func ReadOfflinePruning(db ethdb.KeyValueStore) (time.Time, error) { 215 return ReadTimeMarker(db, offlinePruningKey) 216 } 217 218 // DeleteOfflinePruning deletes any marker of the last attempt to run offline pruning. 219 func DeleteOfflinePruning(db ethdb.KeyValueStore) error { 220 return DeleteTimeMarker(db, offlinePruningKey) 221 } 222 223 // WritePopulateMissingTries writes a marker for the current attempt to populate 224 // missing tries. 225 func WritePopulateMissingTries(db ethdb.KeyValueStore) error { 226 return WriteTimeMarker(db, populateMissingTriesKey) 227 } 228 229 // ReadPopulateMissingTries reads the most recent timestamp of an attempt to 230 // re-populate missing trie nodes. 231 func ReadPopulateMissingTries(db ethdb.KeyValueStore) (time.Time, error) { 232 return ReadTimeMarker(db, populateMissingTriesKey) 233 } 234 235 // DeletePopulateMissingTries deletes any marker of the last attempt to 236 // re-populate missing trie nodes. 237 func DeletePopulateMissingTries(db ethdb.KeyValueStore) error { 238 return DeleteTimeMarker(db, populateMissingTriesKey) 239 } 240 241 // WritePruningDisabled writes a marker to track whether the node has ever run 242 // with pruning disabled. 243 func WritePruningDisabled(db ethdb.KeyValueStore) error { 244 return db.Put(pruningDisabledKey, nil) 245 } 246 247 // HasPruningDisabled returns true if there is a marker present indicating that 248 // the node has run with pruning disabled at some pooint. 249 func HasPruningDisabled(db ethdb.KeyValueStore) (bool, error) { 250 return db.Has(pruningDisabledKey) 251 } 252 253 // DeletePruningDisabled deletes the marker indicating that the node has 254 // run with pruning disabled. 255 func DeletePruningDisabled(db ethdb.KeyValueStore) error { 256 return db.Delete(pruningDisabledKey) 257 } 258 259 // WriteAcceptorTip writes [hash] as the last accepted block that has been fully processed. 260 func WriteAcceptorTip(db ethdb.KeyValueWriter, hash common.Hash) error { 261 return db.Put(acceptorTipKey, hash[:]) 262 } 263 264 // ReadAcceptorTip reads the hash of the last accepted block that was fully processed. 265 // If there is no value present (the index is being initialized for the first time), then the 266 // empty hash is returned. 267 func ReadAcceptorTip(db ethdb.KeyValueReader) (common.Hash, error) { 268 has, err := db.Has(acceptorTipKey) 269 // If the index is not present on disk, the [acceptorTipKey] index has not been initialized yet. 270 if !has || err != nil { 271 return common.Hash{}, err 272 } 273 h, err := db.Get(acceptorTipKey) 274 if err != nil { 275 return common.Hash{}, err 276 } 277 return common.BytesToHash(h), nil 278 }