github.com/theQRL/go-zond@v0.1.1/trie/triestate/state.go (about) 1 // Copyright 2023 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 triestate 18 19 import ( 20 "errors" 21 "fmt" 22 "sync" 23 24 "github.com/theQRL/go-zond/common" 25 "github.com/theQRL/go-zond/core/types" 26 "github.com/theQRL/go-zond/crypto" 27 "github.com/theQRL/go-zond/rlp" 28 "github.com/theQRL/go-zond/trie/trienode" 29 "golang.org/x/crypto/sha3" 30 ) 31 32 // Trie is an Ethereum state trie, can be implemented by Ethereum Merkle Patricia 33 // tree or Verkle tree. 34 type Trie interface { 35 // Get returns the value for key stored in the trie. 36 Get(key []byte) ([]byte, error) 37 38 // Update associates key with value in the trie. 39 Update(key, value []byte) error 40 41 // Delete removes any existing value for key from the trie. 42 Delete(key []byte) error 43 44 // Commit the trie and returns a set of dirty nodes generated along with 45 // the new root hash. 46 Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) 47 } 48 49 // TrieLoader wraps functions to load tries. 50 type TrieLoader interface { 51 // OpenTrie opens the main account trie. 52 OpenTrie(root common.Hash) (Trie, error) 53 54 // OpenStorageTrie opens the storage trie of an account. 55 OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (Trie, error) 56 } 57 58 // Set represents a collection of mutated states during a state transition. 59 // The value refers to the original content of state before the transition 60 // is made. Nil means that the state was not present previously. 61 type Set struct { 62 Accounts map[common.Address][]byte // Mutated account set, nil means the account was not present 63 Storages map[common.Address]map[common.Hash][]byte // Mutated storage set, nil means the slot was not present 64 Incomplete map[common.Address]struct{} // Indicator whether the storage is incomplete due to large deletion 65 size common.StorageSize // Approximate size of set 66 } 67 68 // New constructs the state set with provided data. 69 func New(accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, incomplete map[common.Address]struct{}) *Set { 70 return &Set{ 71 Accounts: accounts, 72 Storages: storages, 73 Incomplete: incomplete, 74 } 75 } 76 77 // Size returns the approximate memory size occupied by the set. 78 func (s *Set) Size() common.StorageSize { 79 if s.size != 0 { 80 return s.size 81 } 82 for _, account := range s.Accounts { 83 s.size += common.StorageSize(common.AddressLength + len(account)) 84 } 85 for _, slots := range s.Storages { 86 for _, val := range slots { 87 s.size += common.StorageSize(common.HashLength + len(val)) 88 } 89 s.size += common.StorageSize(common.AddressLength) 90 } 91 s.size += common.StorageSize(common.AddressLength * len(s.Incomplete)) 92 return s.size 93 } 94 95 // context wraps all fields for executing state diffs. 96 type context struct { 97 prevRoot common.Hash 98 postRoot common.Hash 99 accounts map[common.Address][]byte 100 storages map[common.Address]map[common.Hash][]byte 101 accountTrie Trie 102 nodes *trienode.MergedNodeSet 103 } 104 105 // Apply traverses the provided state diffs, apply them in the associated 106 // post-state and return the generated dirty trie nodes. The state can be 107 // loaded via the provided trie loader. 108 func Apply(prevRoot common.Hash, postRoot common.Hash, accounts map[common.Address][]byte, storages map[common.Address]map[common.Hash][]byte, loader TrieLoader) (map[common.Hash]map[string]*trienode.Node, error) { 109 tr, err := loader.OpenTrie(postRoot) 110 if err != nil { 111 return nil, err 112 } 113 ctx := &context{ 114 prevRoot: prevRoot, 115 postRoot: postRoot, 116 accounts: accounts, 117 storages: storages, 118 accountTrie: tr, 119 nodes: trienode.NewMergedNodeSet(), 120 } 121 for addr, account := range accounts { 122 var err error 123 if len(account) == 0 { 124 err = deleteAccount(ctx, loader, addr) 125 } else { 126 err = updateAccount(ctx, loader, addr) 127 } 128 if err != nil { 129 return nil, fmt.Errorf("failed to revert state, err: %w", err) 130 } 131 } 132 root, result, err := tr.Commit(false) 133 if err != nil { 134 return nil, err 135 } 136 if root != prevRoot { 137 return nil, fmt.Errorf("failed to revert state, want %#x, got %#x", prevRoot, root) 138 } 139 if err := ctx.nodes.Merge(result); err != nil { 140 return nil, err 141 } 142 return ctx.nodes.Flatten(), nil 143 } 144 145 // updateAccount the account was present in prev-state, and may or may not 146 // existent in post-state. Apply the reverse diff and verify if the storage 147 // root matches the one in prev-state account. 148 func updateAccount(ctx *context, loader TrieLoader, addr common.Address) error { 149 // The account was present in prev-state, decode it from the 150 // 'slim-rlp' format bytes. 151 h := newHasher() 152 defer h.release() 153 154 addrHash := h.hash(addr.Bytes()) 155 prev, err := types.FullAccount(ctx.accounts[addr]) 156 if err != nil { 157 return err 158 } 159 // The account may or may not existent in post-state, try to 160 // load it and decode if it's found. 161 blob, err := ctx.accountTrie.Get(addrHash.Bytes()) 162 if err != nil { 163 return err 164 } 165 post := types.NewEmptyStateAccount() 166 if len(blob) != 0 { 167 if err := rlp.DecodeBytes(blob, &post); err != nil { 168 return err 169 } 170 } 171 // Apply all storage changes into the post-state storage trie. 172 st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) 173 if err != nil { 174 return err 175 } 176 for key, val := range ctx.storages[addr] { 177 var err error 178 if len(val) == 0 { 179 err = st.Delete(key.Bytes()) 180 } else { 181 err = st.Update(key.Bytes(), val) 182 } 183 if err != nil { 184 return err 185 } 186 } 187 root, result, err := st.Commit(false) 188 if err != nil { 189 return err 190 } 191 if root != prev.Root { 192 return errors.New("failed to reset storage trie") 193 } 194 // The returned set can be nil if storage trie is not changed 195 // at all. 196 if result != nil { 197 if err := ctx.nodes.Merge(result); err != nil { 198 return err 199 } 200 } 201 // Write the prev-state account into the main trie 202 full, err := rlp.EncodeToBytes(prev) 203 if err != nil { 204 return err 205 } 206 return ctx.accountTrie.Update(addrHash.Bytes(), full) 207 } 208 209 // deleteAccount the account was not present in prev-state, and is expected 210 // to be existent in post-state. Apply the reverse diff and verify if the 211 // account and storage is wiped out correctly. 212 func deleteAccount(ctx *context, loader TrieLoader, addr common.Address) error { 213 // The account must be existent in post-state, load the account. 214 h := newHasher() 215 defer h.release() 216 217 addrHash := h.hash(addr.Bytes()) 218 blob, err := ctx.accountTrie.Get(addrHash.Bytes()) 219 if err != nil { 220 return err 221 } 222 if len(blob) == 0 { 223 return fmt.Errorf("account is non-existent %#x", addrHash) 224 } 225 var post types.StateAccount 226 if err := rlp.DecodeBytes(blob, &post); err != nil { 227 return err 228 } 229 st, err := loader.OpenStorageTrie(ctx.postRoot, addrHash, post.Root) 230 if err != nil { 231 return err 232 } 233 for key, val := range ctx.storages[addr] { 234 if len(val) != 0 { 235 return errors.New("expect storage deletion") 236 } 237 if err := st.Delete(key.Bytes()); err != nil { 238 return err 239 } 240 } 241 root, result, err := st.Commit(false) 242 if err != nil { 243 return err 244 } 245 if root != types.EmptyRootHash { 246 return errors.New("failed to clear storage trie") 247 } 248 // The returned set can be nil if storage trie is not changed 249 // at all. 250 if result != nil { 251 if err := ctx.nodes.Merge(result); err != nil { 252 return err 253 } 254 } 255 // Delete the post-state account from the main trie. 256 return ctx.accountTrie.Delete(addrHash.Bytes()) 257 } 258 259 // hasher is used to compute the sha256 hash of the provided data. 260 type hasher struct{ sha crypto.KeccakState } 261 262 var hasherPool = sync.Pool{ 263 New: func() interface{} { return &hasher{sha: sha3.NewLegacyKeccak256().(crypto.KeccakState)} }, 264 } 265 266 func newHasher() *hasher { 267 return hasherPool.Get().(*hasher) 268 } 269 270 func (h *hasher) hash(data []byte) common.Hash { 271 return crypto.HashData(h.sha, data) 272 } 273 274 func (h *hasher) release() { 275 hasherPool.Put(h) 276 }