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