github.com/theQRL/go-zond@v0.1.1/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 "sync" 21 22 "github.com/theQRL/go-zond/crypto" 23 "github.com/theQRL/go-zond/rlp" 24 "golang.org/x/crypto/sha3" 25 ) 26 27 // hasher is a type used for the trie Hash operation. A hasher has some 28 // internal preallocated temp space 29 type hasher struct { 30 sha crypto.KeccakState 31 tmp []byte 32 encbuf rlp.EncoderBuffer 33 parallel bool // Whether to use parallel threads when hashing 34 } 35 36 // hasherPool holds pureHashers 37 var hasherPool = sync.Pool{ 38 New: func() interface{} { 39 return &hasher{ 40 tmp: make([]byte, 0, 550), // cap is as large as a full fullNode. 41 sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), 42 encbuf: rlp.NewEncoderBuffer(nil), 43 } 44 }, 45 } 46 47 func newHasher(parallel bool) *hasher { 48 h := hasherPool.Get().(*hasher) 49 h.parallel = parallel 50 return h 51 } 52 53 func returnHasherToPool(h *hasher) { 54 hasherPool.Put(h) 55 } 56 57 // hash collapses a node down into a hash node, also returning a copy of the 58 // original node initialized with the computed hash to replace the original one. 59 func (h *hasher) hash(n node, force bool) (hashed node, cached node) { 60 // Return the cached hash if it's available 61 if hash, _ := n.cache(); hash != nil { 62 return hash, n 63 } 64 // Trie not processed yet, walk the children 65 switch n := n.(type) { 66 case *shortNode: 67 collapsed, cached := h.hashShortNodeChildren(n) 68 hashed := h.shortnodeToHash(collapsed, force) 69 // We need to retain the possibly _not_ hashed node, in case it was too 70 // small to be hashed 71 if hn, ok := hashed.(hashNode); ok { 72 cached.flags.hash = hn 73 } else { 74 cached.flags.hash = nil 75 } 76 return hashed, cached 77 case *fullNode: 78 collapsed, cached := h.hashFullNodeChildren(n) 79 hashed = h.fullnodeToHash(collapsed, force) 80 if hn, ok := hashed.(hashNode); ok { 81 cached.flags.hash = hn 82 } else { 83 cached.flags.hash = nil 84 } 85 return hashed, cached 86 default: 87 // Value and hash nodes don't have children so they're left as were 88 return n, n 89 } 90 } 91 92 // hashShortNodeChildren collapses the short node. The returned collapsed node 93 // holds a live reference to the Key, and must not be modified. 94 // The cached 95 func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { 96 // Hash the short node's child, caching the newly hashed subtree 97 collapsed, cached = n.copy(), n.copy() 98 // Previously, we did copy this one. We don't seem to need to actually 99 // do that, since we don't overwrite/reuse keys 100 //cached.Key = common.CopyBytes(n.Key) 101 collapsed.Key = hexToCompact(n.Key) 102 // Unless the child is a valuenode or hashnode, hash it 103 switch n.Val.(type) { 104 case *fullNode, *shortNode: 105 collapsed.Val, cached.Val = h.hash(n.Val, false) 106 } 107 return collapsed, cached 108 } 109 110 func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { 111 // Hash the full node's children, caching the newly hashed subtrees 112 cached = n.copy() 113 collapsed = n.copy() 114 if h.parallel { 115 var wg sync.WaitGroup 116 wg.Add(16) 117 for i := 0; i < 16; i++ { 118 go func(i int) { 119 hasher := newHasher(false) 120 if child := n.Children[i]; child != nil { 121 collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) 122 } else { 123 collapsed.Children[i] = nilValueNode 124 } 125 returnHasherToPool(hasher) 126 wg.Done() 127 }(i) 128 } 129 wg.Wait() 130 } else { 131 for i := 0; i < 16; i++ { 132 if child := n.Children[i]; child != nil { 133 collapsed.Children[i], cached.Children[i] = h.hash(child, false) 134 } else { 135 collapsed.Children[i] = nilValueNode 136 } 137 } 138 } 139 return collapsed, cached 140 } 141 142 // shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode 143 // should have hex-type Key, which will be converted (without modification) 144 // into compact form for RLP encoding. 145 // If the rlp data is smaller than 32 bytes, `nil` is returned. 146 func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { 147 n.encode(h.encbuf) 148 enc := h.encodedBytes() 149 150 if len(enc) < 32 && !force { 151 return n // Nodes smaller than 32 bytes are stored inside their parent 152 } 153 return h.hashData(enc) 154 } 155 156 // shortnodeToHash is used to creates a hashNode from a set of hashNodes, (which 157 // may contain nil values) 158 func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { 159 n.encode(h.encbuf) 160 enc := h.encodedBytes() 161 162 if len(enc) < 32 && !force { 163 return n // Nodes smaller than 32 bytes are stored inside their parent 164 } 165 return h.hashData(enc) 166 } 167 168 // encodedBytes returns the result of the last encoding operation on h.encbuf. 169 // This also resets the encoder buffer. 170 // 171 // All node encoding must be done like this: 172 // 173 // node.encode(h.encbuf) 174 // enc := h.encodedBytes() 175 // 176 // This convention exists because node.encode can only be inlined/escape-analyzed when 177 // called on a concrete receiver type. 178 func (h *hasher) encodedBytes() []byte { 179 h.tmp = h.encbuf.AppendToBytes(h.tmp[:0]) 180 h.encbuf.Reset(nil) 181 return h.tmp 182 } 183 184 // hashData hashes the provided data 185 func (h *hasher) hashData(data []byte) hashNode { 186 n := make(hashNode, 32) 187 h.sha.Reset() 188 h.sha.Write(data) 189 h.sha.Read(n) 190 return n 191 } 192 193 // proofHash is used to construct trie proofs, and returns the 'collapsed' 194 // node (for later RLP encoding) as well as the hashed node -- unless the 195 // node is smaller than 32 bytes, in which case it will be returned as is. 196 // This method does not do anything on value- or hash-nodes. 197 func (h *hasher) proofHash(original node) (collapsed, hashed node) { 198 switch n := original.(type) { 199 case *shortNode: 200 sn, _ := h.hashShortNodeChildren(n) 201 return sn, h.shortnodeToHash(sn, false) 202 case *fullNode: 203 fn, _ := h.hashFullNodeChildren(n) 204 return fn, h.fullnodeToHash(fn, false) 205 default: 206 // Value and hash nodes don't have children so they're left as were 207 return n, n 208 } 209 }