github.com/theQRL/go-zond@v0.1.1/trie/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 trie
    18  
    19  import (
    20  	"errors"
    21  
    22  	"github.com/theQRL/go-zond/common"
    23  	"github.com/theQRL/go-zond/log"
    24  	"github.com/theQRL/go-zond/trie/triedb/hashdb"
    25  	"github.com/theQRL/go-zond/trie/triedb/pathdb"
    26  	"github.com/theQRL/go-zond/trie/trienode"
    27  	"github.com/theQRL/go-zond/trie/triestate"
    28  	"github.com/theQRL/go-zond/zonddb"
    29  )
    30  
    31  // Config defines all necessary options for database.
    32  type Config struct {
    33  	Preimages bool           // Flag whether the preimage of node key is recorded
    34  	HashDB    *hashdb.Config // Configs for hash-based scheme
    35  	PathDB    *pathdb.Config // Configs for experimental path-based scheme
    36  }
    37  
    38  // HashDefaults represents a config for using hash-based scheme with
    39  // default settings.
    40  var HashDefaults = &Config{
    41  	Preimages: false,
    42  	HashDB:    hashdb.Defaults,
    43  }
    44  
    45  // backend defines the methods needed to access/update trie nodes in different
    46  // state scheme.
    47  type backend interface {
    48  	// Scheme returns the identifier of used storage scheme.
    49  	Scheme() string
    50  
    51  	// Initialized returns an indicator if the state data is already initialized
    52  	// according to the state scheme.
    53  	Initialized(genesisRoot common.Hash) bool
    54  
    55  	// Size returns the current storage size of the diff layers on top of the
    56  	// disk layer and the storage size of the nodes cached in the disk layer.
    57  	//
    58  	// For hash scheme, there is no differentiation between diff layer nodes
    59  	// and dirty disk layer nodes, so both are merged into the second return.
    60  	Size() (common.StorageSize, common.StorageSize)
    61  
    62  	// Update performs a state transition by committing dirty nodes contained
    63  	// in the given set in order to update state from the specified parent to
    64  	// the specified root.
    65  	//
    66  	// The passed in maps(nodes, states) will be retained to avoid copying
    67  	// everything. Therefore, these maps must not be changed afterwards.
    68  	Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error
    69  
    70  	// Commit writes all relevant trie nodes belonging to the specified state
    71  	// to disk. Report specifies whether logs will be displayed in info level.
    72  	Commit(root common.Hash, report bool) error
    73  
    74  	// Close closes the trie database backend and releases all held resources.
    75  	Close() error
    76  }
    77  
    78  // Database is the wrapper of the underlying backend which is shared by different
    79  // types of node backend as an entrypoint. It's responsible for all interactions
    80  // relevant with trie nodes and node preimages.
    81  type Database struct {
    82  	config    *Config         // Configuration for trie database
    83  	diskdb    zonddb.Database // Persistent database to store the snapshot
    84  	preimages *preimageStore  // The store for caching preimages
    85  	backend   backend         // The backend for managing trie nodes
    86  }
    87  
    88  // NewDatabase initializes the trie database with default settings, note
    89  // the legacy hash-based scheme is used by default.
    90  func NewDatabase(diskdb zonddb.Database, config *Config) *Database {
    91  	// Sanitize the config and use the default one if it's not specified.
    92  	if config == nil {
    93  		config = HashDefaults
    94  	}
    95  	var preimages *preimageStore
    96  	if config.Preimages {
    97  		preimages = newPreimageStore(diskdb)
    98  	}
    99  	db := &Database{
   100  		config:    config,
   101  		diskdb:    diskdb,
   102  		preimages: preimages,
   103  	}
   104  	if config.HashDB != nil && config.PathDB != nil {
   105  		log.Crit("Both 'hash' and 'path' mode are configured")
   106  	}
   107  	if config.PathDB != nil {
   108  		db.backend = pathdb.New(diskdb, config.PathDB)
   109  	} else {
   110  		db.backend = hashdb.New(diskdb, config.HashDB, mptResolver{})
   111  	}
   112  	return db
   113  }
   114  
   115  // Reader returns a reader for accessing all trie nodes with provided state root.
   116  // An error will be returned if the requested state is not available.
   117  func (db *Database) Reader(blockRoot common.Hash) (Reader, error) {
   118  	switch b := db.backend.(type) {
   119  	case *hashdb.Database:
   120  		return b.Reader(blockRoot)
   121  	case *pathdb.Database:
   122  		return b.Reader(blockRoot)
   123  	}
   124  	return nil, errors.New("unknown backend")
   125  }
   126  
   127  // Update performs a state transition by committing dirty nodes contained in the
   128  // given set in order to update state from the specified parent to the specified
   129  // root. The held pre-images accumulated up to this point will be flushed in case
   130  // the size exceeds the threshold.
   131  //
   132  // The passed in maps(nodes, states) will be retained to avoid copying everything.
   133  // Therefore, these maps must not be changed afterwards.
   134  func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
   135  	if db.preimages != nil {
   136  		db.preimages.commit(false)
   137  	}
   138  	return db.backend.Update(root, parent, block, nodes, states)
   139  }
   140  
   141  // Commit iterates over all the children of a particular node, writes them out
   142  // to disk. As a side effect, all pre-images accumulated up to this point are
   143  // also written.
   144  func (db *Database) Commit(root common.Hash, report bool) error {
   145  	if db.preimages != nil {
   146  		db.preimages.commit(true)
   147  	}
   148  	return db.backend.Commit(root, report)
   149  }
   150  
   151  // Size returns the storage size of diff layer nodes above the persistent disk
   152  // layer, the dirty nodes buffered within the disk layer, and the size of cached
   153  // preimages.
   154  func (db *Database) Size() (common.StorageSize, common.StorageSize, common.StorageSize) {
   155  	var (
   156  		diffs, nodes common.StorageSize
   157  		preimages    common.StorageSize
   158  	)
   159  	diffs, nodes = db.backend.Size()
   160  	if db.preimages != nil {
   161  		preimages = db.preimages.size()
   162  	}
   163  	return diffs, nodes, preimages
   164  }
   165  
   166  // Initialized returns an indicator if the state data is already initialized
   167  // according to the state scheme.
   168  func (db *Database) Initialized(genesisRoot common.Hash) bool {
   169  	return db.backend.Initialized(genesisRoot)
   170  }
   171  
   172  // Scheme returns the node scheme used in the database.
   173  func (db *Database) Scheme() string {
   174  	return db.backend.Scheme()
   175  }
   176  
   177  // Close flushes the dangling preimages to disk and closes the trie database.
   178  // It is meant to be called when closing the blockchain object, so that all
   179  // resources held can be released correctly.
   180  func (db *Database) Close() error {
   181  	db.WritePreimages()
   182  	return db.backend.Close()
   183  }
   184  
   185  // WritePreimages flushes all accumulated preimages to disk forcibly.
   186  func (db *Database) WritePreimages() {
   187  	if db.preimages != nil {
   188  		db.preimages.commit(true)
   189  	}
   190  }
   191  
   192  // Cap iteratively flushes old but still referenced trie nodes until the total
   193  // memory usage goes below the given threshold. The held pre-images accumulated
   194  // up to this point will be flushed in case the size exceeds the threshold.
   195  //
   196  // It's only supported by hash-based database and will return an error for others.
   197  func (db *Database) Cap(limit common.StorageSize) error {
   198  	hdb, ok := db.backend.(*hashdb.Database)
   199  	if !ok {
   200  		return errors.New("not supported")
   201  	}
   202  	if db.preimages != nil {
   203  		db.preimages.commit(false)
   204  	}
   205  	return hdb.Cap(limit)
   206  }
   207  
   208  // Reference adds a new reference from a parent node to a child node. This function
   209  // is used to add reference between internal trie node and external node(e.g. storage
   210  // trie root), all internal trie nodes are referenced together by database itself.
   211  //
   212  // It's only supported by hash-based database and will return an error for others.
   213  func (db *Database) Reference(root common.Hash, parent common.Hash) error {
   214  	hdb, ok := db.backend.(*hashdb.Database)
   215  	if !ok {
   216  		return errors.New("not supported")
   217  	}
   218  	hdb.Reference(root, parent)
   219  	return nil
   220  }
   221  
   222  // Dereference removes an existing reference from a root node. It's only
   223  // supported by hash-based database and will return an error for others.
   224  func (db *Database) Dereference(root common.Hash) error {
   225  	hdb, ok := db.backend.(*hashdb.Database)
   226  	if !ok {
   227  		return errors.New("not supported")
   228  	}
   229  	hdb.Dereference(root)
   230  	return nil
   231  }
   232  
   233  // Node retrieves the rlp-encoded node blob with provided node hash. It's
   234  // only supported by hash-based database and will return an error for others.
   235  // Note, this function should be deprecated once ETH66 is deprecated.
   236  func (db *Database) Node(hash common.Hash) ([]byte, error) {
   237  	hdb, ok := db.backend.(*hashdb.Database)
   238  	if !ok {
   239  		return nil, errors.New("not supported")
   240  	}
   241  	return hdb.Node(hash)
   242  }
   243  
   244  // Recover rollbacks the database to a specified historical point. The state is
   245  // supported as the rollback destination only if it's canonical state and the
   246  // corresponding trie histories are existent. It's only supported by path-based
   247  // database and will return an error for others.
   248  func (db *Database) Recover(target common.Hash) error {
   249  	pdb, ok := db.backend.(*pathdb.Database)
   250  	if !ok {
   251  		return errors.New("not supported")
   252  	}
   253  	return pdb.Recover(target, &trieLoader{db: db})
   254  }
   255  
   256  // Recoverable returns the indicator if the specified state is enabled to be
   257  // recovered. It's only supported by path-based database and will return an
   258  // error for others.
   259  func (db *Database) Recoverable(root common.Hash) (bool, error) {
   260  	pdb, ok := db.backend.(*pathdb.Database)
   261  	if !ok {
   262  		return false, errors.New("not supported")
   263  	}
   264  	return pdb.Recoverable(root), nil
   265  }
   266  
   267  // Reset wipes all available journal from the persistent database and discard
   268  // all caches and diff layers. Using the given root to create a new disk layer.
   269  // It's only supported by path-based database and will return an error for others.
   270  func (db *Database) Reset(root common.Hash) error {
   271  	pdb, ok := db.backend.(*pathdb.Database)
   272  	if !ok {
   273  		return errors.New("not supported")
   274  	}
   275  	return pdb.Reset(root)
   276  }
   277  
   278  // Journal commits an entire diff hierarchy to disk into a single journal entry.
   279  // This is meant to be used during shutdown to persist the snapshot without
   280  // flattening everything down (bad for reorgs). It's only supported by path-based
   281  // database and will return an error for others.
   282  func (db *Database) Journal(root common.Hash) error {
   283  	pdb, ok := db.backend.(*pathdb.Database)
   284  	if !ok {
   285  		return errors.New("not supported")
   286  	}
   287  	return pdb.Journal(root)
   288  }
   289  
   290  // SetBufferSize sets the node buffer size to the provided value(in bytes).
   291  // It's only supported by path-based database and will return an error for
   292  // others.
   293  func (db *Database) SetBufferSize(size int) error {
   294  	pdb, ok := db.backend.(*pathdb.Database)
   295  	if !ok {
   296  		return errors.New("not supported")
   297  	}
   298  	return pdb.SetBufferSize(size)
   299  }