github.com/klaytn/klaytn@v1.10.2/storage/statedb/hasher.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from trie/hasher.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package statedb 22 23 import ( 24 "hash" 25 "sync" 26 27 "github.com/klaytn/klaytn/common" 28 "github.com/klaytn/klaytn/crypto/sha3" 29 "github.com/klaytn/klaytn/rlp" 30 ) 31 32 type hasher struct { 33 tmp sliceBuffer 34 sha KeccakState 35 onleaf LeafCallback 36 } 37 38 // KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports 39 // Read to get a variable amount of data from the hash state. Read is faster than Sum 40 // because it doesn't copy the internal state, but also modifies the internal state. 41 type KeccakState interface { 42 hash.Hash 43 Read([]byte) (int, error) 44 } 45 46 type sliceBuffer []byte 47 48 func (b *sliceBuffer) Write(data []byte) (n int, err error) { 49 *b = append(*b, data...) 50 return len(data), nil 51 } 52 53 func (b *sliceBuffer) Reset() { 54 *b = (*b)[:0] 55 } 56 57 // hashers live in a global db. 58 var hasherPool = sync.Pool{ 59 New: func() interface{} { 60 return &hasher{ 61 tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. 62 sha: sha3.NewKeccak256().(KeccakState), 63 } 64 }, 65 } 66 67 func newHasher(onleaf LeafCallback) *hasher { 68 h := hasherPool.Get().(*hasher) 69 h.onleaf = onleaf 70 return h 71 } 72 73 func returnHasherToPool(h *hasher) { 74 hasherPool.Put(h) 75 } 76 77 // hash collapses a node down into a hash node, also returning a copy of the 78 // original node initialized with the computed hash to replace the original one. 79 func (h *hasher) hash(n node, db *Database, force bool) (node, node) { 80 // If we're not storing the node, just hashing, use available cached data 81 if hash, dirty := n.cache(); hash != nil { 82 if db == nil { 83 return hash, n 84 } 85 if !dirty { 86 switch n.(type) { 87 case *fullNode, *shortNode: 88 return hash, hash 89 default: 90 return hash, n 91 } 92 } 93 } 94 // Trie not processed yet or needs storage, walk the children 95 collapsed, cached := h.hashChildren(n, db) 96 hashed, lenEncoded := h.store(collapsed, db, force) 97 // Cache the hash of the node for later reuse and remove 98 // the dirty flag in commit mode. It's fine to assign these values directly 99 // without copying the node first because hashChildren copies it. 100 cachedHash, _ := hashed.(hashNode) 101 switch cn := cached.(type) { 102 case *shortNode: 103 cn.flags.hash = cachedHash 104 cn.flags.lenEncoded = lenEncoded 105 if db != nil { 106 cn.flags.dirty = false 107 } 108 case *fullNode: 109 cn.flags.hash = cachedHash 110 cn.flags.lenEncoded = lenEncoded 111 if db != nil { 112 cn.flags.dirty = false 113 } 114 } 115 return hashed, cached 116 } 117 118 func (h *hasher) hashRoot(n node, db *Database, force bool) (node, node) { 119 // If we're not storing the node, just hashing, use available cached data 120 if hash, dirty := n.cache(); hash != nil { 121 if db == nil { 122 return hash, n 123 } 124 if !dirty { 125 switch n.(type) { 126 case *fullNode, *shortNode: 127 return hash, hash 128 default: 129 return hash, n 130 } 131 } 132 } 133 // Trie not processed yet or needs storage, walk the children 134 collapsed, cached := h.hashChildrenFromRoot(n, db) 135 hashed, lenEncoded := h.store(collapsed, db, force) 136 // Cache the hash of the node for later reuse and remove 137 // the dirty flag in commit mode. It's fine to assign these values directly 138 // without copying the node first because hashChildren copies it. 139 cachedHash, _ := hashed.(hashNode) 140 switch cn := cached.(type) { 141 case *shortNode: 142 cn.flags.hash = cachedHash 143 cn.flags.lenEncoded = lenEncoded 144 if db != nil { 145 cn.flags.dirty = false 146 } 147 case *fullNode: 148 cn.flags.hash = cachedHash 149 cn.flags.lenEncoded = lenEncoded 150 if db != nil { 151 cn.flags.dirty = false 152 } 153 } 154 return hashed, cached 155 } 156 157 // hashChildren replaces the children of a node with their hashes if the encoded 158 // size of the child is larger than a hash, returning the collapsed node as well 159 // as a replacement for the original node with the child hashes cached in. 160 func (h *hasher) hashChildren(original node, db *Database) (node, node) { 161 switch n := original.(type) { 162 case *shortNode: 163 // Hash the short node's child, caching the newly hashed subtree 164 collapsed, cached := n.copy(), n.copy() 165 collapsed.Key = hexToCompact(n.Key) 166 cached.Key = common.CopyBytes(n.Key) 167 168 if _, ok := n.Val.(valueNode); !ok { 169 collapsed.Val, cached.Val = h.hash(n.Val, db, false) 170 } 171 return collapsed, cached 172 173 case *fullNode: 174 // Hash the full node's children, caching the newly hashed subtrees 175 collapsed, cached := n.copy(), n.copy() 176 177 for i := 0; i < 16; i++ { 178 if n.Children[i] != nil { 179 collapsed.Children[i], cached.Children[i] = h.hash(n.Children[i], db, false) 180 } 181 } 182 cached.Children[16] = n.Children[16] 183 return collapsed, cached 184 185 default: 186 // Value and hash nodes don't have children so they're left as were 187 return n, original 188 } 189 } 190 191 type hashResult struct { 192 index int 193 collapsed node 194 cached node 195 } 196 197 func (h *hasher) hashChildrenFromRoot(original node, db *Database) (node, node) { 198 switch n := original.(type) { 199 case *shortNode: 200 // Hash the short node's child, caching the newly hashed subtree 201 collapsed, cached := n.copy(), n.copy() 202 collapsed.Key = hexToCompact(n.Key) 203 cached.Key = common.CopyBytes(n.Key) 204 205 if _, ok := n.Val.(valueNode); !ok { 206 collapsed.Val, cached.Val = h.hash(n.Val, db, false) 207 } 208 return collapsed, cached 209 210 case *fullNode: 211 // Hash the full node's children, caching the newly hashed subtrees 212 collapsed, cached := n.copy(), n.copy() 213 214 hashResultCh := make(chan hashResult, 16) 215 numRootChildren := 0 216 for i := 0; i < 16; i++ { 217 if n.Children[i] != nil { 218 numRootChildren++ 219 go func(i int, n node) { 220 childHasher := newHasher(h.onleaf) 221 defer returnHasherToPool(childHasher) 222 collapsedFromChild, cachedFromChild := childHasher.hash(n, db, false) 223 hashResultCh <- hashResult{i, collapsedFromChild, cachedFromChild} 224 }(i, n.Children[i]) 225 } 226 } 227 228 for i := 0; i < numRootChildren; i++ { 229 hashResult := <-hashResultCh 230 idx := hashResult.index 231 collapsed.Children[idx], cached.Children[idx] = hashResult.collapsed, hashResult.cached 232 } 233 234 cached.Children[16] = n.Children[16] 235 return collapsed, cached 236 237 default: 238 // Value and hash nodes don't have children so they're left as were 239 return n, original 240 } 241 } 242 243 // store hashes the node n and if we have a storage layer specified, it writes 244 // the key/value pair to it and tracks any node->child references as well as any 245 // node->external trie references. 246 func (h *hasher) store(n node, db *Database, force bool) (node, uint16) { 247 // Don't store hashes or empty nodes. 248 if _, isHash := n.(hashNode); n == nil || isHash { 249 return n, 0 250 } 251 hash, _ := n.cache() 252 lenEncoded := n.lenEncoded() 253 if hash == nil || lenEncoded == 0 { 254 // Generate the RLP encoding of the node 255 h.tmp.Reset() 256 if err := rlp.Encode(&h.tmp, n); err != nil { 257 panic("encode error: " + err.Error()) 258 } 259 260 lenEncoded = uint16(len(h.tmp)) 261 } 262 if lenEncoded < 32 && !force { 263 return n, lenEncoded // Nodes smaller than 32 bytes are stored inside their parent 264 } 265 if hash == nil { 266 hash = h.makeHashNode(h.tmp) 267 } 268 if db != nil { 269 // We are pooling the trie nodes into an intermediate memory cache 270 hash := common.BytesToHash(hash) 271 272 db.lock.Lock() 273 db.insert(hash, lenEncoded, n) 274 db.lock.Unlock() 275 276 // Track external references from account->storage trie 277 if h.onleaf != nil { 278 switch n := n.(type) { 279 case *shortNode: 280 if child, ok := n.Val.(valueNode); ok { 281 h.onleaf(nil, nil, child, hash, 0) 282 } 283 case *fullNode: 284 for i := 0; i < 16; i++ { 285 if child, ok := n.Children[i].(valueNode); ok { 286 h.onleaf(nil, nil, child, hash, 0) 287 } 288 } 289 } 290 } 291 } 292 return hash, lenEncoded 293 } 294 295 func (h *hasher) makeHashNode(data []byte) hashNode { 296 n := make(hashNode, h.sha.Size()) 297 h.sha.Reset() 298 h.sha.Write(data) 299 h.sha.Read(n) 300 return n 301 }