git.pirl.io/community/pirl@v0.0.0-20201111064343-9d3d31ff74be/trie/hasher.go (about) 1 // Copyright 2019 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 "hash" 21 "sync" 22 23 "git.pirl.io/community/pirl/rlp" 24 "golang.org/x/crypto/sha3" 25 ) 26 27 // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports 28 // Read to get a variable amount of data from the hash state. Read is faster than Sum 29 // because it doesn't copy the internal state, but also modifies the internal state. 30 type keccakState interface { 31 hash.Hash 32 Read([]byte) (int, error) 33 } 34 35 type sliceBuffer []byte 36 37 func (b *sliceBuffer) Write(data []byte) (n int, err error) { 38 *b = append(*b, data...) 39 return len(data), nil 40 } 41 42 func (b *sliceBuffer) Reset() { 43 *b = (*b)[:0] 44 } 45 46 // hasher is a type used for the trie Hash operation. A hasher has some 47 // internal preallocated temp space 48 type hasher struct { 49 sha keccakState 50 tmp sliceBuffer 51 parallel bool // Whether to use paralallel threads when hashing 52 } 53 54 // hasherPool holds pureHashers 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(parallel bool) *hasher { 65 h := hasherPool.Get().(*hasher) 66 h.parallel = parallel 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, force bool) (hashed node, cached node) { 77 // We're not storing the node, just hashing, use available cached data 78 if hash, _ := n.cache(); hash != nil { 79 return hash, n 80 } 81 // Trie not processed yet or needs storage, walk the children 82 switch n := n.(type) { 83 case *shortNode: 84 collapsed, cached := h.hashShortNodeChildren(n) 85 hashed := h.shortnodeToHash(collapsed, force) 86 // We need to retain the possibly _not_ hashed node, in case it was too 87 // small to be hashed 88 if hn, ok := hashed.(hashNode); ok { 89 cached.flags.hash = hn 90 } else { 91 cached.flags.hash = nil 92 } 93 return hashed, cached 94 case *fullNode: 95 collapsed, cached := h.hashFullNodeChildren(n) 96 hashed = h.fullnodeToHash(collapsed, force) 97 if hn, ok := hashed.(hashNode); ok { 98 cached.flags.hash = hn 99 } else { 100 cached.flags.hash = nil 101 } 102 return hashed, cached 103 default: 104 // Value and hash nodes don't have children so they're left as were 105 return n, n 106 } 107 } 108 109 // hashShortNodeChildren collapses the short node. The returned collapsed node 110 // holds a live reference to the Key, and must not be modified. 111 // The cached 112 func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { 113 // Hash the short node's child, caching the newly hashed subtree 114 collapsed, cached = n.copy(), n.copy() 115 // Previously, we did copy this one. We don't seem to need to actually 116 // do that, since we don't overwrite/reuse keys 117 //cached.Key = common.CopyBytes(n.Key) 118 collapsed.Key = hexToCompact(n.Key) 119 // Unless the child is a valuenode or hashnode, hash it 120 switch n.Val.(type) { 121 case *fullNode, *shortNode: 122 collapsed.Val, cached.Val = h.hash(n.Val, false) 123 } 124 return collapsed, cached 125 } 126 127 func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { 128 // Hash the full node's children, caching the newly hashed subtrees 129 cached = n.copy() 130 collapsed = n.copy() 131 if h.parallel { 132 var wg sync.WaitGroup 133 wg.Add(16) 134 for i := 0; i < 16; i++ { 135 go func(i int) { 136 hasher := newHasher(false) 137 if child := n.Children[i]; child != nil { 138 collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) 139 } else { 140 collapsed.Children[i] = nilValueNode 141 } 142 returnHasherToPool(hasher) 143 wg.Done() 144 }(i) 145 } 146 wg.Wait() 147 } else { 148 for i := 0; i < 16; i++ { 149 if child := n.Children[i]; child != nil { 150 collapsed.Children[i], cached.Children[i] = h.hash(child, false) 151 } else { 152 collapsed.Children[i] = nilValueNode 153 } 154 } 155 } 156 return collapsed, cached 157 } 158 159 // shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode 160 // should have hex-type Key, which will be converted (without modification) 161 // into compact form for RLP encoding. 162 // If the rlp data is smaller than 32 bytes, `nil` is returned. 163 func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { 164 h.tmp.Reset() 165 if err := rlp.Encode(&h.tmp, n); err != nil { 166 panic("encode error: " + err.Error()) 167 } 168 169 if len(h.tmp) < 32 && !force { 170 return n // Nodes smaller than 32 bytes are stored inside their parent 171 } 172 return h.hashData(h.tmp) 173 } 174 175 // shortnodeToHash is used to creates a hashNode from a set of hashNodes, (which 176 // may contain nil values) 177 func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { 178 h.tmp.Reset() 179 // Generate the RLP encoding of the node 180 if err := n.EncodeRLP(&h.tmp); err != nil { 181 panic("encode error: " + err.Error()) 182 } 183 184 if len(h.tmp) < 32 && !force { 185 return n // Nodes smaller than 32 bytes are stored inside their parent 186 } 187 return h.hashData(h.tmp) 188 } 189 190 // hashData hashes the provided data 191 func (h *hasher) hashData(data []byte) hashNode { 192 n := make(hashNode, 32) 193 h.sha.Reset() 194 h.sha.Write(data) 195 h.sha.Read(n) 196 return n 197 } 198 199 // proofHash is used to construct trie proofs, and returns the 'collapsed' 200 // node (for later RLP encoding) aswell as the hashed node -- unless the 201 // node is smaller than 32 bytes, in which case it will be returned as is. 202 // This method does not do anything on value- or hash-nodes. 203 func (h *hasher) proofHash(original node) (collapsed, hashed node) { 204 switch n := original.(type) { 205 case *shortNode: 206 sn, _ := h.hashShortNodeChildren(n) 207 return sn, h.shortnodeToHash(sn, false) 208 case *fullNode: 209 fn, _ := h.hashFullNodeChildren(n) 210 return fn, h.fullnodeToHash(fn, false) 211 default: 212 // Value and hash nodes don't have children so they're left as were 213 return n, n 214 } 215 }