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