github.com/theQRL/go-zond@v0.1.1/trie/triedb/pathdb/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 pathdb
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"io"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/theQRL/go-zond/common"
    27  	"github.com/theQRL/go-zond/core/rawdb"
    28  	"github.com/theQRL/go-zond/core/types"
    29  	"github.com/theQRL/go-zond/zonddb"
    30  	"github.com/theQRL/go-zond/log"
    31  	"github.com/theQRL/go-zond/params"
    32  	"github.com/theQRL/go-zond/trie/trienode"
    33  	"github.com/theQRL/go-zond/trie/triestate"
    34  )
    35  
    36  const (
    37  	// maxDiffLayers is the maximum diff layers allowed in the layer tree.
    38  	maxDiffLayers = 128
    39  
    40  	// defaultCleanSize is the default memory allowance of clean cache.
    41  	defaultCleanSize = 16 * 1024 * 1024
    42  
    43  	// maxBufferSize is the maximum memory allowance of node buffer.
    44  	// Too large nodebuffer will cause the system to pause for a long
    45  	// time when write happens. Also, the largest batch that pebble can
    46  	// support is 4GB, node will panic if batch size exceeds this limit.
    47  	maxBufferSize = 256 * 1024 * 1024
    48  
    49  	// DefaultBufferSize is the default memory allowance of node buffer
    50  	// that aggregates the writes from above until it's flushed into the
    51  	// disk. It's meant to be used once the initial sync is finished.
    52  	// Do not increase the buffer size arbitrarily, otherwise the system
    53  	// pause time will increase when the database writes happen.
    54  	DefaultBufferSize = 64 * 1024 * 1024
    55  )
    56  
    57  // layer is the interface implemented by all state layers which includes some
    58  // public methods and some additional methods for internal usage.
    59  type layer interface {
    60  	// Node retrieves the trie node with the node info. An error will be returned
    61  	// if the read operation exits abnormally. For example, if the layer is already
    62  	// stale, or the associated state is regarded as corrupted. Notably, no error
    63  	// will be returned if the requested node is not found in database.
    64  	Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error)
    65  
    66  	// rootHash returns the root hash for which this layer was made.
    67  	rootHash() common.Hash
    68  
    69  	// stateID returns the associated state id of layer.
    70  	stateID() uint64
    71  
    72  	// parentLayer returns the subsequent layer of it, or nil if the disk was reached.
    73  	parentLayer() layer
    74  
    75  	// update creates a new layer on top of the existing layer diff tree with
    76  	// the provided dirty trie nodes along with the state change set.
    77  	//
    78  	// Note, the maps are retained by the method to avoid copying everything.
    79  	update(root common.Hash, id uint64, block uint64, nodes map[common.Hash]map[string]*trienode.Node, states *triestate.Set) *diffLayer
    80  
    81  	// journal commits an entire diff hierarchy to disk into a single journal entry.
    82  	// This is meant to be used during shutdown to persist the layer without
    83  	// flattening everything down (bad for reorgs).
    84  	journal(w io.Writer) error
    85  }
    86  
    87  // Config contains the settings for database.
    88  type Config struct {
    89  	StateHistory   uint64 // Number of recent blocks to maintain state history for
    90  	CleanCacheSize int    // Maximum memory allowance (in bytes) for caching clean nodes
    91  	DirtyCacheSize int    // Maximum memory allowance (in bytes) for caching dirty nodes
    92  	ReadOnly       bool   // Flag whether the database is opened in read only mode.
    93  }
    94  
    95  // sanitize checks the provided user configurations and changes anything that's
    96  // unreasonable or unworkable.
    97  func (c *Config) sanitize() *Config {
    98  	conf := *c
    99  	if conf.DirtyCacheSize > maxBufferSize {
   100  		log.Warn("Sanitizing invalid node buffer size", "provided", common.StorageSize(conf.DirtyCacheSize), "updated", common.StorageSize(maxBufferSize))
   101  		conf.DirtyCacheSize = maxBufferSize
   102  	}
   103  	return &conf
   104  }
   105  
   106  // Defaults contains default settings for Ethereum mainnet.
   107  var Defaults = &Config{
   108  	StateHistory:   params.FullImmutabilityThreshold,
   109  	CleanCacheSize: defaultCleanSize,
   110  	DirtyCacheSize: DefaultBufferSize,
   111  }
   112  
   113  // ReadOnly is the config in order to open database in read only mode.
   114  var ReadOnly = &Config{ReadOnly: true}
   115  
   116  // Database is a multiple-layered structure for maintaining in-memory trie nodes.
   117  // It consists of one persistent base layer backed by a key-value store, on top
   118  // of which arbitrarily many in-memory diff layers are stacked. The memory diffs
   119  // can form a tree with branching, but the disk layer is singleton and common to
   120  // all. If a reorg goes deeper than the disk layer, a batch of reverse diffs can
   121  // be applied to rollback. The deepest reorg that can be handled depends on the
   122  // amount of state histories tracked in the disk.
   123  //
   124  // At most one readable and writable database can be opened at the same time in
   125  // the whole system which ensures that only one database writer can operate disk
   126  // state. Unexpected open operations can cause the system to panic.
   127  type Database struct {
   128  	// readOnly is the flag whether the mutation is allowed to be applied.
   129  	// It will be set automatically when the database is journaled during
   130  	// the shutdown to reject all following unexpected mutations.
   131  	readOnly   bool                     // Indicator if database is opened in read only mode
   132  	bufferSize int                      // Memory allowance (in bytes) for caching dirty nodes
   133  	config     *Config                  // Configuration for database
   134  	diskdb     zonddb.Database           // Persistent storage for matured trie nodes
   135  	tree       *layerTree               // The group for all known layers
   136  	freezer    *rawdb.ResettableFreezer // Freezer for storing trie histories, nil possible in tests
   137  	lock       sync.RWMutex             // Lock to prevent mutations from happening at the same time
   138  }
   139  
   140  // New attempts to load an already existing layer from a persistent key-value
   141  // store (with a number of memory layers from a journal). If the journal is not
   142  // matched with the base persistent layer, all the recorded diff layers are discarded.
   143  func New(diskdb zonddb.Database, config *Config) *Database {
   144  	if config == nil {
   145  		config = Defaults
   146  	}
   147  	config = config.sanitize()
   148  
   149  	db := &Database{
   150  		readOnly:   config.ReadOnly,
   151  		bufferSize: config.DirtyCacheSize,
   152  		config:     config,
   153  		diskdb:     diskdb,
   154  	}
   155  	// Construct the layer tree by resolving the in-disk singleton state
   156  	// and in-memory layer journal.
   157  	db.tree = newLayerTree(db.loadLayers())
   158  
   159  	// Open the freezer for state history if the passed database contains an
   160  	// ancient store. Otherwise, all the relevant functionalities are disabled.
   161  	//
   162  	// Because the freezer can only be opened once at the same time, this
   163  	// mechanism also ensures that at most one **non-readOnly** database
   164  	// is opened at the same time to prevent accidental mutation.
   165  	if ancient, err := diskdb.AncientDatadir(); err == nil && ancient != "" && !db.readOnly {
   166  		freezer, err := rawdb.NewStateFreezer(ancient, false)
   167  		if err != nil {
   168  			log.Crit("Failed to open state history freezer", "err", err)
   169  		}
   170  		db.freezer = freezer
   171  
   172  		// Truncate the extra state histories above in freezer in case
   173  		// it's not aligned with the disk layer.
   174  		pruned, err := truncateFromHead(db.diskdb, freezer, db.tree.bottom().stateID())
   175  		if err != nil {
   176  			log.Crit("Failed to truncate extra state histories", "err", err)
   177  		}
   178  		if pruned != 0 {
   179  			log.Warn("Truncated extra state histories", "number", pruned)
   180  		}
   181  	}
   182  	log.Warn("Path-based state scheme is an experimental feature")
   183  	return db
   184  }
   185  
   186  // Reader retrieves a layer belonging to the given state root.
   187  func (db *Database) Reader(root common.Hash) (layer, error) {
   188  	l := db.tree.get(root)
   189  	if l == nil {
   190  		return nil, fmt.Errorf("state %#x is not available", root)
   191  	}
   192  	return l, nil
   193  }
   194  
   195  // Update adds a new layer into the tree, if that can be linked to an existing
   196  // old parent. It is disallowed to insert a disk layer (the origin of all). Apart
   197  // from that this function will flatten the extra diff layers at bottom into disk
   198  // to only keep 128 diff layers in memory by default.
   199  //
   200  // The passed in maps(nodes, states) will be retained to avoid copying everything.
   201  // Therefore, these maps must not be changed afterwards.
   202  func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set) error {
   203  	// Hold the lock to prevent concurrent mutations.
   204  	db.lock.Lock()
   205  	defer db.lock.Unlock()
   206  
   207  	// Short circuit if the database is in read only mode.
   208  	if db.readOnly {
   209  		return errSnapshotReadOnly
   210  	}
   211  	if err := db.tree.add(root, parentRoot, block, nodes, states); err != nil {
   212  		return err
   213  	}
   214  	// Keep 128 diff layers in the memory, persistent layer is 129th.
   215  	// - head layer is paired with HEAD state
   216  	// - head-1 layer is paired with HEAD-1 state
   217  	// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
   218  	// - head-128 layer(disk layer) is paired with HEAD-128 state
   219  	return db.tree.cap(root, maxDiffLayers)
   220  }
   221  
   222  // Commit traverses downwards the layer tree from a specified layer with the
   223  // provided state root and all the layers below are flattened downwards. It
   224  // can be used alone and mostly for test purposes.
   225  func (db *Database) Commit(root common.Hash, report bool) error {
   226  	// Hold the lock to prevent concurrent mutations.
   227  	db.lock.Lock()
   228  	defer db.lock.Unlock()
   229  
   230  	// Short circuit if the database is in read only mode.
   231  	if db.readOnly {
   232  		return errSnapshotReadOnly
   233  	}
   234  	return db.tree.cap(root, 0)
   235  }
   236  
   237  // Reset rebuilds the database with the specified state as the base.
   238  //
   239  //   - if target state is empty, clear the stored state and all layers on top
   240  //   - if target state is non-empty, ensure the stored state matches with it
   241  //     and clear all other layers on top.
   242  func (db *Database) Reset(root common.Hash) error {
   243  	db.lock.Lock()
   244  	defer db.lock.Unlock()
   245  
   246  	// Short circuit if the database is in read only mode.
   247  	if db.readOnly {
   248  		return errSnapshotReadOnly
   249  	}
   250  	batch := db.diskdb.NewBatch()
   251  	root = types.TrieRootHash(root)
   252  	if root == types.EmptyRootHash {
   253  		// Empty state is requested as the target, nuke out
   254  		// the root node and leave all others as dangling.
   255  		rawdb.DeleteAccountTrieNode(batch, nil)
   256  	} else {
   257  		// Ensure the requested state is existent before any
   258  		// action is applied.
   259  		_, hash := rawdb.ReadAccountTrieNode(db.diskdb, nil)
   260  		if hash != root {
   261  			return fmt.Errorf("state is mismatched, local: %x, target: %x", hash, root)
   262  		}
   263  	}
   264  	// Mark the disk layer as stale before applying any mutation.
   265  	db.tree.bottom().markStale()
   266  
   267  	// Drop the stale state journal in persistent database and
   268  	// reset the persistent state id back to zero.
   269  	rawdb.DeleteTrieJournal(batch)
   270  	rawdb.WritePersistentStateID(batch, 0)
   271  	if err := batch.Write(); err != nil {
   272  		return err
   273  	}
   274  	// Clean up all state histories in freezer. Theoretically
   275  	// all root->id mappings should be removed as well. Since
   276  	// mappings can be huge and might take a while to clear
   277  	// them, just leave them in disk and wait for overwriting.
   278  	if db.freezer != nil {
   279  		if err := db.freezer.Reset(); err != nil {
   280  			return err
   281  		}
   282  	}
   283  	// Re-construct a new disk layer backed by persistent state
   284  	// with **empty clean cache and node buffer**.
   285  	dl := newDiskLayer(root, 0, db, nil, newNodeBuffer(db.bufferSize, nil, 0))
   286  	db.tree.reset(dl)
   287  	log.Info("Rebuilt trie database", "root", root)
   288  	return nil
   289  }
   290  
   291  // Recover rollbacks the database to a specified historical point.
   292  // The state is supported as the rollback destination only if it's
   293  // canonical state and the corresponding trie histories are existent.
   294  func (db *Database) Recover(root common.Hash, loader triestate.TrieLoader) error {
   295  	db.lock.Lock()
   296  	defer db.lock.Unlock()
   297  
   298  	// Short circuit if rollback operation is not supported.
   299  	if db.readOnly || db.freezer == nil {
   300  		return errors.New("state rollback is non-supported")
   301  	}
   302  	// Short circuit if the target state is not recoverable.
   303  	root = types.TrieRootHash(root)
   304  	if !db.Recoverable(root) {
   305  		return errStateUnrecoverable
   306  	}
   307  	// Apply the state histories upon the disk layer in order.
   308  	var (
   309  		start = time.Now()
   310  		dl    = db.tree.bottom()
   311  	)
   312  	for dl.rootHash() != root {
   313  		h, err := readHistory(db.freezer, dl.stateID())
   314  		if err != nil {
   315  			return err
   316  		}
   317  		dl, err = dl.revert(h, loader)
   318  		if err != nil {
   319  			return err
   320  		}
   321  		// reset layer with newly created disk layer. It must be
   322  		// done after each revert operation, otherwise the new
   323  		// disk layer won't be accessible from outside.
   324  		db.tree.reset(dl)
   325  	}
   326  	rawdb.DeleteTrieJournal(db.diskdb)
   327  	_, err := truncateFromHead(db.diskdb, db.freezer, dl.stateID())
   328  	if err != nil {
   329  		return err
   330  	}
   331  	log.Debug("Recovered state", "root", root, "elapsed", common.PrettyDuration(time.Since(start)))
   332  	return nil
   333  }
   334  
   335  // Recoverable returns the indicator if the specified state is recoverable.
   336  func (db *Database) Recoverable(root common.Hash) bool {
   337  	// Ensure the requested state is a known state.
   338  	root = types.TrieRootHash(root)
   339  	id := rawdb.ReadStateID(db.diskdb, root)
   340  	if id == nil {
   341  		return false
   342  	}
   343  	// Recoverable state must below the disk layer. The recoverable
   344  	// state only refers the state that is currently not available,
   345  	// but can be restored by applying state history.
   346  	dl := db.tree.bottom()
   347  	if *id >= dl.stateID() {
   348  		return false
   349  	}
   350  	// Ensure the requested state is a canonical state and all state
   351  	// histories in range [id+1, disklayer.ID] are present and complete.
   352  	parent := root
   353  	return checkHistories(db.freezer, *id+1, dl.stateID()-*id, func(m *meta) error {
   354  		if m.parent != parent {
   355  			return errors.New("unexpected state history")
   356  		}
   357  		if len(m.incomplete) > 0 {
   358  			return errors.New("incomplete state history")
   359  		}
   360  		parent = m.root
   361  		return nil
   362  	}) == nil
   363  }
   364  
   365  // Close closes the trie database and the held freezer.
   366  func (db *Database) Close() error {
   367  	db.lock.Lock()
   368  	defer db.lock.Unlock()
   369  
   370  	// Set the database to read-only mode to prevent all
   371  	// following mutations.
   372  	db.readOnly = true
   373  
   374  	// Release the memory held by clean cache.
   375  	db.tree.bottom().resetCache()
   376  
   377  	// Close the attached state history freezer.
   378  	if db.freezer == nil {
   379  		return nil
   380  	}
   381  	return db.freezer.Close()
   382  }
   383  
   384  // Size returns the current storage size of the memory cache in front of the
   385  // persistent database layer.
   386  func (db *Database) Size() (diffs common.StorageSize, nodes common.StorageSize) {
   387  	db.tree.forEach(func(layer layer) {
   388  		if diff, ok := layer.(*diffLayer); ok {
   389  			diffs += common.StorageSize(diff.memory)
   390  		}
   391  		if disk, ok := layer.(*diskLayer); ok {
   392  			nodes += disk.size()
   393  		}
   394  	})
   395  	return diffs, nodes
   396  }
   397  
   398  // Initialized returns an indicator if the state data is already
   399  // initialized in path-based scheme.
   400  func (db *Database) Initialized(genesisRoot common.Hash) bool {
   401  	var inited bool
   402  	db.tree.forEach(func(layer layer) {
   403  		if layer.rootHash() != types.EmptyRootHash {
   404  			inited = true
   405  		}
   406  	})
   407  	return inited
   408  }
   409  
   410  // SetBufferSize sets the node buffer size to the provided value(in bytes).
   411  func (db *Database) SetBufferSize(size int) error {
   412  	db.lock.Lock()
   413  	defer db.lock.Unlock()
   414  
   415  	if size > maxBufferSize {
   416  		log.Info("Capped node buffer size", "provided", common.StorageSize(size), "adjusted", common.StorageSize(maxBufferSize))
   417  		size = maxBufferSize
   418  	}
   419  	db.bufferSize = size
   420  	return db.tree.bottom().setBufferSize(db.bufferSize)
   421  }
   422  
   423  // Scheme returns the node scheme used in the database.
   424  func (db *Database) Scheme() string {
   425  	return rawdb.PathScheme
   426  }