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