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