github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/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 "bytes" 21 "hash" 22 "sync" 23 24 "github.com/ethereum/go-ethereum/common" 25 "github.com/ethereum/go-ethereum/crypto/sha3" 26 "github.com/ethereum/go-ethereum/rlp" 27 ) 28 29 type hasher struct { 30 tmp *bytes.Buffer 31 sha hash.Hash 32 cachegen, cachelimit uint16 33 } 34 35 // hashers live in a global pool. 36 var hasherPool = sync.Pool{ 37 New: func() interface{} { 38 return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()} 39 }, 40 } 41 42 func newHasher(cachegen, cachelimit uint16) *hasher { 43 h := hasherPool.Get().(*hasher) 44 h.cachegen, h.cachelimit = cachegen, cachelimit 45 return h 46 } 47 48 func returnHasherToPool(h *hasher) { 49 hasherPool.Put(h) 50 } 51 52 // hash collapses a node down into a hash node, also returning a copy of the 53 // original node initialzied with the computed hash to replace the original one. 54 func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) { 55 // If we're not storing the node, just hashing, use available cached data 56 if hash, dirty := n.cache(); hash != nil { 57 if db == nil { 58 return hash, n, nil 59 } 60 if n.canUnload(h.cachegen, h.cachelimit) { 61 // Unload the node from cache. All of its subnodes will have a lower or equal 62 // cache generation number. 63 cacheUnloadCounter.Inc(1) 64 return hash, hash, nil 65 } 66 if !dirty { 67 return hash, n, nil 68 } 69 } 70 // Trie not processed yet or needs storage, walk the children 71 collapsed, cached, err := h.hashChildren(n, db) 72 if err != nil { 73 return hashNode{}, n, err 74 } 75 hashed, err := h.store(collapsed, db, force) 76 if err != nil { 77 return hashNode{}, n, err 78 } 79 // Cache the hash of the ndoe for later reuse and remove 80 // the dirty flag in commit mode. It's fine to assign these values directly 81 // without copying the node first because hashChildren copies it. 82 cachedHash, _ := hashed.(hashNode) 83 switch cn := cached.(type) { 84 case *shortNode: 85 cn.flags.hash = cachedHash 86 if db != nil { 87 cn.flags.dirty = false 88 } 89 case *fullNode: 90 cn.flags.hash = cachedHash 91 if db != nil { 92 cn.flags.dirty = false 93 } 94 } 95 return hashed, cached, nil 96 } 97 98 // hashChildren replaces the children of a node with their hashes if the encoded 99 // size of the child is larger than a hash, returning the collapsed node as well 100 // as a replacement for the original node with the child hashes cached in. 101 func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, error) { 102 var err error 103 104 switch n := original.(type) { 105 case *shortNode: 106 // Hash the short node's child, caching the newly hashed subtree 107 collapsed, cached := n.copy(), n.copy() 108 collapsed.Key = compactEncode(n.Key) 109 cached.Key = common.CopyBytes(n.Key) 110 111 if _, ok := n.Val.(valueNode); !ok { 112 collapsed.Val, cached.Val, err = h.hash(n.Val, db, false) 113 if err != nil { 114 return original, original, err 115 } 116 } 117 if collapsed.Val == nil { 118 collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings. 119 } 120 return collapsed, cached, nil 121 122 case *fullNode: 123 // Hash the full node's children, caching the newly hashed subtrees 124 collapsed, cached := n.copy(), n.copy() 125 126 for i := 0; i < 16; i++ { 127 if n.Children[i] != nil { 128 collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false) 129 if err != nil { 130 return original, original, err 131 } 132 } else { 133 collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings. 134 } 135 } 136 cached.Children[16] = n.Children[16] 137 if collapsed.Children[16] == nil { 138 collapsed.Children[16] = valueNode(nil) 139 } 140 return collapsed, cached, nil 141 142 default: 143 // Value and hash nodes don't have children so they're left as were 144 return n, original, nil 145 } 146 } 147 148 func (h *hasher) store(n node, db DatabaseWriter, force bool) (node, error) { 149 // Don't store hashes or empty nodes. 150 if _, isHash := n.(hashNode); n == nil || isHash { 151 return n, nil 152 } 153 // Generate the RLP encoding of the node 154 h.tmp.Reset() 155 if err := rlp.Encode(h.tmp, n); err != nil { 156 panic("encode error: " + err.Error()) 157 } 158 159 if h.tmp.Len() < 32 && !force { 160 return n, nil // Nodes smaller than 32 bytes are stored inside their parent 161 } 162 // Larger nodes are replaced by their hash and stored in the database. 163 hash, _ := n.cache() 164 if hash == nil { 165 h.sha.Reset() 166 h.sha.Write(h.tmp.Bytes()) 167 hash = hashNode(h.sha.Sum(nil)) 168 } 169 if db != nil { 170 return hash, db.Put(hash, h.tmp.Bytes()) 171 } 172 return hash, nil 173 }