github.com/theQRL/go-zond@v0.1.1/trie/triedb/pathdb/testutils.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 pathdb 18 19 import ( 20 "bytes" 21 "fmt" 22 23 "github.com/theQRL/go-zond/common" 24 "github.com/theQRL/go-zond/core/types" 25 "github.com/theQRL/go-zond/crypto" 26 "github.com/theQRL/go-zond/trie/trienode" 27 "github.com/theQRL/go-zond/trie/triestate" 28 "golang.org/x/exp/slices" 29 ) 30 31 // testHasher is a test utility for computing root hash of a batch of state 32 // elements. The hash algorithm is to sort all the elements in lexicographical 33 // order, concat the key and value in turn, and perform hash calculation on 34 // the concatenated bytes. Except the root hash, a nodeset will be returned 35 // once Commit is called, which contains all the changes made to hasher. 36 type testHasher struct { 37 owner common.Hash // owner identifier 38 root common.Hash // original root 39 dirties map[common.Hash][]byte // dirty states 40 cleans map[common.Hash][]byte // clean states 41 } 42 43 // newTestHasher constructs a hasher object with provided states. 44 func newTestHasher(owner common.Hash, root common.Hash, cleans map[common.Hash][]byte) (*testHasher, error) { 45 if cleans == nil { 46 cleans = make(map[common.Hash][]byte) 47 } 48 if got, _ := hash(cleans); got != root { 49 return nil, fmt.Errorf("state root mismatched, want: %x, got: %x", root, got) 50 } 51 return &testHasher{ 52 owner: owner, 53 root: root, 54 dirties: make(map[common.Hash][]byte), 55 cleans: cleans, 56 }, nil 57 } 58 59 // Get returns the value for key stored in the trie. 60 func (h *testHasher) Get(key []byte) ([]byte, error) { 61 hash := common.BytesToHash(key) 62 val, ok := h.dirties[hash] 63 if ok { 64 return val, nil 65 } 66 return h.cleans[hash], nil 67 } 68 69 // Update associates key with value in the trie. 70 func (h *testHasher) Update(key, value []byte) error { 71 h.dirties[common.BytesToHash(key)] = common.CopyBytes(value) 72 return nil 73 } 74 75 // Delete removes any existing value for key from the trie. 76 func (h *testHasher) Delete(key []byte) error { 77 h.dirties[common.BytesToHash(key)] = nil 78 return nil 79 } 80 81 // Commit computes the new hash of the states and returns the set with all 82 // state changes. 83 func (h *testHasher) Commit(collectLeaf bool) (common.Hash, *trienode.NodeSet, error) { 84 var ( 85 nodes = make(map[common.Hash][]byte) 86 set = trienode.NewNodeSet(h.owner) 87 ) 88 for hash, val := range h.cleans { 89 nodes[hash] = val 90 } 91 for hash, val := range h.dirties { 92 nodes[hash] = val 93 if bytes.Equal(val, h.cleans[hash]) { 94 continue 95 } 96 if len(val) == 0 { 97 set.AddNode(hash.Bytes(), trienode.NewDeleted()) 98 } else { 99 set.AddNode(hash.Bytes(), trienode.New(crypto.Keccak256Hash(val), val)) 100 } 101 } 102 root, blob := hash(nodes) 103 104 // Include the dirty root node as well. 105 if root != types.EmptyRootHash && root != h.root { 106 set.AddNode(nil, trienode.New(root, blob)) 107 } 108 if root == types.EmptyRootHash && h.root != types.EmptyRootHash { 109 set.AddNode(nil, trienode.NewDeleted()) 110 } 111 return root, set, nil 112 } 113 114 // hash performs the hash computation upon the provided states. 115 func hash(states map[common.Hash][]byte) (common.Hash, []byte) { 116 var hs []common.Hash 117 for hash := range states { 118 hs = append(hs, hash) 119 } 120 slices.SortFunc(hs, common.Hash.Cmp) 121 122 var input []byte 123 for _, hash := range hs { 124 if len(states[hash]) == 0 { 125 continue 126 } 127 input = append(input, hash.Bytes()...) 128 input = append(input, states[hash]...) 129 } 130 if len(input) == 0 { 131 return types.EmptyRootHash, nil 132 } 133 return crypto.Keccak256Hash(input), input 134 } 135 136 type hashLoader struct { 137 accounts map[common.Hash][]byte 138 storages map[common.Hash]map[common.Hash][]byte 139 } 140 141 func newHashLoader(accounts map[common.Hash][]byte, storages map[common.Hash]map[common.Hash][]byte) *hashLoader { 142 return &hashLoader{ 143 accounts: accounts, 144 storages: storages, 145 } 146 } 147 148 // OpenTrie opens the main account trie. 149 func (l *hashLoader) OpenTrie(root common.Hash) (triestate.Trie, error) { 150 return newTestHasher(common.Hash{}, root, l.accounts) 151 } 152 153 // OpenStorageTrie opens the storage trie of an account. 154 func (l *hashLoader) OpenStorageTrie(stateRoot common.Hash, addrHash, root common.Hash) (triestate.Trie, error) { 155 return newTestHasher(addrHash, root, l.storages[addrHash]) 156 }