github.com/ethereum/go-ethereum@v1.16.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/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() any { 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. 57 func (h *hasher) hash(n node, force bool) node { 58 // Return the cached hash if it's available 59 if hash, _ := n.cache(); hash != nil { 60 return hash 61 } 62 // Trie not processed yet, walk the children 63 switch n := n.(type) { 64 case *shortNode: 65 collapsed := h.hashShortNodeChildren(n) 66 hashed := h.shortnodeToHash(collapsed, force) 67 if hn, ok := hashed.(hashNode); ok { 68 n.flags.hash = hn 69 } else { 70 n.flags.hash = nil 71 } 72 return hashed 73 case *fullNode: 74 collapsed := h.hashFullNodeChildren(n) 75 hashed := h.fullnodeToHash(collapsed, force) 76 if hn, ok := hashed.(hashNode); ok { 77 n.flags.hash = hn 78 } else { 79 n.flags.hash = nil 80 } 81 return hashed 82 default: 83 // Value and hash nodes don't have children, so they're left as were 84 return n 85 } 86 } 87 88 // hashShortNodeChildren returns a copy of the supplied shortNode, with its child 89 // being replaced by either the hash or an embedded node if the child is small. 90 func (h *hasher) hashShortNodeChildren(n *shortNode) *shortNode { 91 var collapsed shortNode 92 collapsed.Key = hexToCompact(n.Key) 93 switch n.Val.(type) { 94 case *fullNode, *shortNode: 95 collapsed.Val = h.hash(n.Val, false) 96 default: 97 collapsed.Val = n.Val 98 } 99 return &collapsed 100 } 101 102 // hashFullNodeChildren returns a copy of the supplied fullNode, with its child 103 // being replaced by either the hash or an embedded node if the child is small. 104 func (h *hasher) hashFullNodeChildren(n *fullNode) *fullNode { 105 var children [17]node 106 if h.parallel { 107 var wg sync.WaitGroup 108 wg.Add(16) 109 for i := 0; i < 16; i++ { 110 go func(i int) { 111 hasher := newHasher(false) 112 if child := n.Children[i]; child != nil { 113 children[i] = hasher.hash(child, false) 114 } else { 115 children[i] = nilValueNode 116 } 117 returnHasherToPool(hasher) 118 wg.Done() 119 }(i) 120 } 121 wg.Wait() 122 } else { 123 for i := 0; i < 16; i++ { 124 if child := n.Children[i]; child != nil { 125 children[i] = h.hash(child, false) 126 } else { 127 children[i] = nilValueNode 128 } 129 } 130 } 131 if n.Children[16] != nil { 132 children[16] = n.Children[16] 133 } 134 return &fullNode{flags: nodeFlag{}, Children: children} 135 } 136 137 // shortNodeToHash computes the hash of the given shortNode. The shortNode must 138 // first be collapsed, with its key converted to compact form. If the RLP-encoded 139 // node data is smaller than 32 bytes, the node itself is returned. 140 func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { 141 n.encode(h.encbuf) 142 enc := h.encodedBytes() 143 144 if len(enc) < 32 && !force { 145 return n // Nodes smaller than 32 bytes are stored inside their parent 146 } 147 return h.hashData(enc) 148 } 149 150 // fullnodeToHash computes the hash of the given fullNode. If the RLP-encoded 151 // node data is smaller than 32 bytes, the node itself is returned. 152 func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { 153 n.encode(h.encbuf) 154 enc := h.encodedBytes() 155 156 if len(enc) < 32 && !force { 157 return n // Nodes smaller than 32 bytes are stored inside their parent 158 } 159 return h.hashData(enc) 160 } 161 162 // encodedBytes returns the result of the last encoding operation on h.encbuf. 163 // This also resets the encoder buffer. 164 // 165 // All node encoding must be done like this: 166 // 167 // node.encode(h.encbuf) 168 // enc := h.encodedBytes() 169 // 170 // This convention exists because node.encode can only be inlined/escape-analyzed when 171 // called on a concrete receiver type. 172 func (h *hasher) encodedBytes() []byte { 173 h.tmp = h.encbuf.AppendToBytes(h.tmp[:0]) 174 h.encbuf.Reset(nil) 175 return h.tmp 176 } 177 178 // hashData hashes the provided data 179 func (h *hasher) hashData(data []byte) hashNode { 180 n := make(hashNode, 32) 181 h.sha.Reset() 182 h.sha.Write(data) 183 h.sha.Read(n) 184 return n 185 } 186 187 // hashDataTo hashes the provided data to the given destination buffer. The caller 188 // must ensure that the dst buffer is of appropriate size. 189 func (h *hasher) hashDataTo(dst, data []byte) { 190 h.sha.Reset() 191 h.sha.Write(data) 192 h.sha.Read(dst) 193 } 194 195 // proofHash is used to construct trie proofs, and returns the 'collapsed' 196 // node (for later RLP encoding) as well as the hashed node -- unless the 197 // node is smaller than 32 bytes, in which case it will be returned as is. 198 // This method does not do anything on value- or hash-nodes. 199 func (h *hasher) proofHash(original node) (collapsed, hashed node) { 200 switch n := original.(type) { 201 case *shortNode: 202 sn := h.hashShortNodeChildren(n) 203 return sn, h.shortnodeToHash(sn, false) 204 case *fullNode: 205 fn := h.hashFullNodeChildren(n) 206 return fn, h.fullnodeToHash(fn, false) 207 default: 208 // Value and hash nodes don't have children, so they're left as were 209 return n, n 210 } 211 }