github.com/MetalBlockchain/subnet-evm@v0.4.9/sync/statesync/trie_queue.go (about)

     1  // (c) 2021-2022, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  package statesync
     5  
     6  import (
     7  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
     8  	"github.com/MetalBlockchain/subnet-evm/ethdb"
     9  	"github.com/ethereum/go-ethereum/common"
    10  )
    11  
    12  // trieQueue persists storage trie roots with their associated
    13  // accounts when [RegisterStorageTrie] is called. These are
    14  // later returned from the [getNextTrie] method.
    15  type trieQueue struct {
    16  	db              ethdb.Database
    17  	nextStorageRoot []byte
    18  }
    19  
    20  func NewTrieQueue(db ethdb.Database) *trieQueue {
    21  	return &trieQueue{
    22  		db: db,
    23  	}
    24  }
    25  
    26  // clearIfRootDoesNotMatch clears progress and segment markers if
    27  // the persisted root does not match the root we are syncing to.
    28  func (t *trieQueue) clearIfRootDoesNotMatch(root common.Hash) error {
    29  	persistedRoot, err := rawdb.ReadSyncRoot(t.db)
    30  	if err != nil {
    31  		return err
    32  	}
    33  	if persistedRoot != (common.Hash{}) && persistedRoot != root {
    34  		// if not resuming, clear all progress markers
    35  		if err := rawdb.ClearAllSyncStorageTries(t.db); err != nil {
    36  			return err
    37  		}
    38  		if err := rawdb.ClearAllSyncSegments(t.db); err != nil {
    39  			return err
    40  		}
    41  	}
    42  
    43  	return rawdb.WriteSyncRoot(t.db, root)
    44  }
    45  
    46  // RegisterStorageTrie is called by the main trie's leaf handling callbacks
    47  // It adds a key built as [syncProgressPrefix+root+account] to the database.
    48  // getNextTrie iterates this prefix to find storage tries and accounts
    49  // associated with them.
    50  func (t *trieQueue) RegisterStorageTrie(root common.Hash, account common.Hash) error {
    51  	return rawdb.WriteSyncStorageTrie(t.db, root, account)
    52  }
    53  
    54  // StorageTrieDone is called when a storage trie has completed syncing.
    55  // This removes any progress markers for the trie.
    56  func (t *trieQueue) StorageTrieDone(root common.Hash) error {
    57  	return rawdb.ClearSyncStorageTrie(t.db, root)
    58  }
    59  
    60  // getNextTrie returns the next storage trie to sync, along with a slice
    61  // of accounts that point to the returned storage trie.
    62  // Returns true if there are more storage tries to sync and false otherwise.
    63  // Note: if a non-nil root is returned, getNextTrie guarantees that there will be at least
    64  // one account hash in the returned slice.
    65  func (t *trieQueue) getNextTrie() (common.Hash, []common.Hash, bool, error) {
    66  	it := rawdb.NewSyncStorageTriesIterator(t.db, t.nextStorageRoot)
    67  	defer it.Release()
    68  
    69  	var (
    70  		root     common.Hash
    71  		accounts []common.Hash
    72  		more     bool
    73  	)
    74  
    75  	// Iterate over the keys to find the next storage trie root and all of the account hashes that contain the same storage root.
    76  	for it.Next() {
    77  		// Unpack the state root and account hash from the current key
    78  		nextRoot, nextAccount := rawdb.UnpackSyncStorageTrieKey(it.Key())
    79  		// Set the root for the first pass
    80  		if root == (common.Hash{}) {
    81  			root = nextRoot
    82  		}
    83  		// If the next root is different than the originally set root, then we've iterated over all of the account hashes that
    84  		// have the same storage trie root. Set more to be true, since there is at least one more storage trie.
    85  		if root != nextRoot {
    86  			t.nextStorageRoot = nextRoot[:]
    87  			more = true
    88  			break
    89  		}
    90  		// If we found another account with the same root, add the accountHash.
    91  		accounts = append(accounts, nextAccount)
    92  	}
    93  
    94  	return root, accounts, more, it.Error()
    95  }
    96  
    97  func (t *trieQueue) countTries() (int, error) {
    98  	it := rawdb.NewSyncStorageTriesIterator(t.db, nil)
    99  	defer it.Release()
   100  
   101  	var (
   102  		root  common.Hash
   103  		tries int
   104  	)
   105  
   106  	for it.Next() {
   107  		nextRoot, _ := rawdb.UnpackSyncStorageTrieKey(it.Key())
   108  		if root == (common.Hash{}) || root != nextRoot {
   109  			root = nextRoot
   110  			tries++
   111  		}
   112  	}
   113  
   114  	return tries, it.Error()
   115  }