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  }