github.com/ethereum/go-ethereum@v1.16.1/triedb/pathdb/generate.go (about)

     1  // Copyright 2019 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  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  	"sync"
    24  	"time"
    25  
    26  	"github.com/ethereum/go-ethereum/common"
    27  	"github.com/ethereum/go-ethereum/common/hexutil"
    28  	"github.com/ethereum/go-ethereum/core/rawdb"
    29  	"github.com/ethereum/go-ethereum/core/types"
    30  	"github.com/ethereum/go-ethereum/crypto"
    31  	"github.com/ethereum/go-ethereum/ethdb"
    32  	"github.com/ethereum/go-ethereum/log"
    33  	"github.com/ethereum/go-ethereum/rlp"
    34  	"github.com/ethereum/go-ethereum/trie"
    35  	"github.com/ethereum/go-ethereum/triedb/database"
    36  )
    37  
    38  var (
    39  	// accountCheckRange is the upper limit of the number of accounts involved in
    40  	// each range check. This is a value estimated based on experience. If this
    41  	// range is too large, the failure rate of range proof will increase. Otherwise,
    42  	// if the range is too small, the efficiency of the state recovery will decrease.
    43  	accountCheckRange = 128
    44  
    45  	// storageCheckRange is the upper limit of the number of storage slots involved
    46  	// in each range check. This is a value estimated based on experience. If this
    47  	// range is too large, the failure rate of range proof will increase. Otherwise,
    48  	// if the range is too small, the efficiency of the state recovery will decrease.
    49  	storageCheckRange = 1024
    50  
    51  	// errMissingTrie is returned if the target trie is missing while the generation
    52  	// is running. In this case the generation is aborted and wait the new signal.
    53  	errMissingTrie = errors.New("missing trie")
    54  )
    55  
    56  // diskReader is a wrapper of key-value store and implements database.NodeReader,
    57  // providing a function for accessing persistent trie nodes in the disk
    58  type diskReader struct{ db ethdb.KeyValueStore }
    59  
    60  // Node retrieves the trie node blob with the provided trie identifier,
    61  // node path and the corresponding node hash. No error will be returned
    62  // if the node is not found.
    63  func (r *diskReader) Node(owner common.Hash, path []byte, hash common.Hash) ([]byte, error) {
    64  	if owner == (common.Hash{}) {
    65  		return rawdb.ReadAccountTrieNode(r.db, path), nil
    66  	}
    67  	return rawdb.ReadStorageTrieNode(r.db, owner, path), nil
    68  }
    69  
    70  // diskStore is a wrapper of key-value store and implements database.NodeDatabase.
    71  // It's meant to be used for generating state snapshot from the trie data.
    72  type diskStore struct {
    73  	db ethdb.KeyValueStore
    74  }
    75  
    76  // NodeReader returns a node reader associated with the specific state.
    77  // An error will be returned if the specified state is not available.
    78  func (s *diskStore) NodeReader(stateRoot common.Hash) (database.NodeReader, error) {
    79  	root := types.EmptyRootHash
    80  	if blob := rawdb.ReadAccountTrieNode(s.db, nil); len(blob) > 0 {
    81  		root = crypto.Keccak256Hash(blob)
    82  	}
    83  	if root != stateRoot {
    84  		return nil, fmt.Errorf("state %x is not available", stateRoot)
    85  	}
    86  	return &diskReader{s.db}, nil
    87  }
    88  
    89  // Generator is the struct for initial state snapshot generation. It is not thread-safe;
    90  // the caller must manage concurrency issues themselves.
    91  type generator struct {
    92  	noBuild bool // Flag indicating whether snapshot generation is permitted
    93  	running bool // Flag indicating whether the background generation is running
    94  
    95  	db    ethdb.KeyValueStore // Key-value store containing the snapshot data
    96  	stats *generatorStats     // Generation statistics used throughout the entire life cycle
    97  	abort chan chan struct{}  // Notification channel to abort generating the snapshot in this layer
    98  	done  chan struct{}       // Notification channel when generation is done
    99  
   100  	progress []byte       // Progress marker of the state generation, nil means it's completed
   101  	lock     sync.RWMutex // Lock which protects the progress, only generator can mutate the progress
   102  }
   103  
   104  // newGenerator constructs the state snapshot generator.
   105  //
   106  // noBuild will be true if the background snapshot generation is not allowed,
   107  // usually used in read-only mode.
   108  //
   109  // progress indicates the starting position for resuming snapshot generation.
   110  // It must be provided even if generation is not allowed; otherwise, uncovered
   111  // states may be exposed for serving.
   112  func newGenerator(db ethdb.KeyValueStore, noBuild bool, progress []byte, stats *generatorStats) *generator {
   113  	if stats == nil {
   114  		stats = &generatorStats{start: time.Now()}
   115  	}
   116  	return &generator{
   117  		noBuild:  noBuild,
   118  		progress: progress,
   119  		db:       db,
   120  		stats:    stats,
   121  		abort:    make(chan chan struct{}),
   122  		done:     make(chan struct{}),
   123  	}
   124  }
   125  
   126  // run starts the state snapshot generation in the background.
   127  func (g *generator) run(root common.Hash) {
   128  	if g.noBuild {
   129  		log.Warn("Snapshot generation is not permitted")
   130  		return
   131  	}
   132  	if g.running {
   133  		g.stop()
   134  		log.Warn("Paused the leftover generation cycle")
   135  	}
   136  	g.running = true
   137  	go g.generate(newGeneratorContext(root, g.progress, g.db))
   138  }
   139  
   140  // stop terminates the background generation if it's actively running.
   141  // The Recent generation progress being made will be saved before returning.
   142  func (g *generator) stop() {
   143  	if !g.running {
   144  		log.Debug("Snapshot generation is not running")
   145  		return
   146  	}
   147  	ch := make(chan struct{})
   148  	g.abort <- ch
   149  	<-ch
   150  	g.running = false
   151  }
   152  
   153  // completed returns the flag indicating if the whole generation is done.
   154  func (g *generator) completed() bool {
   155  	progress := g.progressMarker()
   156  	return progress == nil
   157  }
   158  
   159  // progressMarker returns the current generation progress marker. It may slightly
   160  // lag behind the actual generation position, as the progress field is only updated
   161  // when checkAndFlush is called. The only effect is that some generated states
   162  // may be refused for serving.
   163  func (g *generator) progressMarker() []byte {
   164  	g.lock.RLock()
   165  	defer g.lock.RUnlock()
   166  
   167  	return g.progress
   168  }
   169  
   170  // splitMarker is an internal helper which splits the generation progress marker
   171  // into two parts.
   172  func splitMarker(marker []byte) ([]byte, []byte) {
   173  	var accMarker []byte
   174  	if len(marker) > 0 {
   175  		accMarker = marker[:common.HashLength]
   176  	}
   177  	return accMarker, marker
   178  }
   179  
   180  // generateSnapshot regenerates a brand-new snapshot based on an existing state
   181  // database and head block asynchronously. The snapshot is returned immediately
   182  // and generation is continued in the background until done.
   183  func generateSnapshot(triedb *Database, root common.Hash, noBuild bool) *diskLayer {
   184  	// Create a new disk layer with an initialized state marker at zero
   185  	var (
   186  		stats     = &generatorStats{start: time.Now()}
   187  		genMarker = []byte{} // Initialized but empty!
   188  	)
   189  	dl := newDiskLayer(root, 0, triedb, nil, nil, newBuffer(triedb.config.WriteBufferSize, nil, nil, 0), nil)
   190  	dl.setGenerator(newGenerator(triedb.diskdb, noBuild, genMarker, stats))
   191  
   192  	if !noBuild {
   193  		dl.generator.run(root)
   194  		log.Info("Started snapshot generation", "root", root)
   195  	}
   196  	return dl
   197  }
   198  
   199  // journalProgress persists the generator stats into the database to resume later.
   200  func journalProgress(db ethdb.KeyValueWriter, marker []byte, stats *generatorStats) {
   201  	// Write out the generator marker. Note it's a standalone disk layer generator
   202  	// which is not mixed with journal. It's ok if the generator is persisted while
   203  	// journal is not.
   204  	entry := journalGenerator{
   205  		Done:   marker == nil,
   206  		Marker: marker,
   207  	}
   208  	if stats != nil {
   209  		entry.Accounts = stats.accounts
   210  		entry.Slots = stats.slots
   211  		entry.Storage = uint64(stats.storage)
   212  	}
   213  	blob, err := rlp.EncodeToBytes(entry)
   214  	if err != nil {
   215  		panic(err) // Cannot happen, here to catch dev errors
   216  	}
   217  	var logstr string
   218  	switch {
   219  	case marker == nil:
   220  		logstr = "done"
   221  	case bytes.Equal(marker, []byte{}):
   222  		logstr = "empty"
   223  	case len(marker) == common.HashLength:
   224  		logstr = fmt.Sprintf("%#x", marker)
   225  	default:
   226  		logstr = fmt.Sprintf("%#x:%#x", marker[:common.HashLength], marker[common.HashLength:])
   227  	}
   228  	log.Debug("Journalled generator progress", "progress", logstr)
   229  	rawdb.WriteSnapshotGenerator(db, blob)
   230  }
   231  
   232  // proofResult contains the output of range proving which can be used
   233  // for further processing regardless if it is successful or not.
   234  type proofResult struct {
   235  	keys     [][]byte   // The key set of all elements being iterated, even proving is failed
   236  	vals     [][]byte   // The val set of all elements being iterated, even proving is failed
   237  	diskMore bool       // Set when the database has extra snapshot states since last iteration
   238  	trieMore bool       // Set when the trie has extra snapshot states(only meaningful for successful proving)
   239  	proofErr error      // Indicator whether the given state range is valid or not
   240  	tr       *trie.Trie // The trie, in case the trie was resolved by the prover (may be nil)
   241  }
   242  
   243  // valid returns the indicator that range proof is successful or not.
   244  func (result *proofResult) valid() bool {
   245  	return result.proofErr == nil
   246  }
   247  
   248  // last returns the last verified element key regardless of whether the range proof is
   249  // successful or not. Nil is returned if nothing involved in the proving.
   250  func (result *proofResult) last() []byte {
   251  	var last []byte
   252  	if len(result.keys) > 0 {
   253  		last = result.keys[len(result.keys)-1]
   254  	}
   255  	return last
   256  }
   257  
   258  // forEach iterates all the visited elements and applies the given callback on them.
   259  // The iteration is aborted if the callback returns non-nil error.
   260  func (result *proofResult) forEach(callback func(key []byte, val []byte) error) error {
   261  	for i := 0; i < len(result.keys); i++ {
   262  		key, val := result.keys[i], result.vals[i]
   263  		if err := callback(key, val); err != nil {
   264  			return err
   265  		}
   266  	}
   267  	return nil
   268  }
   269  
   270  // proveRange proves the snapshot segment with particular prefix is "valid".
   271  // The iteration start point will be assigned if the iterator is restored from
   272  // the last interruption. Max will be assigned in order to limit the maximum
   273  // amount of data involved in each iteration.
   274  //
   275  // The proof result will be returned if the range proving is finished, otherwise
   276  // the error will be returned to abort the entire procedure.
   277  func (g *generator) proveRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, valueConvertFn func([]byte) ([]byte, error)) (*proofResult, error) {
   278  	var (
   279  		keys     [][]byte
   280  		vals     [][]byte
   281  		proof    = rawdb.NewMemoryDatabase()
   282  		diskMore = false
   283  		iter     = ctx.iterator(kind)
   284  		start    = time.Now()
   285  		min      = append(prefix, origin...)
   286  	)
   287  	for iter.Next() {
   288  		// Ensure the iterated item is always equal or larger than the given origin.
   289  		key := iter.Key()
   290  		if bytes.Compare(key, min) < 0 {
   291  			return nil, errors.New("invalid iteration position")
   292  		}
   293  		// Ensure the iterated item still fall in the specified prefix. If
   294  		// not which means the items in the specified area are all visited.
   295  		// Move the iterator a step back since we iterate one extra element
   296  		// out.
   297  		if !bytes.Equal(key[:len(prefix)], prefix) {
   298  			iter.Hold()
   299  			break
   300  		}
   301  		// Break if we've reached the max size, and signal that we're not
   302  		// done yet. Move the iterator a step back since we iterate one
   303  		// extra element out.
   304  		if len(keys) == max {
   305  			iter.Hold()
   306  			diskMore = true
   307  			break
   308  		}
   309  		keys = append(keys, common.CopyBytes(key[len(prefix):]))
   310  
   311  		if valueConvertFn == nil {
   312  			vals = append(vals, common.CopyBytes(iter.Value()))
   313  		} else {
   314  			val, err := valueConvertFn(iter.Value())
   315  			if err != nil {
   316  				// Special case, the state data is corrupted (invalid slim-format account),
   317  				// don't abort the entire procedure directly. Instead, let the fallback
   318  				// generation to heal the invalid data.
   319  				//
   320  				// Here append the original value to ensure that the number of key and
   321  				// value are aligned.
   322  				vals = append(vals, common.CopyBytes(iter.Value()))
   323  				log.Error("Failed to convert account state data", "err", err)
   324  			} else {
   325  				vals = append(vals, val)
   326  			}
   327  		}
   328  	}
   329  	// Update metrics for database iteration and merkle proving
   330  	if kind == snapStorage {
   331  		storageSnapReadCounter.Inc(time.Since(start).Nanoseconds())
   332  	} else {
   333  		accountSnapReadCounter.Inc(time.Since(start).Nanoseconds())
   334  	}
   335  	defer func(start time.Time) {
   336  		if kind == snapStorage {
   337  			storageProveCounter.Inc(time.Since(start).Nanoseconds())
   338  		} else {
   339  			accountProveCounter.Inc(time.Since(start).Nanoseconds())
   340  		}
   341  	}(time.Now())
   342  
   343  	// The snap state is exhausted, pass the entire key/val set for verification
   344  	root := trieId.Root
   345  	if origin == nil && !diskMore {
   346  		stackTr := trie.NewStackTrie(nil)
   347  		for i, key := range keys {
   348  			if err := stackTr.Update(key, vals[i]); err != nil {
   349  				return nil, err
   350  			}
   351  		}
   352  		if gotRoot := stackTr.Hash(); gotRoot != root {
   353  			return &proofResult{
   354  				keys:     keys,
   355  				vals:     vals,
   356  				proofErr: fmt.Errorf("wrong root: have %#x want %#x", gotRoot, root),
   357  			}, nil
   358  		}
   359  		return &proofResult{keys: keys, vals: vals}, nil
   360  	}
   361  	// Snap state is chunked, generate edge proofs for verification.
   362  	tr, err := trie.New(trieId, &diskStore{db: g.db})
   363  	if err != nil {
   364  		log.Info("Trie missing, snapshotting paused", "state", ctx.root, "kind", kind, "root", trieId.Root)
   365  		return nil, errMissingTrie
   366  	}
   367  	// Generate the Merkle proofs for the first and last element
   368  	if origin == nil {
   369  		origin = common.Hash{}.Bytes()
   370  	}
   371  	if err := tr.Prove(origin, proof); err != nil {
   372  		log.Debug("Failed to prove range", "kind", kind, "origin", origin, "err", err)
   373  		return &proofResult{
   374  			keys:     keys,
   375  			vals:     vals,
   376  			diskMore: diskMore,
   377  			proofErr: err,
   378  			tr:       tr,
   379  		}, nil
   380  	}
   381  	if len(keys) > 0 {
   382  		if err := tr.Prove(keys[len(keys)-1], proof); err != nil {
   383  			log.Debug("Failed to prove range", "kind", kind, "last", keys[len(keys)-1], "err", err)
   384  			return &proofResult{
   385  				keys:     keys,
   386  				vals:     vals,
   387  				diskMore: diskMore,
   388  				proofErr: err,
   389  				tr:       tr,
   390  			}, nil
   391  		}
   392  	}
   393  	// Verify the snapshot segment with range prover, ensure that all flat states
   394  	// in this range correspond to merkle trie.
   395  	cont, err := trie.VerifyRangeProof(root, origin, keys, vals, proof)
   396  	return &proofResult{
   397  			keys:     keys,
   398  			vals:     vals,
   399  			diskMore: diskMore,
   400  			trieMore: cont,
   401  			proofErr: err,
   402  			tr:       tr},
   403  		nil
   404  }
   405  
   406  // onStateCallback is a function that is called by generateRange, when processing a range of
   407  // accounts or storage slots. For each element, the callback is invoked.
   408  //
   409  // - If 'delete' is true, then this element (and potential slots) needs to be deleted from the snapshot.
   410  // - If 'write' is true, then this element needs to be updated with the 'val'.
   411  // - If 'write' is false, then this element is already correct, and needs no update.
   412  // The 'val' is the canonical encoding of the value (not the slim format for accounts)
   413  //
   414  // However, for accounts, the storage trie of the account needs to be checked. Also,
   415  // dangling storages(storage exists but the corresponding account is missing) need to
   416  // be cleaned up.
   417  type onStateCallback func(key []byte, val []byte, write bool, delete bool) error
   418  
   419  // generateRange generates the state segment with particular prefix. Generation can
   420  // either verify the correctness of existing state through range-proof and skip
   421  // generation, or iterate trie to regenerate state on demand.
   422  func (g *generator) generateRange(ctx *generatorContext, trieId *trie.ID, prefix []byte, kind string, origin []byte, max int, onState onStateCallback, valueConvertFn func([]byte) ([]byte, error)) (bool, []byte, error) {
   423  	// Use range prover to check the validity of the flat state in the range
   424  	result, err := g.proveRange(ctx, trieId, prefix, kind, origin, max, valueConvertFn)
   425  	if err != nil {
   426  		return false, nil, err
   427  	}
   428  	last := result.last()
   429  
   430  	// Construct contextual logger
   431  	logCtx := []interface{}{"kind", kind, "prefix", hexutil.Encode(prefix)}
   432  	if len(origin) > 0 {
   433  		logCtx = append(logCtx, "origin", hexutil.Encode(origin))
   434  	}
   435  	logger := log.New(logCtx...)
   436  
   437  	// The range prover says the range is correct, skip trie iteration
   438  	if result.valid() {
   439  		successfulRangeProofMeter.Mark(1)
   440  		logger.Trace("Proved state range", "last", hexutil.Encode(last))
   441  
   442  		// The verification is passed, process each state with the given
   443  		// callback function. If this state represents a contract, the
   444  		// corresponding storage check will be performed in the callback
   445  		if err := result.forEach(func(key []byte, val []byte) error { return onState(key, val, false, false) }); err != nil {
   446  			return false, nil, err
   447  		}
   448  		// Only abort the iteration when both database and trie are exhausted
   449  		return !result.diskMore && !result.trieMore, last, nil
   450  	}
   451  	logger.Trace("Detected outdated state range", "last", hexutil.Encode(last), "err", result.proofErr)
   452  	failedRangeProofMeter.Mark(1)
   453  
   454  	// Special case, the entire trie is missing. In the original trie scheme,
   455  	// all the duplicated subtries will be filtered out (only one copy of data
   456  	// will be stored). While in the snapshot model, all the storage tries
   457  	// belong to different contracts will be kept even they are duplicated.
   458  	// Track it to a certain extent remove the noise data used for statistics.
   459  	if origin == nil && last == nil {
   460  		meter := missallAccountMeter
   461  		if kind == snapStorage {
   462  			meter = missallStorageMeter
   463  		}
   464  		meter.Mark(1)
   465  	}
   466  	// We use the snap data to build up a cache which can be used by the
   467  	// main account trie as a primary lookup when resolving hashes
   468  	var resolver trie.NodeResolver
   469  	if len(result.keys) > 0 {
   470  		tr := trie.NewEmpty(nil)
   471  		for i, key := range result.keys {
   472  			tr.Update(key, result.vals[i])
   473  		}
   474  		_, nodes := tr.Commit(false)
   475  		hashSet := nodes.HashSet()
   476  		resolver = func(owner common.Hash, path []byte, hash common.Hash) []byte {
   477  			return hashSet[hash]
   478  		}
   479  	}
   480  	// Construct the trie for state iteration, reuse the trie
   481  	// if it's already opened with some nodes resolved.
   482  	tr := result.tr
   483  	if tr == nil {
   484  		tr, err = trie.New(trieId, &diskStore{db: g.db})
   485  		if err != nil {
   486  			log.Info("Trie missing, snapshotting paused", "state", ctx.root, "kind", kind, "root", trieId.Root)
   487  			return false, nil, errMissingTrie
   488  		}
   489  	}
   490  	var (
   491  		trieMore       bool
   492  		kvkeys, kvvals = result.keys, result.vals
   493  
   494  		// counters
   495  		count     = 0 // number of states delivered by iterator
   496  		created   = 0 // states created from the trie
   497  		updated   = 0 // states updated from the trie
   498  		deleted   = 0 // states not in trie, but were in snapshot
   499  		untouched = 0 // states already correct
   500  
   501  		// timers
   502  		start    = time.Now()
   503  		internal time.Duration
   504  	)
   505  	nodeIt, err := tr.NodeIterator(origin)
   506  	if err != nil {
   507  		return false, nil, err
   508  	}
   509  	nodeIt.AddResolver(resolver)
   510  	iter := trie.NewIterator(nodeIt)
   511  
   512  	for iter.Next() {
   513  		if last != nil && bytes.Compare(iter.Key, last) > 0 {
   514  			trieMore = true
   515  			break
   516  		}
   517  		count++
   518  		write := true
   519  		created++
   520  		for len(kvkeys) > 0 {
   521  			if cmp := bytes.Compare(kvkeys[0], iter.Key); cmp < 0 {
   522  				// delete the key
   523  				istart := time.Now()
   524  				if err := onState(kvkeys[0], nil, false, true); err != nil {
   525  					return false, nil, err
   526  				}
   527  				kvkeys = kvkeys[1:]
   528  				kvvals = kvvals[1:]
   529  				deleted++
   530  				internal += time.Since(istart)
   531  				continue
   532  			} else if cmp == 0 {
   533  				// the snapshot key can be overwritten
   534  				created--
   535  				if write = !bytes.Equal(kvvals[0], iter.Value); write {
   536  					updated++
   537  				} else {
   538  					untouched++
   539  				}
   540  				kvkeys = kvkeys[1:]
   541  				kvvals = kvvals[1:]
   542  			}
   543  			break
   544  		}
   545  		istart := time.Now()
   546  		if err := onState(iter.Key, iter.Value, write, false); err != nil {
   547  			return false, nil, err
   548  		}
   549  		internal += time.Since(istart)
   550  	}
   551  	if iter.Err != nil {
   552  		// Trie errors should never happen. Still, in case of a bug, expose the
   553  		// error here, as the outer code will presume errors are interrupts, not
   554  		// some deeper issues.
   555  		log.Error("State snapshotter failed to iterate trie", "err", iter.Err)
   556  		return false, nil, iter.Err
   557  	}
   558  	// Delete all stale snapshot states remaining
   559  	istart := time.Now()
   560  	for _, key := range kvkeys {
   561  		if err := onState(key, nil, false, true); err != nil {
   562  			return false, nil, err
   563  		}
   564  		deleted += 1
   565  	}
   566  	internal += time.Since(istart)
   567  
   568  	// Update metrics for counting trie iteration
   569  	if kind == snapStorage {
   570  		storageTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds())
   571  	} else {
   572  		accountTrieReadCounter.Inc((time.Since(start) - internal).Nanoseconds())
   573  	}
   574  	logger.Trace("Regenerated state range", "root", trieId.Root, "last", hexutil.Encode(last),
   575  		"count", count, "created", created, "updated", updated, "untouched", untouched, "deleted", deleted)
   576  
   577  	// If there are either more trie items, or there are more snap items
   578  	// (in the next segment), then we need to keep working
   579  	return !trieMore && !result.diskMore, last, nil
   580  }
   581  
   582  // checkAndFlush checks if an interruption signal is received or the
   583  // batch size has exceeded the allowance.
   584  func (g *generator) checkAndFlush(ctx *generatorContext, current []byte) error {
   585  	var abort chan struct{}
   586  	select {
   587  	case abort = <-g.abort:
   588  	default:
   589  	}
   590  	if ctx.batch.ValueSize() > ethdb.IdealBatchSize || abort != nil {
   591  		if bytes.Compare(current, g.progress) < 0 {
   592  			log.Error("Snapshot generator went backwards", "current", fmt.Sprintf("%x", current), "genMarker", fmt.Sprintf("%x", g.progress))
   593  		}
   594  		// Persist the progress marker regardless of whether the batch is empty or not.
   595  		// It may happen that all the flat states in the database are correct, so the
   596  		// generator indeed makes progress even if there is nothing to commit.
   597  		journalProgress(ctx.batch, current, g.stats)
   598  
   599  		// Flush out the database writes atomically
   600  		if err := ctx.batch.Write(); err != nil {
   601  			return err
   602  		}
   603  		ctx.batch.Reset()
   604  
   605  		// Update the generation progress marker
   606  		g.lock.Lock()
   607  		g.progress = current
   608  		g.lock.Unlock()
   609  
   610  		// Abort the generation if it's required
   611  		if abort != nil {
   612  			g.stats.log("Aborting snapshot generation", ctx.root, g.progress)
   613  			return newAbortErr(abort) // bubble up an error for interruption
   614  		}
   615  		// Don't hold the iterators too long, release them to let compactor works
   616  		ctx.reopenIterator(snapAccount)
   617  		ctx.reopenIterator(snapStorage)
   618  	}
   619  	if time.Since(ctx.logged) > 8*time.Second {
   620  		g.stats.log("Generating snapshot", ctx.root, g.progress)
   621  		ctx.logged = time.Now()
   622  	}
   623  	return nil
   624  }
   625  
   626  // generateStorages generates the missing storage slots of the specific contract.
   627  // It's supposed to restart the generation from the given origin position.
   628  func (g *generator) generateStorages(ctx *generatorContext, account common.Hash, storageRoot common.Hash, storeMarker []byte) error {
   629  	onStorage := func(key []byte, val []byte, write bool, delete bool) error {
   630  		defer func(start time.Time) {
   631  			storageWriteCounter.Inc(time.Since(start).Nanoseconds())
   632  		}(time.Now())
   633  
   634  		if delete {
   635  			rawdb.DeleteStorageSnapshot(ctx.batch, account, common.BytesToHash(key))
   636  			wipedStorageMeter.Mark(1)
   637  			return nil
   638  		}
   639  		if write {
   640  			rawdb.WriteStorageSnapshot(ctx.batch, account, common.BytesToHash(key), val)
   641  			generatedStorageMeter.Mark(1)
   642  		} else {
   643  			recoveredStorageMeter.Mark(1)
   644  		}
   645  		g.stats.storage += common.StorageSize(1 + 2*common.HashLength + len(val))
   646  		g.stats.slots++
   647  
   648  		// If we've exceeded our batch allowance or termination was requested, flush to disk
   649  		if err := g.checkAndFlush(ctx, append(account[:], key...)); err != nil {
   650  			return err
   651  		}
   652  		return nil
   653  	}
   654  	// Loop for re-generating the missing storage slots.
   655  	var origin = common.CopyBytes(storeMarker)
   656  	for {
   657  		id := trie.StorageTrieID(ctx.root, account, storageRoot)
   658  		exhausted, last, err := g.generateRange(ctx, id, append(rawdb.SnapshotStoragePrefix, account.Bytes()...), snapStorage, origin, storageCheckRange, onStorage, nil)
   659  		if err != nil {
   660  			return err // The procedure it aborted, either by external signal or internal error.
   661  		}
   662  		// Abort the procedure if the entire contract storage is generated
   663  		if exhausted {
   664  			break
   665  		}
   666  		if origin = increaseKey(last); origin == nil {
   667  			break // special case, the last is 0xffffffff...fff
   668  		}
   669  	}
   670  	return nil
   671  }
   672  
   673  // generateAccounts generates the missing snapshot accounts as well as their
   674  // storage slots in the main trie. It's supposed to restart the generation
   675  // from the given origin position.
   676  func (g *generator) generateAccounts(ctx *generatorContext, accMarker []byte) error {
   677  	onAccount := func(key []byte, val []byte, write bool, delete bool) error {
   678  		// Make sure to clear all dangling storages before this account
   679  		account := common.BytesToHash(key)
   680  		g.stats.dangling += ctx.removeStorageBefore(account)
   681  
   682  		start := time.Now()
   683  		if delete {
   684  			rawdb.DeleteAccountSnapshot(ctx.batch, account)
   685  			wipedAccountMeter.Mark(1)
   686  			accountWriteCounter.Inc(time.Since(start).Nanoseconds())
   687  
   688  			ctx.removeStorageAt(account)
   689  			return nil
   690  		}
   691  		// Retrieve the current account and flatten it into the internal format
   692  		var acc types.StateAccount
   693  		if err := rlp.DecodeBytes(val, &acc); err != nil {
   694  			log.Crit("Invalid account encountered during snapshot creation", "err", err)
   695  		}
   696  		// If the account is not yet in-progress, write it out
   697  		if accMarker == nil || !bytes.Equal(account[:], accMarker) {
   698  			dataLen := len(val) // Approximate size, saves us a round of RLP-encoding
   699  			if !write {
   700  				if bytes.Equal(acc.CodeHash, types.EmptyCodeHash[:]) {
   701  					dataLen -= 32
   702  				}
   703  				if acc.Root == types.EmptyRootHash {
   704  					dataLen -= 32
   705  				}
   706  				recoveredAccountMeter.Mark(1)
   707  			} else {
   708  				data := types.SlimAccountRLP(acc)
   709  				dataLen = len(data)
   710  				rawdb.WriteAccountSnapshot(ctx.batch, account, data)
   711  				generatedAccountMeter.Mark(1)
   712  			}
   713  			g.stats.storage += common.StorageSize(1 + common.HashLength + dataLen)
   714  			g.stats.accounts++
   715  		}
   716  		// If the snap generation goes here after interrupted, genMarker may go backward
   717  		// when last genMarker is consisted of accountHash and storageHash
   718  		marker := account[:]
   719  		if accMarker != nil && bytes.Equal(marker, accMarker) && len(g.progress) > common.HashLength {
   720  			marker = g.progress
   721  		}
   722  		// If we've exceeded our batch allowance or termination was requested, flush to disk
   723  		if err := g.checkAndFlush(ctx, marker); err != nil {
   724  			return err
   725  		}
   726  		accountWriteCounter.Inc(time.Since(start).Nanoseconds()) // let's count flush time as well
   727  
   728  		// If the iterated account is the contract, create a further loop to
   729  		// verify or regenerate the contract storage.
   730  		if acc.Root == types.EmptyRootHash {
   731  			ctx.removeStorageAt(account)
   732  		} else {
   733  			var storeMarker []byte
   734  			if accMarker != nil && bytes.Equal(account[:], accMarker) && len(g.progress) > common.HashLength {
   735  				storeMarker = g.progress[common.HashLength:]
   736  			}
   737  			if err := g.generateStorages(ctx, account, acc.Root, storeMarker); err != nil {
   738  				return err
   739  			}
   740  		}
   741  		// Some account processed, unmark the marker
   742  		accMarker = nil
   743  		return nil
   744  	}
   745  	origin := common.CopyBytes(accMarker)
   746  	for {
   747  		id := trie.StateTrieID(ctx.root)
   748  		exhausted, last, err := g.generateRange(ctx, id, rawdb.SnapshotAccountPrefix, snapAccount, origin, accountCheckRange, onAccount, types.FullAccountRLP)
   749  		if err != nil {
   750  			return err // The procedure it aborted, either by external signal or internal error.
   751  		}
   752  		origin = increaseKey(last)
   753  
   754  		// Last step, cleanup the storages after the last account.
   755  		// All the left storages should be treated as dangling.
   756  		if origin == nil || exhausted {
   757  			g.stats.dangling += ctx.removeRemainingStorage()
   758  			break
   759  		}
   760  	}
   761  	return nil
   762  }
   763  
   764  // generate is a background thread that iterates over the state and storage tries,
   765  // constructing the state snapshot. All the arguments are purely for statistics
   766  // gathering and logging, since the method surfs the blocks as they arrive, often
   767  // being restarted.
   768  func (g *generator) generate(ctx *generatorContext) {
   769  	g.stats.log("Resuming snapshot generation", ctx.root, g.progress)
   770  	defer ctx.close()
   771  
   772  	// Persist the initial marker and state snapshot root if progress is none
   773  	if len(g.progress) == 0 {
   774  		batch := g.db.NewBatch()
   775  		rawdb.WriteSnapshotRoot(batch, ctx.root)
   776  		journalProgress(batch, g.progress, g.stats)
   777  		if err := batch.Write(); err != nil {
   778  			log.Crit("Failed to write initialized state marker", "err", err)
   779  		}
   780  	}
   781  	// Initialize the global generator context. The snapshot iterators are
   782  	// opened at the interrupted position because the assumption is held
   783  	// that all the snapshot data are generated correctly before the marker.
   784  	// Even if the snapshot data is updated during the interruption (before
   785  	// or at the marker), the assumption is still held.
   786  	// For the account or storage slot at the interruption, they will be
   787  	// processed twice by the generator(they are already processed in the
   788  	// last run) but it's fine.
   789  	var (
   790  		accMarker, _ = splitMarker(g.progress)
   791  		abort        chan struct{}
   792  	)
   793  	if err := g.generateAccounts(ctx, accMarker); err != nil {
   794  		// Extract the received interruption signal if exists
   795  		var aerr *abortErr
   796  		if errors.As(err, &aerr) {
   797  			abort = aerr.abort
   798  		}
   799  		// Aborted by internal error, wait the signal
   800  		if abort == nil {
   801  			abort = <-g.abort
   802  		}
   803  		close(abort)
   804  		return
   805  	}
   806  	// Snapshot fully generated, set the marker to nil.
   807  	// Note even there is nothing to commit, persist the
   808  	// generator anyway to mark the snapshot is complete.
   809  	journalProgress(ctx.batch, nil, g.stats)
   810  	if err := ctx.batch.Write(); err != nil {
   811  		log.Error("Failed to flush batch", "err", err)
   812  		abort = <-g.abort
   813  		close(abort)
   814  		return
   815  	}
   816  	ctx.batch.Reset()
   817  
   818  	log.Info("Generated snapshot", "accounts", g.stats.accounts, "slots", g.stats.slots,
   819  		"storage", g.stats.storage, "dangling", g.stats.dangling, "elapsed", common.PrettyDuration(time.Since(g.stats.start)))
   820  
   821  	// Update the generation progress marker
   822  	g.lock.Lock()
   823  	g.progress = nil
   824  	g.lock.Unlock()
   825  	close(g.done)
   826  
   827  	// Someone will be looking for us, wait it out
   828  	abort = <-g.abort
   829  	close(abort)
   830  }
   831  
   832  // increaseKey increase the input key by one bit. Return nil if the entire
   833  // addition operation overflows.
   834  func increaseKey(key []byte) []byte {
   835  	for i := len(key) - 1; i >= 0; i-- {
   836  		key[i]++
   837  		if key[i] != 0x0 {
   838  			return key
   839  		}
   840  	}
   841  	return nil
   842  }
   843  
   844  // abortErr wraps an interruption signal received to represent the
   845  // generation is aborted by external processes.
   846  type abortErr struct {
   847  	abort chan struct{}
   848  }
   849  
   850  func newAbortErr(abort chan struct{}) error {
   851  	return &abortErr{abort: abort}
   852  }
   853  
   854  func (err *abortErr) Error() string {
   855  	return "aborted"
   856  }