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  }