github.com/tirogen/go-ethereum@v1.10.12-0.20221226051715-250cfede41b6/core/state/snapshot/utils.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 snapshot 18 19 import ( 20 "bytes" 21 "fmt" 22 "time" 23 24 "github.com/tirogen/go-ethereum/common" 25 "github.com/tirogen/go-ethereum/core/rawdb" 26 "github.com/tirogen/go-ethereum/ethdb" 27 "github.com/tirogen/go-ethereum/log" 28 "github.com/tirogen/go-ethereum/rlp" 29 ) 30 31 // CheckDanglingStorage iterates the snap storage data, and verifies that all 32 // storage also has corresponding account data. 33 func CheckDanglingStorage(chaindb ethdb.KeyValueStore) error { 34 if err := checkDanglingDiskStorage(chaindb); err != nil { 35 log.Error("Database check error", "err", err) 36 } 37 return checkDanglingMemStorage(chaindb) 38 } 39 40 // checkDanglingDiskStorage checks if there is any 'dangling' storage data in the 41 // disk-backed snapshot layer. 42 func checkDanglingDiskStorage(chaindb ethdb.KeyValueStore) error { 43 var ( 44 lastReport = time.Now() 45 start = time.Now() 46 lastKey []byte 47 it = rawdb.NewKeyLengthIterator(chaindb.NewIterator(rawdb.SnapshotStoragePrefix, nil), 1+2*common.HashLength) 48 ) 49 log.Info("Checking dangling snapshot disk storage") 50 51 defer it.Release() 52 for it.Next() { 53 k := it.Key() 54 accKey := k[1:33] 55 if bytes.Equal(accKey, lastKey) { 56 // No need to look up for every slot 57 continue 58 } 59 lastKey = common.CopyBytes(accKey) 60 if time.Since(lastReport) > time.Second*8 { 61 log.Info("Iterating snap storage", "at", fmt.Sprintf("%#x", accKey), "elapsed", common.PrettyDuration(time.Since(start))) 62 lastReport = time.Now() 63 } 64 if data := rawdb.ReadAccountSnapshot(chaindb, common.BytesToHash(accKey)); len(data) == 0 { 65 log.Warn("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accKey), "storagekey", fmt.Sprintf("%#x", k)) 66 return fmt.Errorf("dangling snapshot storage account %#x", accKey) 67 } 68 } 69 log.Info("Verified the snapshot disk storage", "time", common.PrettyDuration(time.Since(start)), "err", it.Error()) 70 return nil 71 } 72 73 // checkDanglingMemStorage checks if there is any 'dangling' storage in the journalled 74 // snapshot difflayers. 75 func checkDanglingMemStorage(db ethdb.KeyValueStore) error { 76 start := time.Now() 77 log.Info("Checking dangling journalled storage") 78 err := iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { 79 for accHash := range storage { 80 if _, ok := accounts[accHash]; !ok { 81 log.Error("Dangling storage - missing account", "account", fmt.Sprintf("%#x", accHash), "root", root) 82 } 83 } 84 return nil 85 }) 86 if err != nil { 87 log.Info("Failed to resolve snapshot journal", "err", err) 88 return err 89 } 90 log.Info("Verified the snapshot journalled storage", "time", common.PrettyDuration(time.Since(start))) 91 return nil 92 } 93 94 // CheckJournalAccount shows information about an account, from the disk layer and 95 // up through the diff layers. 96 func CheckJournalAccount(db ethdb.KeyValueStore, hash common.Hash) error { 97 // Look up the disk layer first 98 baseRoot := rawdb.ReadSnapshotRoot(db) 99 fmt.Printf("Disklayer: Root: %x\n", baseRoot) 100 if data := rawdb.ReadAccountSnapshot(db, hash); data != nil { 101 account := new(Account) 102 if err := rlp.DecodeBytes(data, account); err != nil { 103 panic(err) 104 } 105 fmt.Printf("\taccount.nonce: %d\n", account.Nonce) 106 fmt.Printf("\taccount.balance: %x\n", account.Balance) 107 fmt.Printf("\taccount.root: %x\n", account.Root) 108 fmt.Printf("\taccount.codehash: %x\n", account.CodeHash) 109 } 110 // Check storage 111 { 112 it := rawdb.NewKeyLengthIterator(db.NewIterator(append(rawdb.SnapshotStoragePrefix, hash.Bytes()...), nil), 1+2*common.HashLength) 113 fmt.Printf("\tStorage:\n") 114 for it.Next() { 115 slot := it.Key()[33:] 116 fmt.Printf("\t\t%x: %x\n", slot, it.Value()) 117 } 118 it.Release() 119 } 120 var depth = 0 121 122 return iterateJournal(db, func(pRoot, root common.Hash, destructs map[common.Hash]struct{}, accounts map[common.Hash][]byte, storage map[common.Hash]map[common.Hash][]byte) error { 123 _, a := accounts[hash] 124 _, b := destructs[hash] 125 _, c := storage[hash] 126 depth++ 127 if !a && !b && !c { 128 return nil 129 } 130 fmt.Printf("Disklayer+%d: Root: %x, parent %x\n", depth, root, pRoot) 131 if data, ok := accounts[hash]; ok { 132 account := new(Account) 133 if err := rlp.DecodeBytes(data, account); err != nil { 134 panic(err) 135 } 136 fmt.Printf("\taccount.nonce: %d\n", account.Nonce) 137 fmt.Printf("\taccount.balance: %x\n", account.Balance) 138 fmt.Printf("\taccount.root: %x\n", account.Root) 139 fmt.Printf("\taccount.codehash: %x\n", account.CodeHash) 140 } 141 if _, ok := destructs[hash]; ok { 142 fmt.Printf("\t Destructed!") 143 } 144 if data, ok := storage[hash]; ok { 145 fmt.Printf("\tStorage\n") 146 for k, v := range data { 147 fmt.Printf("\t\t%x: %x\n", k, v) 148 } 149 } 150 return nil 151 }) 152 }