github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/evmstore/utils.go (about) 1 package evmstore 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "io" 8 9 "github.com/unicornultrafoundation/go-helios/u2udb" 10 "github.com/unicornultrafoundation/go-helios/u2udb/table" 11 "github.com/unicornultrafoundation/go-helios/utils/simplewlru" 12 "github.com/unicornultrafoundation/go-u2u/common" 13 "github.com/unicornultrafoundation/go-u2u/core/rawdb" 14 "github.com/unicornultrafoundation/go-u2u/core/state" 15 "github.com/unicornultrafoundation/go-u2u/core/types" 16 "github.com/unicornultrafoundation/go-u2u/crypto" 17 "github.com/unicornultrafoundation/go-u2u/log" 18 "github.com/unicornultrafoundation/go-u2u/rlp" 19 20 "github.com/unicornultrafoundation/go-u2u/utils/iodb" 21 ) 22 23 var ( 24 // EmptyCode is the known hash of the empty EVM bytecode. 25 EmptyCode = crypto.Keccak256(nil) 26 27 emptyCodeHash = common.BytesToHash(EmptyCode) 28 emptyHash = common.Hash{} 29 ) 30 31 func (s *Store) CheckEvm(forEachState func(func(root common.Hash) (found bool, err error)), onlyRoots bool) error { 32 log.Info("Checking every node hash") 33 nodeIt := s.table.Evm.NewIterator(nil, nil) 34 defer nodeIt.Release() 35 for nodeIt.Next() { 36 if len(nodeIt.Key()) != 32 { 37 continue 38 } 39 calcHash := crypto.Keccak256(nodeIt.Value()) 40 if !bytes.Equal(nodeIt.Key(), calcHash) { 41 log.Crit("Malformed node record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(nodeIt.Key())) 42 } 43 } 44 45 log.Info("Checking every code hash") 46 codeIt := table.New(s.table.Evm, []byte("c")).NewIterator(nil, nil) 47 defer codeIt.Release() 48 for codeIt.Next() { 49 if len(codeIt.Key()) != 32 { 50 continue 51 } 52 calcHash := crypto.Keccak256(codeIt.Value()) 53 if !bytes.Equal(codeIt.Key(), calcHash) { 54 log.Crit("Malformed code record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(codeIt.Key())) 55 } 56 } 57 58 log.Info("Checking every preimage") 59 preimageIt := table.New(s.table.Evm, []byte("secure-key-")).NewIterator(nil, nil) 60 defer preimageIt.Release() 61 for preimageIt.Next() { 62 if len(preimageIt.Key()) != 32 { 63 continue 64 } 65 calcHash := crypto.Keccak256(preimageIt.Value()) 66 if !bytes.Equal(preimageIt.Key(), calcHash) { 67 log.Crit("Malformed preimage record", "exp", common.Bytes2Hex(calcHash), "got", common.Bytes2Hex(preimageIt.Key())) 68 } 69 } 70 71 if onlyRoots { 72 log.Info("Checking presence of every root") 73 } else { 74 log.Info("Checking presence of every node") 75 } 76 var ( 77 visitedHashes = make([]common.Hash, 0, 1000000) 78 visitedI = 0 79 checkedCache, _ = simplewlru.New(100000000, 100000000) 80 cached = func(h common.Hash) bool { 81 _, ok := checkedCache.Get(h) 82 return ok 83 } 84 ) 85 visited := func(h common.Hash, priority int) { 86 base := 100000 * priority 87 if visitedI%(1<<(len(visitedHashes)/base)) == 0 { 88 visitedHashes = append(visitedHashes, h) 89 } 90 visitedI++ 91 } 92 forEachState(func(root common.Hash) (found bool, err error) { 93 stateTrie, err := s.EvmState.OpenTrie(root) 94 found = stateTrie != nil && err == nil 95 if !found || onlyRoots { 96 return 97 } 98 99 // check existence of every code hash and root of every storage trie 100 stateIt := stateTrie.NodeIterator(nil) 101 for stateItSkip := false; stateIt.Next(!stateItSkip); { 102 stateItSkip = false 103 if stateIt.Hash() != emptyHash { 104 if cached(stateIt.Hash()) { 105 stateItSkip = true 106 continue 107 } 108 visited(stateIt.Hash(), 2) 109 } 110 111 if stateIt.Leaf() { 112 addrHash := common.BytesToHash(stateIt.LeafKey()) 113 114 var account state.Account 115 if err = rlp.Decode(bytes.NewReader(stateIt.LeafBlob()), &account); err != nil { 116 err = fmt.Errorf("Failed to decode accoun as %s addr: %s", addrHash.String(), err.Error()) 117 return 118 } 119 120 codeHash := common.BytesToHash(account.CodeHash) 121 if codeHash != emptyCodeHash && !cached(codeHash) { 122 code, _ := s.EvmState.ContractCode(addrHash, codeHash) 123 if code == nil { 124 err = fmt.Errorf("failed to get code %s at %s addr", codeHash.String(), addrHash.String()) 125 return 126 } 127 checkedCache.Add(codeHash, true, 1) 128 } 129 130 if account.Root != types.EmptyRootHash && !cached(account.Root) { 131 storageTrie, storageErr := s.EvmState.OpenStorageTrie(addrHash, account.Root) 132 if storageErr != nil { 133 err = fmt.Errorf("failed to open storage trie %s at %s addr: %s", account.Root.String(), addrHash.String(), storageErr.Error()) 134 return 135 } 136 storageIt := storageTrie.NodeIterator(nil) 137 for storageItSkip := false; storageIt.Next(!storageItSkip); { 138 storageItSkip = false 139 if storageIt.Hash() != emptyHash { 140 if cached(storageIt.Hash()) { 141 storageItSkip = true 142 continue 143 } 144 visited(storageIt.Hash(), 1) 145 } 146 } 147 if storageIt.Error() != nil { 148 err = fmt.Errorf("EVM storage trie %s at %s addr iteration error: %s", account.Root.String(), addrHash.String(), storageIt.Error()) 149 return 150 } 151 } 152 } 153 } 154 155 if stateIt.Error() != nil { 156 err = fmt.Errorf("EVM state trie %s iteration error: %s", root.String(), stateIt.Error()) 157 return 158 } 159 for _, h := range visitedHashes { 160 checkedCache.Add(h, true, 1) 161 } 162 visitedHashes = visitedHashes[:0] 163 164 return 165 }) 166 167 return nil 168 } 169 170 func (s *Store) ImportEvm(r io.Reader) error { 171 it := iodb.NewIterator(r) 172 defer it.Release() 173 batch := &restrictedEvmBatch{s.table.Evm.NewBatch()} 174 defer batch.Reset() 175 for it.Next() { 176 err := batch.Put(it.Key(), it.Value()) 177 if err != nil { 178 return err 179 } 180 if batch.ValueSize() > u2udb.IdealBatchSize { 181 err := batch.Write() 182 if err != nil { 183 return err 184 } 185 batch.Reset() 186 } 187 } 188 return batch.Write() 189 } 190 191 type restrictedEvmBatch struct { 192 u2udb.Batch 193 } 194 195 func IsMptKey(key []byte) bool { 196 return len(key) == common.HashLength || 197 (bytes.HasPrefix(key, rawdb.CodePrefix) && len(key) == len(rawdb.CodePrefix)+common.HashLength) 198 } 199 200 func IsPreimageKey(key []byte) bool { 201 preimagePrefix := []byte("secure-key-") 202 return bytes.HasPrefix(key, preimagePrefix) && len(key) == (len(preimagePrefix)+common.HashLength) 203 } 204 205 func (v *restrictedEvmBatch) Put(key []byte, value []byte) error { 206 if !IsMptKey(key) && !IsPreimageKey(key) { 207 return errors.New("not expected prefix for EVM history dump") 208 } 209 return v.Batch.Put(key, value) 210 }