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 }