github.com/gochain-io/gochain@v2.2.26+incompatible/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  	"hash"
    21  	"sync"
    22  
    23  	"github.com/gochain-io/gochain/common"
    24  	"github.com/gochain-io/gochain/crypto/sha3"
    25  	"github.com/gochain-io/gochain/rlp"
    26  )
    27  
    28  type hasher struct {
    29  	tmp        sliceBuffer
    30  	sha        keccakState
    31  	cachegen   uint16
    32  	cachelimit uint16
    33  	onleaf     LeafCallback
    34  }
    35  
    36  // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
    37  // Read to get a variable amount of data from the hash state. Read is faster than Sum
    38  // because it doesn't copy the internal state, but also modifies the internal state.
    39  type keccakState interface {
    40  	hash.Hash
    41  	Read([]byte) (int, error)
    42  }
    43  
    44  type sliceBuffer []byte
    45  
    46  func (b *sliceBuffer) Write(data []byte) (n int, err error) {
    47  	*b = append(*b, data...)
    48  	return len(data), nil
    49  }
    50  
    51  func (b *sliceBuffer) Reset() {
    52  	*b = (*b)[:0]
    53  }
    54  
    55  // hashers live in a global db.
    56  var hasherPool = sync.Pool{
    57  	New: func() interface{} {
    58  		return &hasher{
    59  			tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode.
    60  			sha: sha3.NewKeccak256().(keccakState),
    61  		}
    62  	},
    63  }
    64  
    65  func newHasher(cachegen, cachelimit uint16, onleaf LeafCallback) *hasher {
    66  	h := hasherPool.Get().(*hasher)
    67  	h.cachegen, h.cachelimit, h.onleaf = cachegen, cachelimit, onleaf
    68  	return h
    69  }
    70  
    71  func returnHasherToPool(h *hasher) {
    72  	hasherPool.Put(h)
    73  }
    74  
    75  // hash collapses a node down into a hash node, also returning a copy of the
    76  // original node initialized with the computed hash to replace the original one.
    77  func (h *hasher) hash(n node, db *Database, force bool) (node, node, error) {
    78  	// If we're not storing the node, just hashing, use available cached data
    79  	if hash, dirty := n.cache(); hash != nil {
    80  		if db == nil {
    81  			return hash, n, nil
    82  		}
    83  		if n.canUnload(h.cachegen, h.cachelimit) {
    84  			// Unload the node from cache. All of its subnodes will have a lower or equal
    85  			// cache generation number.
    86  			cacheUnloadCounter.Inc(1)
    87  			return hash, hash, nil
    88  		}
    89  		if !dirty {
    90  			return hash, n, nil
    91  		}
    92  	}
    93  	// Trie not processed yet or needs storage, walk the children
    94  	collapsed, cached, err := h.hashChildren(n, db)
    95  	if err != nil {
    96  		return hashNode{}, n, err
    97  	}
    98  	hashed, err := h.store(collapsed, db, force)
    99  	if err != nil {
   100  		return hashNode{}, n, err
   101  	}
   102  	// Cache the hash of the node for later reuse and remove
   103  	// the dirty flag in commit mode. It's fine to assign these values directly
   104  	// without copying the node first because hashChildren copies it.
   105  	cachedHash, _ := hashed.(hashNode)
   106  	switch cn := cached.(type) {
   107  	case *shortNode:
   108  		cn.flags.hash = cachedHash
   109  		if db != nil {
   110  			cn.flags.dirty = false
   111  		}
   112  	case *fullNode:
   113  		cn.flags.hash = cachedHash
   114  		if db != nil {
   115  			cn.flags.dirty = false
   116  		}
   117  	}
   118  	return hashed, cached, nil
   119  }
   120  
   121  // hashChildren replaces the children of a node with their hashes if the encoded
   122  // size of the child is larger than a hash, returning the collapsed node as well
   123  // as a replacement for the original node with the child hashes cached in.
   124  func (h *hasher) hashChildren(original node, db *Database) (node, node, error) {
   125  	var err error
   126  
   127  	switch n := original.(type) {
   128  	case *shortNode:
   129  		// Hash the short node's child, caching the newly hashed subtree
   130  		collapsed, cached := n.copy(), n.copy()
   131  		collapsed.Key = hexToCompact(n.Key)
   132  		cached.Key = common.CopyBytes(n.Key)
   133  
   134  		if _, ok := n.Val.(valueNode); !ok {
   135  			collapsed.Val, cached.Val, err = h.hash(n.Val, db, false)
   136  			if err != nil {
   137  				return original, original, err
   138  			}
   139  		}
   140  		return collapsed, cached, nil
   141  
   142  	case *fullNode:
   143  		// Hash the full node's children, caching the newly hashed subtrees
   144  		collapsed, cached := n.copy(), n.copy()
   145  
   146  		for i := 0; i < 16; i++ {
   147  			if n.Children[i] != nil {
   148  				collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false)
   149  				if err != nil {
   150  					return original, original, err
   151  				}
   152  			}
   153  		}
   154  		cached.Children[16] = n.Children[16]
   155  		return collapsed, cached, nil
   156  
   157  	default:
   158  		// Value and hash nodes don't have children so they're left as were
   159  		return n, original, nil
   160  	}
   161  }
   162  
   163  // store hashes the node n and if we have a storage layer specified, it writes
   164  // the key/value pair to it and tracks any node->child references as well as any
   165  // node->external trie references.
   166  func (h *hasher) store(n node, db *Database, force bool) (node, error) {
   167  	// Don't store hashes or empty nodes.
   168  	if _, isHash := n.(hashNode); n == nil || isHash {
   169  		return n, nil
   170  	}
   171  	// Generate the RLP encoding of the node
   172  	h.tmp.Reset()
   173  	if err := rlp.Encode(&h.tmp, n); err != nil {
   174  		panic("encode error: " + err.Error())
   175  	}
   176  	if len(h.tmp) < 32 && !force {
   177  		return n, nil // Nodes smaller than 32 bytes are stored inside their parent
   178  	}
   179  	// Larger nodes are replaced by their hash and stored in the database.
   180  	hash, _ := n.cache()
   181  	if hash == nil {
   182  		hash = h.makeHashNode(h.tmp)
   183  	}
   184  
   185  	if db != nil {
   186  		// We are pooling the trie nodes into an intermediate memory cache
   187  		hash := common.BytesToHash(hash)
   188  
   189  		db.lock.Lock()
   190  		db.insert(hash, h.tmp, n)
   191  		db.lock.Unlock()
   192  
   193  		// Track external references from account->storage trie
   194  		if h.onleaf != nil {
   195  			switch n := n.(type) {
   196  			case *shortNode:
   197  				if child, ok := n.Val.(valueNode); ok {
   198  					h.onleaf(child, hash)
   199  				}
   200  			case *fullNode:
   201  				for i := 0; i < 16; i++ {
   202  					if child, ok := n.Children[i].(valueNode); ok {
   203  						h.onleaf(child, hash)
   204  					}
   205  				}
   206  			}
   207  		}
   208  	}
   209  	return hash, nil
   210  }
   211  
   212  func (h *hasher) makeHashNode(data []byte) hashNode {
   213  	n := make(hashNode, h.sha.Size())
   214  	h.sha.Reset()
   215  	h.sha.Write(data)
   216  	h.sha.Read(n)
   217  	return n
   218  }