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  }