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