github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/triedb/database.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package triedb
    18  
    19  import (
    20  	"errors"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/core/rawdb"
    24  	"github.com/ethereum/go-ethereum/ethdb"
    25  	"github.com/ethereum/go-ethereum/log"
    26  	"github.com/ethereum/go-ethereum/trie"
    27  	"github.com/ethereum/go-ethereum/trie/trienode"
    28  	"github.com/ethereum/go-ethereum/trie/triestate"
    29  	"github.com/ethereum/go-ethereum/triedb/database"
    30  	"github.com/ethereum/go-ethereum/triedb/hashdb"
    31  	"github.com/ethereum/go-ethereum/triedb/pathdb"
    32  )
    33  
    34  // Config defines all necessary options for database.
    35  type Config struct {
    36  	Preimages bool           // Flag whether the preimage of node key is recorded
    37  	IsVerkle  bool           // Flag whether the db is holding a verkle tree
    38  	HashDB    *hashdb.Config // Configs for hash-based scheme
    39  	PathDB    *pathdb.Config // Configs for experimental path-based scheme
    40  }
    41  
    42  // HashDefaults represents a config for using hash-based scheme with
    43  // default settings.
    44  var HashDefaults = &Config{
    45  	Preimages: false,
    46  	HashDB:    hashdb.Defaults,
    47  }
    48  
    49  // backend defines the methods needed to access/update trie nodes in different
    50  // state scheme.
    51  type backend interface {
    52  	// Initialized returns an indicator if the state data is already initialized
    53  	// according to the state scheme.
    54  	Initialized(genesisRoot common.Hash) bool
    55  
    56  	// Size returns the current storage size of the diff layers on top of the
    57  	// disk layer and the storage size of the nodes cached in the disk layer.
    58  	//
    59  	// For hash scheme, there is no differentiation between diff layer nodes
    60  	// and dirty disk layer nodes, so both are merged into the second return.
    61  	Size() (common.StorageSize, common.StorageSize)
    62  
    63  	// Update performs a state transition by committing dirty nodes contained
    64  	// in the given set in order to update state from the specified parent to
    65  	// the specified root.
    66  	//
    67  	// The passed in maps(nodes, states) will be retained to avoid copying
    68  	// everything. Therefore, these maps must not be changed afterwards.
    69  	Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error
    70  
    71  	// Commit writes all relevant trie nodes belonging to the specified state
    72  	// to disk. Report specifies whether logs will be displayed in info level.
    73  	Commit(root common.Hash, report bool) error
    74  
    75  	// Close closes the trie database backend and releases all held resources.
    76  	Close() error
    77  }
    78  
    79  // Database is the wrapper of the underlying backend which is shared by different
    80  // types of node backend as an entrypoint. It's responsible for all interactions
    81  // relevant with trie nodes and node preimages.
    82  type Database struct {
    83  	config    *Config        // Configuration for trie database
    84  	diskdb    ethdb.Database // Persistent database to store the snapshot
    85  	preimages *preimageStore // The store for caching preimages
    86  	backend   backend        // The backend for managing trie nodes
    87  }
    88  
    89  // NewDatabase initializes the trie database with default settings, note
    90  // the legacy hash-based scheme is used by default.
    91  func NewDatabase(diskdb ethdb.Database, config *Config) *Database {
    92  	// Sanitize the config and use the default one if it's not specified.
    93  	if config == nil {
    94  		config = HashDefaults
    95  	}
    96  	var preimages *preimageStore
    97  	if config.Preimages {
    98  		preimages = newPreimageStore(diskdb)
    99  	}
   100  	db := &Database{
   101  		config:    config,
   102  		diskdb:    diskdb,
   103  		preimages: preimages,
   104  	}
   105  	if config.HashDB != nil && config.PathDB != nil {
   106  		log.Crit("Both 'hash' and 'path' mode are configured")
   107  	}
   108  	if config.PathDB != nil {
   109  		db.backend = pathdb.New(diskdb, config.PathDB, config.IsVerkle)
   110  	} else {
   111  		var resolver hashdb.ChildResolver
   112  		if config.IsVerkle {
   113  			// TODO define verkle resolver
   114  			log.Crit("verkle does not use a hash db")
   115  		} else {
   116  			resolver = trie.MerkleResolver{}
   117  		}
   118  		db.backend = hashdb.New(diskdb, config.HashDB, resolver)
   119  	}
   120  	return db
   121  }
   122  
   123  // Reader returns a reader for accessing all trie nodes with provided state root.
   124  // An error will be returned if the requested state is not available.
   125  func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) {
   126  	switch b := db.backend.(type) {
   127  	case *hashdb.Database:
   128  		return b.Reader(blockRoot)
   129  	case *pathdb.Database:
   130  		return b.Reader(blockRoot)
   131  	}
   132  	return nil, errors.New("unknown backend")
   133  }
   134  
   135  // Update performs a state transition by committing dirty nodes contained in the
   136  // given set in order to update state from the specified parent to the specified
   137  // root. The held pre-images accumulated up to this point will be flushed in case
   138  // the size exceeds the threshold.
   139  //
   140  // The passed in maps(nodes, states) will be retained to avoid copying everything.
   141  // Therefore, these maps must not be changed afterwards.
   142  func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
   143  	if db.preimages != nil {
   144  		db.preimages.commit(false)
   145  	}
   146  	return db.backend.Update(root, parent, block, nodes, states)
   147  }
   148  
   149  // Commit iterates over all the children of a particular node, writes them out
   150  // to disk. As a side effect, all pre-images accumulated up to this point are
   151  // also written.
   152  func (db *Database) Commit(root common.Hash, report bool) error {
   153  	if db.preimages != nil {
   154  		db.preimages.commit(true)
   155  	}
   156  	return db.backend.Commit(root, report)
   157  }
   158  
   159  // Size returns the storage size of diff layer nodes above the persistent disk
   160  // layer, the dirty nodes buffered within the disk layer, and the size of cached
   161  // preimages.
   162  func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {
   163  	var (
   164  		diffs, nodes common.StorageSize
   165  		preimages    common.StorageSize
   166  	)
   167  	diffs, nodes = db.backend.Size()
   168  	if db.preimages != nil {
   169  		preimages = db.preimages.size()
   170  	}
   171  	return diffs, nodes, preimages
   172  }
   173  
   174  // Initialized returns an indicator if the state data is already initialized
   175  // according to the state scheme.
   176  func (db *Database) Initialized(genesisRoot common.Hash) bool {
   177  	return db.backend.Initialized(genesisRoot)
   178  }
   179  
   180  // Scheme returns the node scheme used in the database.
   181  func (db *Database) Scheme() string {
   182  	if db.config.PathDB != nil {
   183  		return rawdb.PathScheme
   184  	}
   185  	return rawdb.HashScheme
   186  }
   187  
   188  // Close flushes the dangling preimages to disk and closes the trie database.
   189  // It is meant to be called when closing the blockchain object, so that all
   190  // resources held can be released correctly.
   191  func (db *Database) Close() error {
   192  	db.WritePreimages()
   193  	return db.backend.Close()
   194  }
   195  
   196  // WritePreimages flushes all accumulated preimages to disk forcibly.
   197  func (db *Database) WritePreimages() {
   198  	if db.preimages != nil {
   199  		db.preimages.commit(true)
   200  	}
   201  }
   202  
   203  // Preimage retrieves a cached trie node pre-image from preimage store.
   204  func (db *Database) Preimage(hash common.Hash) []byte {
   205  	if db.preimages == nil {
   206  		return nil
   207  	}
   208  	return db.preimages.preimage(hash)
   209  }
   210  
   211  // InsertPreimage writes pre-images of trie node to the preimage store.
   212  func (db *Database) InsertPreimage(preimages map[common.Hash][]byte) {
   213  	if db.preimages == nil {
   214  		return
   215  	}
   216  	db.preimages.insertPreimage(preimages)
   217  }
   218  
   219  // Cap iteratively flushes old but still referenced trie nodes until the total
   220  // memory usage goes below the given threshold. The held pre-images accumulated
   221  // up to this point will be flushed in case the size exceeds the threshold.
   222  //
   223  // It's only supported by hash-based database and will return an error for others.
   224  func (db *Database) Cap(limit common.StorageSize) error {
   225  	hdb, ok := db.backend.(*hashdb.Database)
   226  	if !ok {
   227  		return errors.New("not supported")
   228  	}
   229  	if db.preimages != nil {
   230  		db.preimages.commit(false)
   231  	}
   232  	return hdb.Cap(limit)
   233  }
   234  
   235  // Reference adds a new reference from a parent node to a child node. This function
   236  // is used to add reference between internal trie node and external node(e.g. storage
   237  // trie root), all internal trie nodes are referenced together by database itself.
   238  //
   239  // It's only supported by hash-based database and will return an error for others.
   240  func (db *Database) Reference(root common.Hash, parent common.Hash) error {
   241  	hdb, ok := db.backend.(*hashdb.Database)
   242  	if !ok {
   243  		return errors.New("not supported")
   244  	}
   245  	hdb.Reference(root, parent)
   246  	return nil
   247  }
   248  
   249  // Dereference removes an existing reference from a root node. It's only
   250  // supported by hash-based database and will return an error for others.
   251  func (db *Database) Dereference(root common.Hash) error {
   252  	hdb, ok := db.backend.(*hashdb.Database)
   253  	if !ok {
   254  		return errors.New("not supported")
   255  	}
   256  	hdb.Dereference(root)
   257  	return nil
   258  }
   259  
   260  // Recover rollbacks the database to a specified historical point. The state is
   261  // supported as the rollback destination only if it's canonical state and the
   262  // corresponding trie histories are existent. It's only supported by path-based
   263  // database and will return an error for others.
   264  func (db *Database) Recover(target common.Hash) error {
   265  	pdb, ok := db.backend.(*pathdb.Database)
   266  	if !ok {
   267  		return errors.New("not supported")
   268  	}
   269  	var loader triestate.TrieLoader
   270  	if db.config.IsVerkle {
   271  		// TODO define verkle loader
   272  		log.Crit("Verkle loader is not defined")
   273  	} else {
   274  		loader = trie.NewMerkleLoader(db)
   275  	}
   276  	return pdb.Recover(target, loader)
   277  }
   278  
   279  // Recoverable returns the indicator if the specified state is enabled to be
   280  // recovered. It's only supported by path-based database and will return an
   281  // error for others.
   282  func (db *Database) Recoverable(root common.Hash) (bool, error) {
   283  	pdb, ok := db.backend.(*pathdb.Database)
   284  	if !ok {
   285  		return false, errors.New("not supported")
   286  	}
   287  	return pdb.Recoverable(root), nil
   288  }
   289  
   290  // Disable deactivates the database and invalidates all available state layers
   291  // as stale to prevent access to the persistent state, which is in the syncing
   292  // stage.
   293  //
   294  // It's only supported by path-based database and will return an error for others.
   295  func (db *Database) Disable() error {
   296  	pdb, ok := db.backend.(*pathdb.Database)
   297  	if !ok {
   298  		return errors.New("not supported")
   299  	}
   300  	return pdb.Disable()
   301  }
   302  
   303  // Enable activates database and resets the state tree with the provided persistent
   304  // state root once the state sync is finished.
   305  func (db *Database) Enable(root common.Hash) error {
   306  	pdb, ok := db.backend.(*pathdb.Database)
   307  	if !ok {
   308  		return errors.New("not supported")
   309  	}
   310  	return pdb.Enable(root)
   311  }
   312  
   313  // Journal commits an entire diff hierarchy to disk into a single journal entry.
   314  // This is meant to be used during shutdown to persist the snapshot without
   315  // flattening everything down (bad for reorgs). It's only supported by path-based
   316  // database and will return an error for others.
   317  func (db *Database) Journal(root common.Hash) error {
   318  	pdb, ok := db.backend.(*pathdb.Database)
   319  	if !ok {
   320  		return errors.New("not supported")
   321  	}
   322  	return pdb.Journal(root)
   323  }
   324  
   325  // SetBufferSize sets the node buffer size to the provided value(in bytes).
   326  // It's only supported by path-based database and will return an error for
   327  // others.
   328  func (db *Database) SetBufferSize(size int) error {
   329  	pdb, ok := db.backend.(*pathdb.Database)
   330  	if !ok {
   331  		return errors.New("not supported")
   332  	}
   333  	return pdb.SetBufferSize(size)
   334  }
   335  
   336  // IsVerkle returns the indicator if the database is holding a verkle tree.
   337  func (db *Database) IsVerkle() bool {
   338  	return db.config.IsVerkle
   339  }