github.com/cgcardona/r-subnet-evm@v0.1.5/trie/hasher.go (about) 1 // (c) 2020-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2016 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package trie 28 29 import ( 30 "sync" 31 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/rlp" 34 "golang.org/x/crypto/sha3" 35 ) 36 37 // hasher is a type used for the trie Hash operation. A hasher has some 38 // internal preallocated temp space 39 type hasher struct { 40 sha crypto.KeccakState 41 tmp []byte 42 encbuf rlp.EncoderBuffer 43 parallel bool // Whether to use parallel threads when hashing 44 } 45 46 // hasherPool holds pureHashers 47 var hasherPool = sync.Pool{ 48 New: func() interface{} { 49 return &hasher{ 50 tmp: make([]byte, 0, 550), // cap is as large as a full fullNode. 51 sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), 52 encbuf: rlp.NewEncoderBuffer(nil), 53 } 54 }, 55 } 56 57 func newHasher(parallel bool) *hasher { 58 h := hasherPool.Get().(*hasher) 59 h.parallel = parallel 60 return h 61 } 62 63 func returnHasherToPool(h *hasher) { 64 hasherPool.Put(h) 65 } 66 67 // hash collapses a node down into a hash node, also returning a copy of the 68 // original node initialized with the computed hash to replace the original one. 69 func (h *hasher) hash(n node, force bool) (hashed node, cached node) { 70 // Return the cached hash if it's available 71 if hash, _ := n.cache(); hash != nil { 72 return hash, n 73 } 74 // Trie not processed yet, walk the children 75 switch n := n.(type) { 76 case *shortNode: 77 collapsed, cached := h.hashShortNodeChildren(n) 78 hashed := h.shortnodeToHash(collapsed, force) 79 // We need to retain the possibly _not_ hashed node, in case it was too 80 // small to be hashed 81 if hn, ok := hashed.(hashNode); ok { 82 cached.flags.hash = hn 83 } else { 84 cached.flags.hash = nil 85 } 86 return hashed, cached 87 case *fullNode: 88 collapsed, cached := h.hashFullNodeChildren(n) 89 hashed = h.fullnodeToHash(collapsed, force) 90 if hn, ok := hashed.(hashNode); ok { 91 cached.flags.hash = hn 92 } else { 93 cached.flags.hash = nil 94 } 95 return hashed, cached 96 default: 97 // Value and hash nodes don't have children so they're left as were 98 return n, n 99 } 100 } 101 102 // hashShortNodeChildren collapses the short node. The returned collapsed node 103 // holds a live reference to the Key, and must not be modified. 104 // The cached 105 func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { 106 // Hash the short node's child, caching the newly hashed subtree 107 collapsed, cached = n.copy(), n.copy() 108 // Previously, we did copy this one. We don't seem to need to actually 109 // do that, since we don't overwrite/reuse keys 110 //cached.Key = common.CopyBytes(n.Key) 111 collapsed.Key = hexToCompact(n.Key) 112 // Unless the child is a valuenode or hashnode, hash it 113 switch n.Val.(type) { 114 case *fullNode, *shortNode: 115 collapsed.Val, cached.Val = h.hash(n.Val, false) 116 } 117 return collapsed, cached 118 } 119 120 func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { 121 // Hash the full node's children, caching the newly hashed subtrees 122 cached = n.copy() 123 collapsed = n.copy() 124 if h.parallel { 125 var wg sync.WaitGroup 126 wg.Add(16) 127 for i := 0; i < 16; i++ { 128 go func(i int) { 129 hasher := newHasher(false) 130 if child := n.Children[i]; child != nil { 131 collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) 132 } else { 133 collapsed.Children[i] = nilValueNode 134 } 135 returnHasherToPool(hasher) 136 wg.Done() 137 }(i) 138 } 139 wg.Wait() 140 } else { 141 for i := 0; i < 16; i++ { 142 if child := n.Children[i]; child != nil { 143 collapsed.Children[i], cached.Children[i] = h.hash(child, false) 144 } else { 145 collapsed.Children[i] = nilValueNode 146 } 147 } 148 } 149 return collapsed, cached 150 } 151 152 // shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode 153 // should have hex-type Key, which will be converted (without modification) 154 // into compact form for RLP encoding. 155 // If the rlp data is smaller than 32 bytes, `nil` is returned. 156 func (h *hasher) shortnodeToHash(n *shortNode, 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 // shortnodeToHash is used to creates a hashNode from a set of hashNodes, (which 167 // may contain nil values) 168 func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { 169 n.encode(h.encbuf) 170 enc := h.encodedBytes() 171 172 if len(enc) < 32 && !force { 173 return n // Nodes smaller than 32 bytes are stored inside their parent 174 } 175 return h.hashData(enc) 176 } 177 178 // encodedBytes returns the result of the last encoding operation on h.encbuf. 179 // This also resets the encoder buffer. 180 // 181 // All node encoding must be done like this: 182 // 183 // node.encode(h.encbuf) 184 // enc := h.encodedBytes() 185 // 186 // This convention exists because node.encode can only be inlined/escape-analyzed when 187 // called on a concrete receiver type. 188 func (h *hasher) encodedBytes() []byte { 189 h.tmp = h.encbuf.AppendToBytes(h.tmp[:0]) 190 h.encbuf.Reset(nil) 191 return h.tmp 192 } 193 194 // hashData hashes the provided data 195 func (h *hasher) hashData(data []byte) hashNode { 196 n := make(hashNode, 32) 197 h.sha.Reset() 198 h.sha.Write(data) 199 h.sha.Read(n) 200 return n 201 } 202 203 // proofHash is used to construct trie proofs, and returns the 'collapsed' 204 // node (for later RLP encoding) as well as the hashed node -- unless the 205 // node is smaller than 32 bytes, in which case it will be returned as is. 206 // This method does not do anything on value- or hash-nodes. 207 func (h *hasher) proofHash(original node) (collapsed, hashed node) { 208 switch n := original.(type) { 209 case *shortNode: 210 sn, _ := h.hashShortNodeChildren(n) 211 return sn, h.shortnodeToHash(sn, false) 212 case *fullNode: 213 fn, _ := h.hashFullNodeChildren(n) 214 return fn, h.fullnodeToHash(fn, false) 215 default: 216 // Value and hash nodes don't have children so they're left as were 217 return n, n 218 } 219 }