github.com/MetalBlockchain/subnet-evm@v0.6.3/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/MetalBlockchain/subnet-evm/params" 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/ethdb" 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 78 // Read the upgrade config for this chain config 79 data, _ = db.Get(upgradeConfigKey(hash)) 80 if len(data) == 0 { 81 return &config // return early if no upgrade config is found 82 } 83 if err := json.Unmarshal(data, &config.UpgradeConfig); err != nil { 84 log.Error("Invalid upgrade config JSON", "err", err) 85 return nil 86 } 87 88 return &config 89 } 90 91 // WriteChainConfig writes the chain config settings to the database. 92 func WriteChainConfig(db ethdb.KeyValueWriter, hash common.Hash, cfg *params.ChainConfig) { 93 if cfg == nil { 94 return 95 } 96 data, err := json.Marshal(cfg) 97 if err != nil { 98 log.Crit("Failed to JSON encode chain config", "err", err) 99 } 100 if err := db.Put(configKey(hash), data); err != nil { 101 log.Crit("Failed to store chain config", "err", err) 102 } 103 104 // Write the upgrade config for this chain config 105 data, err = json.Marshal(cfg.UpgradeConfig) 106 if err != nil { 107 log.Crit("Failed to JSON encode upgrade config", "err", err) 108 } 109 if err := db.Put(upgradeConfigKey(hash), data); err != nil { 110 log.Crit("Failed to store upgrade config", "err", err) 111 } 112 } 113 114 // crashList is a list of unclean-shutdown-markers, for rlp-encoding to the 115 // database 116 type crashList struct { 117 Discarded uint64 // how many ucs have we deleted 118 Recent []uint64 // unix timestamps of 10 latest unclean shutdowns 119 } 120 121 const crashesToKeep = 10 122 123 // PushUncleanShutdownMarker appends a new unclean shutdown marker and returns 124 // the previous data 125 // - a list of timestamps 126 // - a count of how many old unclean-shutdowns have been discarded 127 func PushUncleanShutdownMarker(db ethdb.KeyValueStore) ([]uint64, uint64, error) { 128 var uncleanShutdowns crashList 129 // Read old data 130 if data, err := db.Get(uncleanShutdownKey); err != nil { 131 log.Warn("Error reading unclean shutdown markers", "error", err) 132 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 133 return nil, 0, err 134 } 135 var discarded = uncleanShutdowns.Discarded 136 var previous = make([]uint64, len(uncleanShutdowns.Recent)) 137 copy(previous, uncleanShutdowns.Recent) 138 // Add a new (but cap it) 139 uncleanShutdowns.Recent = append(uncleanShutdowns.Recent, uint64(time.Now().Unix())) 140 if count := len(uncleanShutdowns.Recent); count > crashesToKeep+1 { 141 numDel := count - (crashesToKeep + 1) 142 uncleanShutdowns.Recent = uncleanShutdowns.Recent[numDel:] 143 uncleanShutdowns.Discarded += uint64(numDel) 144 } 145 // And save it again 146 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 147 if err := db.Put(uncleanShutdownKey, data); err != nil { 148 log.Warn("Failed to write unclean-shutdown marker", "err", err) 149 return nil, 0, err 150 } 151 return previous, discarded, nil 152 } 153 154 // PopUncleanShutdownMarker removes the last unclean shutdown marker 155 func PopUncleanShutdownMarker(db ethdb.KeyValueStore) { 156 var uncleanShutdowns crashList 157 // Read old data 158 if data, err := db.Get(uncleanShutdownKey); err != nil { 159 log.Warn("Error reading unclean shutdown markers", "error", err) 160 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 161 log.Error("Error decoding unclean shutdown markers", "error", err) // Should mos def _not_ happen 162 } 163 if l := len(uncleanShutdowns.Recent); l > 0 { 164 uncleanShutdowns.Recent = uncleanShutdowns.Recent[:l-1] 165 } 166 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 167 if err := db.Put(uncleanShutdownKey, data); err != nil { 168 log.Warn("Failed to clear unclean-shutdown marker", "err", err) 169 } 170 } 171 172 // UpdateUncleanShutdownMarker updates the last marker's timestamp to now. 173 func UpdateUncleanShutdownMarker(db ethdb.KeyValueStore) { 174 var uncleanShutdowns crashList 175 // Read old data 176 if data, err := db.Get(uncleanShutdownKey); err != nil { 177 log.Warn("Error reading unclean shutdown markers", "error", err) 178 } else if err := rlp.DecodeBytes(data, &uncleanShutdowns); err != nil { 179 log.Warn("Error decoding unclean shutdown markers", "error", err) 180 } 181 // This shouldn't happen because we push a marker on Backend instantiation 182 count := len(uncleanShutdowns.Recent) 183 if count == 0 { 184 log.Warn("No unclean shutdown marker to update") 185 return 186 } 187 uncleanShutdowns.Recent[count-1] = uint64(time.Now().Unix()) 188 data, _ := rlp.EncodeToBytes(uncleanShutdowns) 189 if err := db.Put(uncleanShutdownKey, data); err != nil { 190 log.Warn("Failed to write unclean-shutdown marker", "err", err) 191 } 192 } 193 194 // WriteTimeMarker writes a marker of the current time in the db at [key] 195 func WriteTimeMarker(db ethdb.KeyValueStore, key []byte) error { 196 data, err := rlp.EncodeToBytes(uint64(time.Now().Unix())) 197 if err != nil { 198 return err 199 } 200 return db.Put(key, data) 201 } 202 203 // ReadTimeMarker reads the timestamp stored at [key] 204 func ReadTimeMarker(db ethdb.KeyValueStore, key []byte) (time.Time, error) { 205 data, err := db.Get(key) 206 if err != nil { 207 return time.Time{}, err 208 } 209 210 var lastRun uint64 211 if err := rlp.DecodeBytes(data, &lastRun); err != nil { 212 return time.Time{}, err 213 } 214 215 return time.Unix(int64(lastRun), 0), nil 216 } 217 218 // DeleteTimeMarker deletes any value stored at [key] 219 func DeleteTimeMarker(db ethdb.KeyValueStore, key []byte) error { 220 return db.Delete(key) 221 } 222 223 // WriteOfflinePruning writes a marker of the last attempt to run offline pruning 224 // The marker is written when offline pruning completes and is deleted when the node 225 // is started successfully with offline pruning disabled. This ensures users must 226 // disable offline pruning and start their node successfully between runs of offline 227 // pruning. 228 func WriteOfflinePruning(db ethdb.KeyValueStore) error { 229 return WriteTimeMarker(db, offlinePruningKey) 230 } 231 232 // ReadOfflinePruning reads the most recent timestamp of an attempt to run offline 233 // pruning if present. 234 func ReadOfflinePruning(db ethdb.KeyValueStore) (time.Time, error) { 235 return ReadTimeMarker(db, offlinePruningKey) 236 } 237 238 // DeleteOfflinePruning deletes any marker of the last attempt to run offline pruning. 239 func DeleteOfflinePruning(db ethdb.KeyValueStore) error { 240 return DeleteTimeMarker(db, offlinePruningKey) 241 } 242 243 // WritePopulateMissingTries writes a marker for the current attempt to populate 244 // missing tries. 245 func WritePopulateMissingTries(db ethdb.KeyValueStore) error { 246 return WriteTimeMarker(db, populateMissingTriesKey) 247 } 248 249 // ReadPopulateMissingTries reads the most recent timestamp of an attempt to 250 // re-populate missing trie nodes. 251 func ReadPopulateMissingTries(db ethdb.KeyValueStore) (time.Time, error) { 252 return ReadTimeMarker(db, populateMissingTriesKey) 253 } 254 255 // DeletePopulateMissingTries deletes any marker of the last attempt to 256 // re-populate missing trie nodes. 257 func DeletePopulateMissingTries(db ethdb.KeyValueStore) error { 258 return DeleteTimeMarker(db, populateMissingTriesKey) 259 } 260 261 // WritePruningDisabled writes a marker to track whether the node has ever run 262 // with pruning disabled. 263 func WritePruningDisabled(db ethdb.KeyValueStore) error { 264 return db.Put(pruningDisabledKey, nil) 265 } 266 267 // HasPruningDisabled returns true if there is a marker present indicating that 268 // the node has run with pruning disabled at some pooint. 269 func HasPruningDisabled(db ethdb.KeyValueStore) (bool, error) { 270 return db.Has(pruningDisabledKey) 271 } 272 273 // DeletePruningDisabled deletes the marker indicating that the node has 274 // run with pruning disabled. 275 func DeletePruningDisabled(db ethdb.KeyValueStore) error { 276 return db.Delete(pruningDisabledKey) 277 } 278 279 // WriteAcceptorTip writes [hash] as the last accepted block that has been fully processed. 280 func WriteAcceptorTip(db ethdb.KeyValueWriter, hash common.Hash) error { 281 return db.Put(acceptorTipKey, hash[:]) 282 } 283 284 // ReadAcceptorTip reads the hash of the last accepted block that was fully processed. 285 // If there is no value present (the index is being initialized for the first time), then the 286 // empty hash is returned. 287 func ReadAcceptorTip(db ethdb.KeyValueReader) (common.Hash, error) { 288 has, err := db.Has(acceptorTipKey) 289 // If the index is not present on disk, the [acceptorTipKey] index has not been initialized yet. 290 if !has || err != nil { 291 return common.Hash{}, err 292 } 293 h, err := db.Get(acceptorTipKey) 294 if err != nil { 295 return common.Hash{}, err 296 } 297 return common.BytesToHash(h), nil 298 }