github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state/snapshot/snapshot.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 2019 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 snapshot implements a journalled, dynamic state dump.
    28  package snapshot
    29  
    30  import (
    31  	"bytes"
    32  	"errors"
    33  	"fmt"
    34  	"sync"
    35  	"sync/atomic"
    36  	"time"
    37  
    38  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    39  	"github.com/MetalBlockchain/subnet-evm/ethdb"
    40  	"github.com/MetalBlockchain/subnet-evm/metrics"
    41  	"github.com/MetalBlockchain/subnet-evm/trie"
    42  	"github.com/MetalBlockchain/subnet-evm/utils"
    43  	"github.com/ethereum/go-ethereum/common"
    44  	"github.com/ethereum/go-ethereum/log"
    45  )
    46  
    47  const (
    48  	// skipGenThreshold is the minimum time that must have elapsed since the
    49  	// creation of the previous disk layer to start snapshot generation on a new
    50  	// disk layer.
    51  	//
    52  	// If disk layers are being discarded at a frequency greater than this threshold,
    53  	// starting snapshot generation is not worth it (will be aborted before meaningful
    54  	// work can be done).
    55  	skipGenThreshold = 500 * time.Millisecond
    56  )
    57  
    58  var (
    59  	snapshotCleanAccountHitMeter   = metrics.NewRegisteredMeter("state/snapshot/clean/account/hit", nil)
    60  	snapshotCleanAccountMissMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/account/miss", nil)
    61  	snapshotCleanAccountInexMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/account/inex", nil)
    62  	snapshotCleanAccountReadMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/account/read", nil)
    63  	snapshotCleanAccountWriteMeter = metrics.NewRegisteredMeter("state/snapshot/clean/account/write", nil)
    64  
    65  	snapshotCleanStorageHitMeter   = metrics.NewRegisteredMeter("state/snapshot/clean/storage/hit", nil)
    66  	snapshotCleanStorageMissMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/storage/miss", nil)
    67  	snapshotCleanStorageInexMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/storage/inex", nil)
    68  	snapshotCleanStorageReadMeter  = metrics.NewRegisteredMeter("state/snapshot/clean/storage/read", nil)
    69  	snapshotCleanStorageWriteMeter = metrics.NewRegisteredMeter("state/snapshot/clean/storage/write", nil)
    70  
    71  	snapshotDirtyAccountHitMeter   = metrics.NewRegisteredMeter("state/snapshot/dirty/account/hit", nil)
    72  	snapshotDirtyAccountMissMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/account/miss", nil)
    73  	snapshotDirtyAccountInexMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/account/inex", nil)
    74  	snapshotDirtyAccountReadMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/account/read", nil)
    75  	snapshotDirtyAccountWriteMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/account/write", nil)
    76  
    77  	snapshotDirtyStorageHitMeter   = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/hit", nil)
    78  	snapshotDirtyStorageMissMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/miss", nil)
    79  	snapshotDirtyStorageInexMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/inex", nil)
    80  	snapshotDirtyStorageReadMeter  = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/read", nil)
    81  	snapshotDirtyStorageWriteMeter = metrics.NewRegisteredMeter("state/snapshot/dirty/storage/write", nil)
    82  
    83  	snapshotDirtyAccountHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/account/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015))
    84  	snapshotDirtyStorageHitDepthHist = metrics.NewRegisteredHistogram("state/snapshot/dirty/storage/hit/depth", nil, metrics.NewExpDecaySample(1028, 0.015))
    85  
    86  	snapshotFlushAccountItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/item", nil)
    87  	snapshotFlushAccountSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/account/size", nil)
    88  	snapshotFlushStorageItemMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/item", nil)
    89  	snapshotFlushStorageSizeMeter = metrics.NewRegisteredMeter("state/snapshot/flush/storage/size", nil)
    90  
    91  	snapshotBloomIndexTimer = metrics.NewRegisteredResettingTimer("state/snapshot/bloom/index", nil)
    92  	snapshotBloomErrorGauge = metrics.NewRegisteredGaugeFloat64("state/snapshot/bloom/error", nil)
    93  
    94  	snapshotBloomAccountTrueHitMeter  = metrics.NewRegisteredMeter("state/snapshot/bloom/account/truehit", nil)
    95  	snapshotBloomAccountFalseHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/account/falsehit", nil)
    96  	snapshotBloomAccountMissMeter     = metrics.NewRegisteredMeter("state/snapshot/bloom/account/miss", nil)
    97  
    98  	snapshotBloomStorageTrueHitMeter  = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/truehit", nil)
    99  	snapshotBloomStorageFalseHitMeter = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/falsehit", nil)
   100  	snapshotBloomStorageMissMeter     = metrics.NewRegisteredMeter("state/snapshot/bloom/storage/miss", nil)
   101  
   102  	// ErrSnapshotStale is returned from data accessors if the underlying snapshot
   103  	// layer had been invalidated due to the chain progressing forward far enough
   104  	// to not maintain the layer's original state.
   105  	ErrSnapshotStale = errors.New("snapshot stale")
   106  
   107  	// ErrStaleParentLayer is returned when Flatten attempts to flatten a diff layer into
   108  	// a stale parent.
   109  	ErrStaleParentLayer = errors.New("parent disk layer is stale")
   110  
   111  	// ErrNotCoveredYet is returned from data accessors if the underlying snapshot
   112  	// is being generated currently and the requested data item is not yet in the
   113  	// range of accounts covered.
   114  	ErrNotCoveredYet = errors.New("not covered yet")
   115  
   116  	// ErrNotConstructed is returned if the callers want to iterate the snapshot
   117  	// while the generation is not finished yet.
   118  	ErrNotConstructed = errors.New("snapshot is not constructed")
   119  )
   120  
   121  // Snapshot represents the functionality supported by a snapshot storage layer.
   122  type Snapshot interface {
   123  	// Root returns the root hash for which this snapshot was made.
   124  	Root() common.Hash
   125  
   126  	// Account directly retrieves the account associated with a particular hash in
   127  	// the snapshot slim data format.
   128  	Account(hash common.Hash) (*Account, error)
   129  
   130  	// AccountRLP directly retrieves the account RLP associated with a particular
   131  	// hash in the snapshot slim data format.
   132  	AccountRLP(hash common.Hash) ([]byte, error)
   133  
   134  	// Storage directly retrieves the storage data associated with a particular hash,
   135  	// within a particular account.
   136  	Storage(accountHash, storageHash common.Hash) ([]byte, error)
   137  
   138  	// AccountIterator creates an account iterator over the account trie given by the provided root hash.
   139  	AccountIterator(seek common.Hash) AccountIterator
   140  
   141  	// StorageIterator creates a storage iterator over the storage trie given by the provided root hash.
   142  	StorageIterator(account common.Hash, seek common.Hash) (StorageIterator, bool)
   143  }
   144  
   145  // snapshot is the internal version of the snapshot data layer that supports some
   146  // additional methods compared to the public API.
   147  type snapshot interface {
   148  	Snapshot
   149  
   150  	BlockHash() common.Hash
   151  
   152  	// Parent returns the subsequent layer of a snapshot, or nil if the base was
   153  	// reached.
   154  	//
   155  	// Note, the method is an internal helper to avoid type switching between the
   156  	// disk and diff layers. There is no locking involved.
   157  	Parent() snapshot
   158  
   159  	// Update creates a new layer on top of the existing snapshot diff tree with
   160  	// the specified data items.
   161  	//
   162  	// Note, the maps are retained by the method to avoid copying everything.
   163  	Update(blockHash, blockRoot common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) *diffLayer
   164  
   165  	// Stale return whether this layer has become stale (was flattened across) or
   166  	// if it's still live.
   167  	Stale() bool
   168  }
   169  
   170  // Tree is an Ethereum state snapshot tree. It consists of one persistent base
   171  // layer backed by a key-value store, on top of which arbitrarily many in-memory
   172  // diff layers are topped. The memory diffs can form a tree with branching, but
   173  // the disk layer is singleton and common to all. If a reorg goes deeper than the
   174  // disk layer, everything needs to be deleted.
   175  //
   176  // The goal of a state snapshot is twofold: to allow direct access to account and
   177  // storage data to avoid expensive multi-level trie lookups; and to allow sorted,
   178  // cheap iteration of the account/storage tries for sync aid.
   179  type Tree struct {
   180  	diskdb ethdb.KeyValueStore // Persistent database to store the snapshot
   181  	triedb *trie.Database      // In-memory cache to access the trie through
   182  	cache  int                 // Megabytes permitted to use for read caches
   183  	// Collection of all known layers
   184  	// blockHash -> snapshot
   185  	blockLayers map[common.Hash]snapshot
   186  	// stateRoot -> blockHash -> snapshot
   187  	// Update creates a new block layer with a parent taken from the blockHash -> snapshot map
   188  	// we can support grabbing a read only Snapshot by getting any one from the state root based map
   189  	stateLayers map[common.Hash]map[common.Hash]snapshot
   190  	verified    bool // Indicates if snapshot integrity has been verified
   191  	lock        sync.RWMutex
   192  
   193  	// Test hooks
   194  	onFlatten func() // Hook invoked when the bottom most diff layers are flattened
   195  }
   196  
   197  // New attempts to load an already existing snapshot from a persistent key-value
   198  // store (with a number of memory layers from a journal), ensuring that the head
   199  // of the snapshot matches the expected one.
   200  //
   201  // If the snapshot is missing or the disk layer is broken, the snapshot will be
   202  // reconstructed using both the existing data and the state trie.
   203  // The repair happens on a background thread.
   204  func New(diskdb ethdb.KeyValueStore, triedb *trie.Database, cache int, blockHash, root common.Hash, async bool, rebuild bool, verify bool) (*Tree, error) {
   205  	// Create a new, empty snapshot tree
   206  	snap := &Tree{
   207  		diskdb:      diskdb,
   208  		triedb:      triedb,
   209  		cache:       cache,
   210  		blockLayers: make(map[common.Hash]snapshot),
   211  		stateLayers: make(map[common.Hash]map[common.Hash]snapshot),
   212  		verified:    !verify, // if verify is false, all verification will be bypassed
   213  	}
   214  
   215  	// Attempt to load a previously persisted snapshot and rebuild one if failed
   216  	head, generated, err := loadSnapshot(diskdb, triedb, cache, blockHash, root)
   217  	if err != nil {
   218  		if rebuild {
   219  			log.Warn("Failed to load snapshot, regenerating", "err", err)
   220  			snap.Rebuild(blockHash, root)
   221  			if !async {
   222  				if err := snap.verifyIntegrity(snap.disklayer(), true); err != nil {
   223  					return nil, err
   224  				}
   225  			}
   226  			return snap, nil
   227  		}
   228  		return nil, err // Bail out the error, don't rebuild automatically.
   229  	}
   230  
   231  	// Existing snapshot loaded, seed all the layers
   232  	// It is unnecessary to grab the lock here, since it was created within this function
   233  	// call, but we grab it nevertheless to follow the spec for insertSnap.
   234  	snap.lock.Lock()
   235  	defer snap.lock.Unlock()
   236  	for head != nil {
   237  		snap.insertSnap(head)
   238  		head = head.Parent()
   239  	}
   240  
   241  	// Verify any synchronously generated or loaded snapshot from disk
   242  	if !async || generated {
   243  		if err := snap.verifyIntegrity(snap.disklayer(), !async && !generated); err != nil {
   244  			return nil, err
   245  		}
   246  	}
   247  
   248  	return snap, nil
   249  }
   250  
   251  // insertSnap inserts [snap] into the tree.
   252  // Assumes the lock is held.
   253  func (t *Tree) insertSnap(snap snapshot) {
   254  	t.blockLayers[snap.BlockHash()] = snap
   255  	blockSnaps, ok := t.stateLayers[snap.Root()]
   256  	if !ok {
   257  		blockSnaps = make(map[common.Hash]snapshot)
   258  		t.stateLayers[snap.Root()] = blockSnaps
   259  	}
   260  	blockSnaps[snap.BlockHash()] = snap
   261  }
   262  
   263  // Snapshot retrieves a snapshot belonging to the given state root, or nil if no
   264  // snapshot is maintained for that state root.
   265  func (t *Tree) Snapshot(stateRoot common.Hash) Snapshot {
   266  	return t.getSnapshot(stateRoot, false)
   267  }
   268  
   269  // getSnapshot retrieves a Snapshot by its state root. If the caller already holds the
   270  // snapTree lock when callthing this function, [holdsTreeLock] should be set to true.
   271  func (t *Tree) getSnapshot(stateRoot common.Hash, holdsTreeLock bool) snapshot {
   272  	if !holdsTreeLock {
   273  		t.lock.RLock()
   274  		defer t.lock.RUnlock()
   275  	}
   276  
   277  	layers := t.stateLayers[stateRoot]
   278  	for _, layer := range layers {
   279  		return layer
   280  	}
   281  	return nil
   282  }
   283  
   284  // Snapshots returns all visited layers from the topmost layer with specific
   285  // root and traverses downward. The layer amount is limited by the given number.
   286  // If nodisk is set, then disk layer is excluded.
   287  func (t *Tree) Snapshots(blockHash common.Hash, limits int, nodisk bool) []Snapshot {
   288  	t.lock.RLock()
   289  	defer t.lock.RUnlock()
   290  
   291  	if limits == 0 {
   292  		return nil
   293  	}
   294  	layer, ok := t.blockLayers[blockHash]
   295  	if !ok {
   296  		return nil
   297  	}
   298  	var ret []Snapshot
   299  	for {
   300  		if _, isdisk := layer.(*diskLayer); isdisk && nodisk {
   301  			break
   302  		}
   303  		ret = append(ret, layer)
   304  		limits -= 1
   305  		if limits == 0 {
   306  			break
   307  		}
   308  		parent := layer.Parent()
   309  		if parent == nil {
   310  			break
   311  		}
   312  		layer = parent
   313  	}
   314  	return ret
   315  }
   316  
   317  // Update adds a new snapshot into the tree, if that can be linked to an existing
   318  // old parent. It is disallowed to insert a disk layer (the origin of all).
   319  func (t *Tree) Update(blockHash, blockRoot, parentBlockHash common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error {
   320  	t.lock.Lock()
   321  	defer t.lock.Unlock()
   322  
   323  	// Grab the parent snapshot based on the parent block hash, not the parent state root
   324  	parent := t.blockLayers[parentBlockHash]
   325  	if parent == nil {
   326  		return fmt.Errorf("parent [%#x] snapshot missing", parentBlockHash)
   327  	}
   328  
   329  	snap := t.blockLayers[blockHash]
   330  	if snap != nil {
   331  		log.Warn("Attempted to insert a snapshot layer for an existing block",
   332  			"blockHash", blockHash, "blockRoot", blockRoot, "parentHash", parentBlockHash,
   333  			"existingBlockRoot", snap.Root(),
   334  		)
   335  	}
   336  
   337  	snap = parent.Update(blockHash, blockRoot, destructs, accounts, storage)
   338  	t.insertSnap(snap)
   339  	return nil
   340  }
   341  
   342  // verifyIntegrity performs an integrity check on the current snapshot using
   343  // verify. Most importantly, verifyIntegrity ensures verify is called at
   344  // most once during the entire lifetime of [Tree], returning immediately if
   345  // already invoked. If [waitBuild] is true, verifyIntegrity will wait for
   346  // generation of the snapshot to finish before verifying.
   347  //
   348  // It is assumed that the caller holds the [snapTree] lock
   349  // when calling this function.
   350  func (t *Tree) verifyIntegrity(base *diskLayer, waitBuild bool) error {
   351  	// Find the rebuild termination channel and wait until
   352  	// the snapshot is generated
   353  	if done := base.genPending; waitBuild && done != nil {
   354  		log.Info("Waiting for snapshot generation", "root", base.root)
   355  		<-done
   356  	}
   357  
   358  	if t.verified {
   359  		return nil
   360  	}
   361  
   362  	if base.genMarker != nil {
   363  		return errors.New("cannot verify integrity of an unfinished snapshot")
   364  	}
   365  
   366  	start := time.Now()
   367  	log.Info("Verifying snapshot integrity", "root", base.root)
   368  	if err := t.verify(base.root, true); err != nil {
   369  		return fmt.Errorf("unable to verify snapshot integrity: %w", err)
   370  	}
   371  
   372  	log.Info("Verified snapshot integrity", "root", base.root, "elapsed", time.Since(start))
   373  	t.verified = true
   374  	return nil
   375  }
   376  
   377  // Flatten flattens the snapshot for [blockHash] into its parent. if its
   378  // parent is not a disk layer, Flatten will return an error.
   379  // Note: a blockHash is used instead of a state root so that the exact state
   380  // transition between the two states is well defined. This is intended to
   381  // prevent the following edge case
   382  //    A
   383  //   /  \
   384  //  B    C
   385  //       |
   386  //       D
   387  // In this scenario, it's possible For (A, B) and (A, C, D) to be two
   388  // different paths to the resulting state. We use block hashes and parent
   389  // block hashes to ensure that the exact path through which we flatten
   390  // diffLayers is well defined.
   391  func (t *Tree) Flatten(blockHash common.Hash) error {
   392  	t.lock.Lock()
   393  	defer t.lock.Unlock()
   394  
   395  	start := time.Now()
   396  	snap, ok := t.blockLayers[blockHash]
   397  	if !ok {
   398  		return fmt.Errorf("cannot flatten missing snapshot: %s", blockHash)
   399  	}
   400  	diff, ok := snap.(*diffLayer)
   401  	if !ok {
   402  		return fmt.Errorf("cannot flatten disk layer: (%s, %s)", blockHash, snap.Root())
   403  	}
   404  	if diff.parent == nil {
   405  		return fmt.Errorf("cannot flatten snapshot with missing parent (%s, %s)", blockHash, diff.root)
   406  	}
   407  	if parentDiff, ok := diff.parent.(*diffLayer); ok {
   408  		return fmt.Errorf("cannot flatten snapshot (%s, %s) into diff layer parent (%s, %s)", blockHash, diff.root, parentDiff.blockHash, parentDiff.root)
   409  	}
   410  	parentLayer := t.blockLayers[diff.parent.BlockHash()]
   411  	if parentLayer == nil {
   412  		return fmt.Errorf("snapshot missing parent layer: %s", diff.parent.BlockHash())
   413  	}
   414  
   415  	diff.lock.Lock()
   416  	// Invoke the hook if it's registered. Ugly hack.
   417  	if t.onFlatten != nil {
   418  		t.onFlatten()
   419  	}
   420  	base, snapshotGenerated, err := diffToDisk(diff)
   421  	diff.lock.Unlock()
   422  	if err != nil {
   423  		return err
   424  	}
   425  
   426  	// Remove parent layer
   427  	if err := t.discard(diff.parent.BlockHash(), true); err != nil {
   428  		return fmt.Errorf("failed to discard parent layer while flattening (%s, %s): %w", blockHash, diff.root, err)
   429  	}
   430  	// We created a new diskLayer [base] to replace [diff], so we need to replace
   431  	// it in both maps and replace all pointers to it.
   432  	t.blockLayers[base.blockHash] = base
   433  	stateSnaps := t.stateLayers[base.root]
   434  	// stateSnaps must already be initialized here, since we are replacing
   435  	// an existing snapshot instead of adding a new one.
   436  	stateSnaps[base.blockHash] = base
   437  
   438  	// Replace the parent pointers for any snapshot that referenced
   439  	// the replaced diffLayer.
   440  	for _, snap := range t.blockLayers {
   441  		if diff, ok := snap.(*diffLayer); ok {
   442  			if base.blockHash == diff.parent.BlockHash() {
   443  				diff.lock.Lock()
   444  				diff.parent = base
   445  				diff.lock.Unlock()
   446  			}
   447  		}
   448  	}
   449  
   450  	// TODO add tracking of children to the snapshots to reduce overhead here.
   451  	children := make(map[common.Hash][]common.Hash)
   452  	for blockHash, snap := range t.blockLayers {
   453  		if diff, ok := snap.(*diffLayer); ok {
   454  			parent := diff.parent.BlockHash()
   455  			children[parent] = append(children[parent], blockHash)
   456  		}
   457  	}
   458  	var remove func(blockHash common.Hash)
   459  	remove = func(blockHash common.Hash) {
   460  		t.discard(blockHash, false)
   461  		for _, child := range children[blockHash] {
   462  			remove(child)
   463  		}
   464  		delete(children, blockHash)
   465  	}
   466  	for blockHash, snap := range t.blockLayers {
   467  		if snap.Stale() {
   468  			remove(blockHash)
   469  		}
   470  	}
   471  	// If the disk layer was modified, regenerate all the cumulative blooms
   472  	var rebloom func(blockHash common.Hash)
   473  	rebloom = func(blockHash common.Hash) {
   474  		if diff, ok := t.blockLayers[blockHash].(*diffLayer); ok {
   475  			diff.rebloom(base)
   476  		}
   477  		for _, child := range children[blockHash] {
   478  			rebloom(child)
   479  		}
   480  	}
   481  	rebloom(base.blockHash)
   482  	log.Debug("Flattened snapshot tree", "blockHash", blockHash, "root", base.root, "size", len(t.blockLayers), "elapsed", common.PrettyDuration(time.Since(start)))
   483  
   484  	if !snapshotGenerated {
   485  		return nil
   486  	}
   487  	return t.verifyIntegrity(base, false)
   488  }
   489  
   490  // Length returns the number of snapshot layers that is currently being maintained.
   491  func (t *Tree) NumStateLayers() int {
   492  	t.lock.RLock()
   493  	defer t.lock.RUnlock()
   494  
   495  	return len(t.stateLayers)
   496  }
   497  
   498  func (t *Tree) NumBlockLayers() int {
   499  	t.lock.RLock()
   500  	defer t.lock.RUnlock()
   501  
   502  	return len(t.blockLayers)
   503  }
   504  
   505  // Discard removes layers that we no longer need
   506  func (t *Tree) Discard(blockHash common.Hash) error {
   507  	t.lock.Lock()
   508  	defer t.lock.Unlock()
   509  
   510  	return t.discard(blockHash, false)
   511  }
   512  
   513  // discard removes the snapshot associated with [blockHash] from the
   514  // snapshot tree.
   515  // If [force] is true, discard may delete the disk layer. This should
   516  // only be called within Flatten, when a new disk layer is being created.
   517  // Assumes the lock is held.
   518  func (t *Tree) discard(blockHash common.Hash, force bool) error {
   519  	snap := t.blockLayers[blockHash]
   520  	if snap == nil {
   521  		return fmt.Errorf("cannot discard missing snapshot: %s", blockHash)
   522  	}
   523  	_, ok := snap.(*diffLayer)
   524  	// Never discard the disk layer
   525  	if !ok && !force {
   526  		return fmt.Errorf("cannot discard the disk layer: %s", blockHash)
   527  	}
   528  	snaps, ok := t.stateLayers[snap.Root()]
   529  	if !ok {
   530  		return fmt.Errorf("cannot discard snapshot %s missing from state: %s", blockHash, snap.Root())
   531  	}
   532  	// Discard the block from the map. If there are no more blocks
   533  	// mapping to the same state remove it from [stateLayers] as well.
   534  	delete(snaps, blockHash)
   535  	if len(snaps) == 0 {
   536  		delete(t.stateLayers, snap.Root())
   537  	}
   538  	delete(t.blockLayers, blockHash)
   539  	return nil
   540  }
   541  
   542  // AbortGeneration aborts an ongoing snapshot generation process (if it hasn't
   543  // stopped already).
   544  //
   545  // It is not required to manually abort snapshot generation. If generation has not
   546  // been manually aborted prior to invoking [diffToDisk], it will be aborted anyways.
   547  //
   548  // It is safe to call this method multiple times and when there is no snapshot
   549  // generation currently underway.
   550  func (t *Tree) AbortGeneration() {
   551  	t.lock.Lock()
   552  	defer t.lock.Unlock()
   553  
   554  	dl := t.disklayer()
   555  	dl.abortGeneration()
   556  }
   557  
   558  // abortGeneration sends an abort message to the generate goroutine and waits
   559  // for it to shutdown before returning (if it is running). This call should not
   560  // be made concurrently.
   561  func (dl *diskLayer) abortGeneration() bool {
   562  	// Store ideal time for abort to get better estimate of load
   563  	//
   564  	// Note that we set this time regardless if abortion was skipped otherwise we
   565  	// will never restart generation (age will always be negative).
   566  	if dl.abortStarted.IsZero() {
   567  		dl.abortStarted = time.Now()
   568  	}
   569  
   570  	// If the disk layer is running a snapshot generator, abort it
   571  	if dl.genAbort != nil && dl.genStats == nil {
   572  		abort := make(chan struct{})
   573  		dl.genAbort <- abort
   574  		<-abort
   575  		return true
   576  	}
   577  
   578  	return false
   579  }
   580  
   581  // diffToDisk merges a bottom-most diff into the persistent disk layer underneath
   582  // it. The method will panic if called onto a non-bottom-most diff layer.
   583  //
   584  // The disk layer persistence should be operated in an atomic way. All updates should
   585  // be discarded if the whole transition if not finished.
   586  func diffToDisk(bottom *diffLayer) (*diskLayer, bool, error) {
   587  	var (
   588  		base  = bottom.parent.(*diskLayer)
   589  		batch = base.diskdb.NewBatch()
   590  	)
   591  
   592  	// Attempt to abort generation (if not already aborted)
   593  	base.abortGeneration()
   594  
   595  	// Put the deletion in the batch writer, flush all updates in the final step.
   596  	rawdb.DeleteSnapshotBlockHash(batch)
   597  	rawdb.DeleteSnapshotRoot(batch)
   598  
   599  	// Mark the original base as stale as we're going to create a new wrapper
   600  	base.lock.Lock()
   601  	if base.stale {
   602  		base.lock.Unlock()
   603  		return nil, false, ErrStaleParentLayer // we've committed into the same base from two children, boo
   604  	}
   605  	base.stale = true
   606  	base.lock.Unlock()
   607  
   608  	// Destroy all the destructed accounts from the database
   609  	for hash := range bottom.destructSet {
   610  		// Skip any account not covered yet by the snapshot
   611  		if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 {
   612  			continue
   613  		}
   614  		// Remove all storage slots
   615  		rawdb.DeleteAccountSnapshot(batch, hash)
   616  		base.cache.Set(hash[:], nil)
   617  
   618  		it := rawdb.IterateStorageSnapshots(base.diskdb, hash)
   619  		for it.Next() {
   620  			key := it.Key()
   621  			batch.Delete(key)
   622  			base.cache.Del(key[1:])
   623  			snapshotFlushStorageItemMeter.Mark(1)
   624  
   625  			// Ensure we don't delete too much data blindly (contract can be
   626  			// huge). It's ok to flush, the root will go missing in case of a
   627  			// crash and we'll detect and regenerate the snapshot.
   628  			if batch.ValueSize() > ethdb.IdealBatchSize {
   629  				if err := batch.Write(); err != nil {
   630  					log.Crit("Failed to write storage deletions", "err", err)
   631  				}
   632  				batch.Reset()
   633  			}
   634  		}
   635  		it.Release()
   636  	}
   637  	// Push all updated accounts into the database
   638  	for hash, data := range bottom.accountData {
   639  		// Skip any account not covered yet by the snapshot
   640  		if base.genMarker != nil && bytes.Compare(hash[:], base.genMarker) > 0 {
   641  			continue
   642  		}
   643  		// Push the account to disk
   644  		rawdb.WriteAccountSnapshot(batch, hash, data)
   645  		base.cache.Set(hash[:], data)
   646  		snapshotCleanAccountWriteMeter.Mark(int64(len(data)))
   647  
   648  		snapshotFlushAccountItemMeter.Mark(1)
   649  		snapshotFlushAccountSizeMeter.Mark(int64(len(data)))
   650  
   651  		// Ensure we don't write too much data blindly. It's ok to flush, the
   652  		// root will go missing in case of a crash and we'll detect and regen
   653  		// the snapshot.
   654  		if batch.ValueSize() > ethdb.IdealBatchSize {
   655  			if err := batch.Write(); err != nil {
   656  				log.Crit("Failed to write storage deletions", "err", err)
   657  			}
   658  			batch.Reset()
   659  		}
   660  	}
   661  	// Push all the storage slots into the database
   662  	for accountHash, storage := range bottom.storageData {
   663  		// Skip any account not covered yet by the snapshot
   664  		if base.genMarker != nil && bytes.Compare(accountHash[:], base.genMarker) > 0 {
   665  			continue
   666  		}
   667  		// Generation might be mid-account, track that case too
   668  		midAccount := base.genMarker != nil && bytes.Equal(accountHash[:], base.genMarker[:common.HashLength])
   669  
   670  		for storageHash, data := range storage {
   671  			// Skip any slot not covered yet by the snapshot
   672  			if midAccount && bytes.Compare(storageHash[:], base.genMarker[common.HashLength:]) > 0 {
   673  				continue
   674  			}
   675  			if len(data) > 0 {
   676  				rawdb.WriteStorageSnapshot(batch, accountHash, storageHash, data)
   677  				base.cache.Set(append(accountHash[:], storageHash[:]...), data)
   678  				snapshotCleanStorageWriteMeter.Mark(int64(len(data)))
   679  			} else {
   680  				rawdb.DeleteStorageSnapshot(batch, accountHash, storageHash)
   681  				base.cache.Set(append(accountHash[:], storageHash[:]...), nil)
   682  			}
   683  			snapshotFlushStorageItemMeter.Mark(1)
   684  			snapshotFlushStorageSizeMeter.Mark(int64(len(data)))
   685  		}
   686  	}
   687  	// Update the snapshot block marker and write any remainder data
   688  	rawdb.WriteSnapshotBlockHash(batch, bottom.blockHash)
   689  	rawdb.WriteSnapshotRoot(batch, bottom.root)
   690  
   691  	// Write out the generator progress marker and report
   692  	journalProgress(batch, base.genMarker, base.genStats)
   693  
   694  	// Flush all the updates in the single db operation. Ensure the
   695  	// disk layer transition is atomic.
   696  	if err := batch.Write(); err != nil {
   697  		log.Crit("Failed to write leftover snapshot", "err", err)
   698  	}
   699  	log.Debug("Journalled disk layer", "root", bottom.root, "complete", base.genMarker == nil)
   700  	res := &diskLayer{
   701  		root:       bottom.root,
   702  		blockHash:  bottom.blockHash,
   703  		cache:      base.cache,
   704  		diskdb:     base.diskdb,
   705  		triedb:     base.triedb,
   706  		genMarker:  base.genMarker,
   707  		genPending: base.genPending,
   708  		created:    time.Now(),
   709  	}
   710  	// If snapshot generation hasn't finished yet, port over all the starts and
   711  	// continue where the previous round left off.
   712  	//
   713  	// Note, the `base.genAbort` comparison is not used normally, it's checked
   714  	// to allow the tests to play with the marker without triggering this path.
   715  	if base.genMarker != nil && base.genAbort != nil {
   716  		res.genMarker = base.genMarker
   717  		res.genAbort = make(chan chan struct{})
   718  
   719  		// If the diskLayer we are about to discard is not very old, we skip
   720  		// generation on the next layer (assuming generation will just get canceled
   721  		// before doing meaningful work anyways).
   722  		diskLayerAge := base.abortStarted.Sub(base.created)
   723  		if diskLayerAge < skipGenThreshold {
   724  			log.Debug("Skipping snapshot generation", "previous disk layer age", diskLayerAge)
   725  			res.genStats = base.genStats
   726  		} else {
   727  			go res.generate(base.genStats)
   728  		}
   729  	}
   730  	return res, base.genMarker == nil, nil
   731  }
   732  
   733  // Rebuild wipes all available snapshot data from the persistent database and
   734  // discard all caches and diff layers. Afterwards, it starts a new snapshot
   735  // generator with the given root hash.
   736  func (t *Tree) Rebuild(blockHash, root common.Hash) {
   737  	t.lock.Lock()
   738  	defer t.lock.Unlock()
   739  
   740  	// Track whether there's a wipe currently running and keep it alive if so
   741  	var wiper chan struct{}
   742  
   743  	// Iterate over and mark all layers stale
   744  	for _, layer := range t.blockLayers {
   745  		switch layer := layer.(type) {
   746  		case *diskLayer:
   747  			// If the base layer is generating, abort it and save
   748  			if layer.genAbort != nil {
   749  				abort := make(chan struct{})
   750  				layer.genAbort <- abort
   751  				<-abort
   752  
   753  				if stats := layer.genStats; stats != nil {
   754  					wiper = stats.wiping
   755  				}
   756  			}
   757  			// Layer should be inactive now, mark it as stale
   758  			layer.lock.Lock()
   759  			layer.stale = true
   760  			layer.lock.Unlock()
   761  
   762  		case *diffLayer:
   763  			// If the layer is a simple diff, simply mark as stale
   764  			layer.lock.Lock()
   765  			atomic.StoreUint32(&layer.stale, 1)
   766  			layer.lock.Unlock()
   767  
   768  		default:
   769  			panic(fmt.Sprintf("unknown layer type: %T", layer))
   770  		}
   771  	}
   772  	// Start generating a new snapshot from scratch on a background thread. The
   773  	// generator will run a wiper first if there's not one running right now.
   774  	log.Info("Rebuilding state snapshot")
   775  	base := generateSnapshot(t.diskdb, t.triedb, t.cache, blockHash, root, wiper)
   776  	t.blockLayers = map[common.Hash]snapshot{
   777  		blockHash: base,
   778  	}
   779  	t.stateLayers = map[common.Hash]map[common.Hash]snapshot{
   780  		root: {
   781  			blockHash: base,
   782  		},
   783  	}
   784  }
   785  
   786  // AccountIterator creates a new account iterator for the specified root hash and
   787  // seeks to a starting account hash. When [force] is true, a new account
   788  // iterator is created without acquiring the [snapTree] lock and without
   789  // confirming that the snapshot on the disk layer is fully generated.
   790  func (t *Tree) AccountIterator(root common.Hash, seek common.Hash, force bool) (AccountIterator, error) {
   791  	if !force {
   792  		ok, err := t.generating()
   793  		if err != nil {
   794  			return nil, err
   795  		}
   796  		if ok {
   797  			return nil, ErrNotConstructed
   798  		}
   799  	}
   800  	return newFastAccountIterator(t, root, seek, force)
   801  }
   802  
   803  // StorageIterator creates a new storage iterator for the specified root hash and
   804  // account. The iterator will be move to the specific start position. When [force]
   805  // is true, a new account iterator is created without acquiring the [snapTree]
   806  // lock and without confirming that the snapshot on the disk layer is fully generated.
   807  func (t *Tree) StorageIterator(root common.Hash, account common.Hash, seek common.Hash, force bool) (StorageIterator, error) {
   808  	if !force {
   809  		ok, err := t.generating()
   810  		if err != nil {
   811  			return nil, err
   812  		}
   813  		if ok {
   814  			return nil, ErrNotConstructed
   815  		}
   816  	}
   817  	return newFastStorageIterator(t, root, account, seek, force)
   818  }
   819  
   820  // Verify iterates the whole state(all the accounts as well as the corresponding storages)
   821  // with the specific root and compares the re-computed hash with the original one.
   822  func (t *Tree) Verify(root common.Hash) error {
   823  	return t.verify(root, false)
   824  }
   825  
   826  // verify iterates the whole state(all the accounts as well as the corresponding storages)
   827  // with the specific root and compares the re-computed hash with the original one.
   828  // When [force] is true, it is assumed that the caller has confirmed that the
   829  // snapshot is generated and that they hold the snapTree lock.
   830  func (t *Tree) verify(root common.Hash, force bool) error {
   831  	acctIt, err := t.AccountIterator(root, common.Hash{}, force)
   832  	if err != nil {
   833  		return err
   834  	}
   835  	defer acctIt.Release()
   836  
   837  	got, err := generateTrieRoot(nil, acctIt, common.Hash{}, stackTrieGenerate, func(db ethdb.KeyValueWriter, accountHash, codeHash common.Hash, stat *generateStats) (common.Hash, error) {
   838  		storageIt, err := t.StorageIterator(root, accountHash, common.Hash{}, force)
   839  		if err != nil {
   840  			return common.Hash{}, err
   841  		}
   842  		defer storageIt.Release()
   843  
   844  		hash, err := generateTrieRoot(nil, storageIt, accountHash, stackTrieGenerate, nil, stat, false)
   845  		if err != nil {
   846  			return common.Hash{}, err
   847  		}
   848  		return hash, nil
   849  	}, newGenerateStats(), true)
   850  
   851  	if err != nil {
   852  		return err
   853  	}
   854  	if got != root {
   855  		return fmt.Errorf("state root hash mismatch: got %x, want %x", got, root)
   856  	}
   857  	return nil
   858  }
   859  
   860  // disklayer is an internal helper function to return the disk layer.
   861  // The lock of snapTree is assumed to be held already.
   862  func (t *Tree) disklayer() *diskLayer {
   863  	var snap snapshot
   864  	for _, s := range t.blockLayers {
   865  		snap = s
   866  		break
   867  	}
   868  	if snap == nil {
   869  		return nil
   870  	}
   871  	switch layer := snap.(type) {
   872  	case *diskLayer:
   873  		return layer
   874  	case *diffLayer:
   875  		return layer.origin
   876  	default:
   877  		panic(fmt.Sprintf("%T: undefined layer", snap))
   878  	}
   879  }
   880  
   881  // diskRoot is a internal helper function to return the disk layer root.
   882  // The lock of snapTree is assumed to be held already.
   883  func (t *Tree) diskRoot() common.Hash {
   884  	disklayer := t.disklayer()
   885  	if disklayer == nil {
   886  		return common.Hash{}
   887  	}
   888  	return disklayer.Root()
   889  }
   890  
   891  // generating is an internal helper function which reports whether the snapshot
   892  // is still under the construction.
   893  func (t *Tree) generating() (bool, error) {
   894  	t.lock.Lock()
   895  	defer t.lock.Unlock()
   896  
   897  	layer := t.disklayer()
   898  	if layer == nil {
   899  		return false, errors.New("disk layer is missing")
   900  	}
   901  	layer.lock.RLock()
   902  	defer layer.lock.RUnlock()
   903  	return layer.genMarker != nil, nil
   904  }
   905  
   906  // diskRoot is a external helper function to return the disk layer root.
   907  func (t *Tree) DiskRoot() common.Hash {
   908  	t.lock.Lock()
   909  	defer t.lock.Unlock()
   910  
   911  	return t.diskRoot()
   912  }
   913  
   914  func (t *Tree) DiskAccountIterator(seek common.Hash) AccountIterator {
   915  	t.lock.Lock()
   916  	defer t.lock.Unlock()
   917  
   918  	return t.disklayer().AccountIterator(seek)
   919  }
   920  
   921  func (t *Tree) DiskStorageIterator(account common.Hash, seek common.Hash) StorageIterator {
   922  	t.lock.Lock()
   923  	defer t.lock.Unlock()
   924  
   925  	it, _ := t.disklayer().StorageIterator(account, seek)
   926  	return it
   927  }
   928  
   929  // NewDiskLayer creates a diskLayer for direct access to the contents of the on-disk
   930  // snapshot. Does not perform any validation.
   931  func NewDiskLayer(diskdb ethdb.KeyValueStore) Snapshot {
   932  	return &diskLayer{
   933  		diskdb:  diskdb,
   934  		created: time.Now(),
   935  
   936  		// state sync uses iterators to access data, so this cache is not used.
   937  		// initializing it out of caution.
   938  		cache: utils.NewMeteredCache(32*1024, "", "", 0),
   939  	}
   940  }
   941  
   942  // NewTestTree creates a *Tree with a pre-populated diskLayer
   943  func NewTestTree(diskdb ethdb.KeyValueStore, blockHash, root common.Hash) *Tree {
   944  	base := &diskLayer{
   945  		diskdb:    diskdb,
   946  		root:      root,
   947  		blockHash: blockHash,
   948  		cache:     utils.NewMeteredCache(128*256, "", "", 0),
   949  		created:   time.Now(),
   950  	}
   951  	return &Tree{
   952  		blockLayers: map[common.Hash]snapshot{
   953  			blockHash: base,
   954  		},
   955  		stateLayers: map[common.Hash]map[common.Hash]snapshot{
   956  			root: {
   957  				blockHash: base,
   958  			},
   959  		},
   960  	}
   961  }