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