github.com/myafeier/go-ethereum@v1.6.8-0.20170719123245-3e0dbe0eaa72/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  	"bytes"
    21  	"hash"
    22  	"sync"
    23  
    24  	"github.com/ethereum/go-ethereum/common"
    25  	"github.com/ethereum/go-ethereum/crypto/sha3"
    26  	"github.com/ethereum/go-ethereum/rlp"
    27  )
    28  
    29  type hasher struct {
    30  	tmp                  *bytes.Buffer
    31  	sha                  hash.Hash
    32  	cachegen, cachelimit uint16
    33  }
    34  
    35  // hashers live in a global pool.
    36  var hasherPool = sync.Pool{
    37  	New: func() interface{} {
    38  		return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()}
    39  	},
    40  }
    41  
    42  func newHasher(cachegen, cachelimit uint16) *hasher {
    43  	h := hasherPool.Get().(*hasher)
    44  	h.cachegen, h.cachelimit = cachegen, cachelimit
    45  	return h
    46  }
    47  
    48  func returnHasherToPool(h *hasher) {
    49  	hasherPool.Put(h)
    50  }
    51  
    52  // hash collapses a node down into a hash node, also returning a copy of the
    53  // original node initialized with the computed hash to replace the original one.
    54  func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) {
    55  	// If we're not storing the node, just hashing, use available cached data
    56  	if hash, dirty := n.cache(); hash != nil {
    57  		if db == nil {
    58  			return hash, n, nil
    59  		}
    60  		if n.canUnload(h.cachegen, h.cachelimit) {
    61  			// Unload the node from cache. All of its subnodes will have a lower or equal
    62  			// cache generation number.
    63  			cacheUnloadCounter.Inc(1)
    64  			return hash, hash, nil
    65  		}
    66  		if !dirty {
    67  			return hash, n, nil
    68  		}
    69  	}
    70  	// Trie not processed yet or needs storage, walk the children
    71  	collapsed, cached, err := h.hashChildren(n, db)
    72  	if err != nil {
    73  		return hashNode{}, n, err
    74  	}
    75  	hashed, err := h.store(collapsed, db, force)
    76  	if err != nil {
    77  		return hashNode{}, n, err
    78  	}
    79  	// Cache the hash of the ndoe for later reuse and remove
    80  	// the dirty flag in commit mode. It's fine to assign these values directly
    81  	// without copying the node first because hashChildren copies it.
    82  	cachedHash, _ := hashed.(hashNode)
    83  	switch cn := cached.(type) {
    84  	case *shortNode:
    85  		cn.flags.hash = cachedHash
    86  		if db != nil {
    87  			cn.flags.dirty = false
    88  		}
    89  	case *fullNode:
    90  		cn.flags.hash = cachedHash
    91  		if db != nil {
    92  			cn.flags.dirty = false
    93  		}
    94  	}
    95  	return hashed, cached, nil
    96  }
    97  
    98  // hashChildren replaces the children of a node with their hashes if the encoded
    99  // size of the child is larger than a hash, returning the collapsed node as well
   100  // as a replacement for the original node with the child hashes cached in.
   101  func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, error) {
   102  	var err error
   103  
   104  	switch n := original.(type) {
   105  	case *shortNode:
   106  		// Hash the short node's child, caching the newly hashed subtree
   107  		collapsed, cached := n.copy(), n.copy()
   108  		collapsed.Key = hexToCompact(n.Key)
   109  		cached.Key = common.CopyBytes(n.Key)
   110  
   111  		if _, ok := n.Val.(valueNode); !ok {
   112  			collapsed.Val, cached.Val, err = h.hash(n.Val, db, false)
   113  			if err != nil {
   114  				return original, original, err
   115  			}
   116  		}
   117  		if collapsed.Val == nil {
   118  			collapsed.Val = valueNode(nil) // Ensure that nil children are encoded as empty strings.
   119  		}
   120  		return collapsed, cached, nil
   121  
   122  	case *fullNode:
   123  		// Hash the full node's children, caching the newly hashed subtrees
   124  		collapsed, cached := n.copy(), n.copy()
   125  
   126  		for i := 0; i < 16; i++ {
   127  			if n.Children[i] != nil {
   128  				collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false)
   129  				if err != nil {
   130  					return original, original, err
   131  				}
   132  			} else {
   133  				collapsed.Children[i] = valueNode(nil) // Ensure that nil children are encoded as empty strings.
   134  			}
   135  		}
   136  		cached.Children[16] = n.Children[16]
   137  		if collapsed.Children[16] == nil {
   138  			collapsed.Children[16] = valueNode(nil)
   139  		}
   140  		return collapsed, cached, nil
   141  
   142  	default:
   143  		// Value and hash nodes don't have children so they're left as were
   144  		return n, original, nil
   145  	}
   146  }
   147  
   148  func (h *hasher) store(n node, db DatabaseWriter, force bool) (node, error) {
   149  	// Don't store hashes or empty nodes.
   150  	if _, isHash := n.(hashNode); n == nil || isHash {
   151  		return n, nil
   152  	}
   153  	// Generate the RLP encoding of the node
   154  	h.tmp.Reset()
   155  	if err := rlp.Encode(h.tmp, n); err != nil {
   156  		panic("encode error: " + err.Error())
   157  	}
   158  
   159  	if h.tmp.Len() < 32 && !force {
   160  		return n, nil // Nodes smaller than 32 bytes are stored inside their parent
   161  	}
   162  	// Larger nodes are replaced by their hash and stored in the database.
   163  	hash, _ := n.cache()
   164  	if hash == nil {
   165  		h.sha.Reset()
   166  		h.sha.Write(h.tmp.Bytes())
   167  		hash = hashNode(h.sha.Sum(nil))
   168  	}
   169  	if db != nil {
   170  		return hash, db.Put(hash, h.tmp.Bytes())
   171  	}
   172  	return hash, nil
   173  }