github.com/gochain-io/gochain@v2.2.26+incompatible/trie/hasher.go (about) 1 // Copyright 2016 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 trie 18 19 import ( 20 "hash" 21 "sync" 22 23 "github.com/gochain-io/gochain/common" 24 "github.com/gochain-io/gochain/crypto/sha3" 25 "github.com/gochain-io/gochain/rlp" 26 ) 27 28 type hasher struct { 29 tmp sliceBuffer 30 sha keccakState 31 cachegen uint16 32 cachelimit uint16 33 onleaf LeafCallback 34 } 35 36 // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports 37 // Read to get a variable amount of data from the hash state. Read is faster than Sum 38 // because it doesn't copy the internal state, but also modifies the internal state. 39 type keccakState interface { 40 hash.Hash 41 Read([]byte) (int, error) 42 } 43 44 type sliceBuffer []byte 45 46 func (b *sliceBuffer) Write(data []byte) (n int, err error) { 47 *b = append(*b, data...) 48 return len(data), nil 49 } 50 51 func (b *sliceBuffer) Reset() { 52 *b = (*b)[:0] 53 } 54 55 // hashers live in a global db. 56 var hasherPool = sync.Pool{ 57 New: func() interface{} { 58 return &hasher{ 59 tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. 60 sha: sha3.NewKeccak256().(keccakState), 61 } 62 }, 63 } 64 65 func newHasher(cachegen, cachelimit uint16, onleaf LeafCallback) *hasher { 66 h := hasherPool.Get().(*hasher) 67 h.cachegen, h.cachelimit, h.onleaf = cachegen, cachelimit, onleaf 68 return h 69 } 70 71 func returnHasherToPool(h *hasher) { 72 hasherPool.Put(h) 73 } 74 75 // hash collapses a node down into a hash node, also returning a copy of the 76 // original node initialized with the computed hash to replace the original one. 77 func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) { 78 // If we're not storing the node, just hashing, use available cached data 79 if hash, dirty := n.cache(); hash != nil { 80 if db == nil { 81 return hash, n, nil 82 } 83 if n.canUnload(h.cachegen, h.cachelimit) { 84 // Unload the node from cache. All of its subnodes will have a lower or equal 85 // cache generation number. 86 cacheUnloadCounter.Inc(1) 87 return hash, hash, nil 88 } 89 if !dirty { 90 return hash, n, nil 91 } 92 } 93 // Trie not processed yet or needs storage, walk the children 94 collapsed, cached, err := h.hashChildren(n, db) 95 if err != nil { 96 return hashNode{}, n, err 97 } 98 hashed, err := h.store(collapsed, db, force) 99 if err != nil { 100 return hashNode{}, n, err 101 } 102 // Cache the hash of the node for later reuse and remove 103 // the dirty flag in commit mode. It's fine to assign these values directly 104 // without copying the node first because hashChildren copies it. 105 cachedHash, _ := hashed.(hashNode) 106 switch cn := cached.(type) { 107 case *shortNode: 108 cn.flags.hash = cachedHash 109 if db != nil { 110 cn.flags.dirty = false 111 } 112 case *fullNode: 113 cn.flags.hash = cachedHash 114 if db != nil { 115 cn.flags.dirty = false 116 } 117 } 118 return hashed, cached, nil 119 } 120 121 // hashChildren replaces the children of a node with their hashes if the encoded 122 // size of the child is larger than a hash, returning the collapsed node as well 123 // as a replacement for the original node with the child hashes cached in. 124 func (h *hasher) hashChildren(original node, db *Database) (node, node, error) { 125 var err error 126 127 switch n := original.(type) { 128 case *shortNode: 129 // Hash the short node's child, caching the newly hashed subtree 130 collapsed, cached := n.copy(), n.copy() 131 collapsed.Key = hexToCompact(n.Key) 132 cached.Key = common.CopyBytes(n.Key) 133 134 if _, ok := n.Val.(valueNode); !ok { 135 collapsed.Val, cached.Val, err = h.hash(n.Val, db, false) 136 if err != nil { 137 return original, original, err 138 } 139 } 140 return collapsed, cached, nil 141 142 case *fullNode: 143 // Hash the full node's children, caching the newly hashed subtrees 144 collapsed, cached := n.copy(), n.copy() 145 146 for i := 0; i < 16; i++ { 147 if n.Children[i] != nil { 148 collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false) 149 if err != nil { 150 return original, original, err 151 } 152 } 153 } 154 cached.Children[16] = n.Children[16] 155 return collapsed, cached, nil 156 157 default: 158 // Value and hash nodes don't have children so they're left as were 159 return n, original, nil 160 } 161 } 162 163 // store hashes the node n and if we have a storage layer specified, it writes 164 // the key/value pair to it and tracks any node->child references as well as any 165 // node->external trie references. 166 func (h *hasher) store(n node, db *Database, force bool) (node, error) { 167 // Don't store hashes or empty nodes. 168 if _, isHash := n.(hashNode); n == nil || isHash { 169 return n, nil 170 } 171 // Generate the RLP encoding of the node 172 h.tmp.Reset() 173 if err := rlp.Encode(&h.tmp, n); err != nil { 174 panic("encode error: " + err.Error()) 175 } 176 if len(h.tmp) < 32 && !force { 177 return n, nil // Nodes smaller than 32 bytes are stored inside their parent 178 } 179 // Larger nodes are replaced by their hash and stored in the database. 180 hash, _ := n.cache() 181 if hash == nil { 182 hash = h.makeHashNode(h.tmp) 183 } 184 185 if db != nil { 186 // We are pooling the trie nodes into an intermediate memory cache 187 hash := common.BytesToHash(hash) 188 189 db.lock.Lock() 190 db.insert(hash, h.tmp, n) 191 db.lock.Unlock() 192 193 // Track external references from account->storage trie 194 if h.onleaf != nil { 195 switch n := n.(type) { 196 case *shortNode: 197 if child, ok := n.Val.(valueNode); ok { 198 h.onleaf(child, hash) 199 } 200 case *fullNode: 201 for i := 0; i < 16; i++ { 202 if child, ok := n.Children[i].(valueNode); ok { 203 h.onleaf(child, hash) 204 } 205 } 206 } 207 } 208 } 209 return hash, nil 210 } 211 212 func (h *hasher) makeHashNode(data []byte) hashNode { 213 n := make(hashNode, h.sha.Size()) 214 h.sha.Reset() 215 h.sha.Write(data) 216 h.sha.Read(n) 217 return n 218 }