| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | // Copyright 2019 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package trie | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/crypto" | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/rlp" | 
					
						
							| 
									
										
										
										
											2019-01-03 16:15:26 -06:00
										 |  |  | 	"golang.org/x/crypto/sha3" | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | type sliceBuffer []byte | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (b *sliceBuffer) Write(data []byte) (n int, err error) { | 
					
						
							|  |  |  | 	*b = append(*b, data...) | 
					
						
							|  |  |  | 	return len(data), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (b *sliceBuffer) Reset() { | 
					
						
							|  |  |  | 	*b = (*b)[:0] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | // hasher is a type used for the trie Hash operation. A hasher has some | 
					
						
							|  |  |  | // internal preallocated temp space | 
					
						
							|  |  |  | type hasher struct { | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 	sha      crypto.KeccakState | 
					
						
							| 
									
										
										
										
											2020-02-04 13:02:38 +01:00
										 |  |  | 	tmp      sliceBuffer | 
					
						
							|  |  |  | 	parallel bool // Whether to use paralallel threads when hashing | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // hasherPool holds pureHashers | 
					
						
							| 
									
										
										
										
											2018-01-15 15:32:14 +02:00
										 |  |  | var hasherPool = sync.Pool{ | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	New: func() interface{} { | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 		return &hasher{ | 
					
						
							|  |  |  | 			tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode. | 
					
						
							| 
									
										
										
										
											2020-06-30 11:59:06 +02:00
										 |  |  | 			sha: sha3.NewLegacyKeccak256().(crypto.KeccakState), | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	}, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-04 13:02:38 +01:00
										 |  |  | func newHasher(parallel bool) *hasher { | 
					
						
							| 
									
										
										
										
											2018-01-15 15:32:14 +02:00
										 |  |  | 	h := hasherPool.Get().(*hasher) | 
					
						
							| 
									
										
										
										
											2020-02-04 13:02:38 +01:00
										 |  |  | 	h.parallel = parallel | 
					
						
							| 
									
										
										
										
											2016-10-14 18:04:33 +02:00
										 |  |  | 	return h | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-15 15:32:14 +02:00
										 |  |  | func returnHasherToPool(h *hasher) { | 
					
						
							|  |  |  | 	hasherPool.Put(h) | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // hash collapses a node down into a hash node, also returning a copy of the | 
					
						
							| 
									
										
										
										
											2017-06-12 14:45:17 +02:00
										 |  |  | // original node initialized with the computed hash to replace the original one. | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | func (h *hasher) hash(n node, force bool) (hashed node, cached node) { | 
					
						
							| 
									
										
										
										
											2020-09-30 19:45:56 +08:00
										 |  |  | 	// Return the cached hash if it's available | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	if hash, _ := n.cache(); hash != nil { | 
					
						
							|  |  |  | 		return hash, n | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-09-30 19:45:56 +08:00
										 |  |  | 	// Trie not processed yet, walk the children | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	switch n := n.(type) { | 
					
						
							| 
									
										
										
										
											2016-10-17 23:01:29 +02:00
										 |  |  | 	case *shortNode: | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 		collapsed, cached := h.hashShortNodeChildren(n) | 
					
						
							|  |  |  | 		hashed := h.shortnodeToHash(collapsed, force) | 
					
						
							|  |  |  | 		// We need to retain the possibly _not_ hashed node, in case it was too | 
					
						
							|  |  |  | 		// small to be hashed | 
					
						
							|  |  |  | 		if hn, ok := hashed.(hashNode); ok { | 
					
						
							|  |  |  | 			cached.flags.hash = hn | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			cached.flags.hash = nil | 
					
						
							| 
									
										
										
										
											2016-10-17 23:01:29 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 		return hashed, cached | 
					
						
							| 
									
										
										
										
											2016-10-17 23:01:29 +02:00
										 |  |  | 	case *fullNode: | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 		collapsed, cached := h.hashFullNodeChildren(n) | 
					
						
							|  |  |  | 		hashed = h.fullnodeToHash(collapsed, force) | 
					
						
							|  |  |  | 		if hn, ok := hashed.(hashNode); ok { | 
					
						
							|  |  |  | 			cached.flags.hash = hn | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			cached.flags.hash = nil | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 		return hashed, cached | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// Value and hash nodes don't have children so they're left as were | 
					
						
							|  |  |  | 		return n, n | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | // hashShortNodeChildren collapses the short node. The returned collapsed node | 
					
						
							|  |  |  | // holds a live reference to the Key, and must not be modified. | 
					
						
							|  |  |  | // The cached | 
					
						
							|  |  |  | func (h *hasher) hashShortNodeChildren(n *shortNode) (collapsed, cached *shortNode) { | 
					
						
							|  |  |  | 	// Hash the short node's child, caching the newly hashed subtree | 
					
						
							|  |  |  | 	collapsed, cached = n.copy(), n.copy() | 
					
						
							|  |  |  | 	// Previously, we did copy this one. We don't seem to need to actually | 
					
						
							|  |  |  | 	// do that, since we don't overwrite/reuse keys | 
					
						
							|  |  |  | 	//cached.Key = common.CopyBytes(n.Key) | 
					
						
							|  |  |  | 	collapsed.Key = hexToCompact(n.Key) | 
					
						
							|  |  |  | 	// Unless the child is a valuenode or hashnode, hash it | 
					
						
							|  |  |  | 	switch n.Val.(type) { | 
					
						
							|  |  |  | 	case *fullNode, *shortNode: | 
					
						
							|  |  |  | 		collapsed.Val, cached.Val = h.hash(n.Val, false) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return collapsed, cached | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | func (h *hasher) hashFullNodeChildren(n *fullNode) (collapsed *fullNode, cached *fullNode) { | 
					
						
							|  |  |  | 	// Hash the full node's children, caching the newly hashed subtrees | 
					
						
							|  |  |  | 	cached = n.copy() | 
					
						
							|  |  |  | 	collapsed = n.copy() | 
					
						
							| 
									
										
										
										
											2020-02-04 13:02:38 +01:00
										 |  |  | 	if h.parallel { | 
					
						
							|  |  |  | 		var wg sync.WaitGroup | 
					
						
							|  |  |  | 		wg.Add(16) | 
					
						
							|  |  |  | 		for i := 0; i < 16; i++ { | 
					
						
							|  |  |  | 			go func(i int) { | 
					
						
							|  |  |  | 				hasher := newHasher(false) | 
					
						
							|  |  |  | 				if child := n.Children[i]; child != nil { | 
					
						
							|  |  |  | 					collapsed.Children[i], cached.Children[i] = hasher.hash(child, false) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					collapsed.Children[i] = nilValueNode | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				returnHasherToPool(hasher) | 
					
						
							|  |  |  | 				wg.Done() | 
					
						
							|  |  |  | 			}(i) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		wg.Wait() | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		for i := 0; i < 16; i++ { | 
					
						
							|  |  |  | 			if child := n.Children[i]; child != nil { | 
					
						
							|  |  |  | 				collapsed.Children[i], cached.Children[i] = h.hash(child, false) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				collapsed.Children[i] = nilValueNode | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	return collapsed, cached | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | // shortnodeToHash creates a hashNode from a shortNode. The supplied shortnode | 
					
						
							|  |  |  | // should have hex-type Key, which will be converted (without modification) | 
					
						
							|  |  |  | // into compact form for RLP encoding. | 
					
						
							|  |  |  | // If the rlp data is smaller than 32 bytes, `nil` is returned. | 
					
						
							|  |  |  | func (h *hasher) shortnodeToHash(n *shortNode, force bool) node { | 
					
						
							| 
									
										
										
										
											2018-01-15 15:32:14 +02:00
										 |  |  | 	h.tmp.Reset() | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 	if err := rlp.Encode(&h.tmp, n); err != nil { | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 		panic("encode error: " + err.Error()) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 	if len(h.tmp) < 32 && !force { | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 		return n // Nodes smaller than 32 bytes are stored inside their parent | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	return h.hashData(h.tmp) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // shortnodeToHash is used to creates a hashNode from a set of hashNodes, (which | 
					
						
							|  |  |  | // may contain nil values) | 
					
						
							|  |  |  | func (h *hasher) fullnodeToHash(n *fullNode, force bool) node { | 
					
						
							|  |  |  | 	h.tmp.Reset() | 
					
						
							|  |  |  | 	// Generate the RLP encoding of the node | 
					
						
							|  |  |  | 	if err := n.EncodeRLP(&h.tmp); err != nil { | 
					
						
							|  |  |  | 		panic("encode error: " + err.Error()) | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	if len(h.tmp) < 32 && !force { | 
					
						
							|  |  |  | 		return n // Nodes smaller than 32 bytes are stored inside their parent | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 	return h.hashData(h.tmp) | 
					
						
							| 
									
										
										
										
											2016-09-25 20:49:02 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | // hashData hashes the provided data | 
					
						
							|  |  |  | func (h *hasher) hashData(data []byte) hashNode { | 
					
						
							|  |  |  | 	n := make(hashNode, 32) | 
					
						
							| 
									
										
										
										
											2018-06-05 14:06:29 +02:00
										 |  |  | 	h.sha.Reset() | 
					
						
							|  |  |  | 	h.sha.Write(data) | 
					
						
							|  |  |  | 	h.sha.Read(n) | 
					
						
							|  |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2020-02-03 16:28:30 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // proofHash is used to construct trie proofs, and returns the 'collapsed' | 
					
						
							|  |  |  | // node (for later RLP encoding) aswell as the hashed node -- unless the | 
					
						
							|  |  |  | // node is smaller than 32 bytes, in which case it will be returned as is. | 
					
						
							|  |  |  | // This method does not do anything on value- or hash-nodes. | 
					
						
							|  |  |  | func (h *hasher) proofHash(original node) (collapsed, hashed node) { | 
					
						
							|  |  |  | 	switch n := original.(type) { | 
					
						
							|  |  |  | 	case *shortNode: | 
					
						
							|  |  |  | 		sn, _ := h.hashShortNodeChildren(n) | 
					
						
							|  |  |  | 		return sn, h.shortnodeToHash(sn, false) | 
					
						
							|  |  |  | 	case *fullNode: | 
					
						
							|  |  |  | 		fn, _ := h.hashFullNodeChildren(n) | 
					
						
							|  |  |  | 		return fn, h.fullnodeToHash(fn, false) | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		// Value and hash nodes don't have children so they're left as were | 
					
						
							|  |  |  | 		return n, n | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |