github.com/klaytn/klaytn@v1.10.2/storage/statedb/hasher.go (about)

     1  // Modifications Copyright 2018 The klaytn Authors
     2  // Copyright 2015 The go-ethereum Authors
     3  // This file is part of the go-ethereum library.
     4  //
     5  // The go-ethereum library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU Lesser General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // The go-ethereum library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    13  // GNU Lesser General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public License
    16  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  // This file is derived from trie/hasher.go (2018/06/04).
    19  // Modified and improved for the klaytn development.
    20  
    21  package statedb
    22  
    23  import (
    24  	"hash"
    25  	"sync"
    26  
    27  	"github.com/klaytn/klaytn/common"
    28  	"github.com/klaytn/klaytn/crypto/sha3"
    29  	"github.com/klaytn/klaytn/rlp"
    30  )
    31  
    32  type hasher struct {
    33  	tmp    sliceBuffer
    34  	sha    KeccakState
    35  	onleaf LeafCallback
    36  }
    37  
    38  // KeccakState wraps sha3.state. In addition to the usual hash methods, it also supports
    39  // Read to get a variable amount of data from the hash state. Read is faster than Sum
    40  // because it doesn't copy the internal state, but also modifies the internal state.
    41  type KeccakState interface {
    42  	hash.Hash
    43  	Read([]byte) (int, error)
    44  }
    45  
    46  type sliceBuffer []byte
    47  
    48  func (b *sliceBuffer) Write(data []byte) (n int, err error) {
    49  	*b = append(*b, data...)
    50  	return len(data), nil
    51  }
    52  
    53  func (b *sliceBuffer) Reset() {
    54  	*b = (*b)[:0]
    55  }
    56  
    57  // hashers live in a global db.
    58  var hasherPool = sync.Pool{
    59  	New: func() interface{} {
    60  		return &hasher{
    61  			tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode.
    62  			sha: sha3.NewKeccak256().(KeccakState),
    63  		}
    64  	},
    65  }
    66  
    67  func newHasher(onleaf LeafCallback) *hasher {
    68  	h := hasherPool.Get().(*hasher)
    69  	h.onleaf = onleaf
    70  	return h
    71  }
    72  
    73  func returnHasherToPool(h *hasher) {
    74  	hasherPool.Put(h)
    75  }
    76  
    77  // hash collapses a node down into a hash node, also returning a copy of the
    78  // original node initialized with the computed hash to replace the original one.
    79  func (h *hasher) hash(n node, db *Database, force bool) (node, node) {
    80  	// If we're not storing the node, just hashing, use available cached data
    81  	if hash, dirty := n.cache(); hash != nil {
    82  		if db == nil {
    83  			return hash, n
    84  		}
    85  		if !dirty {
    86  			switch n.(type) {
    87  			case *fullNode, *shortNode:
    88  				return hash, hash
    89  			default:
    90  				return hash, n
    91  			}
    92  		}
    93  	}
    94  	// Trie not processed yet or needs storage, walk the children
    95  	collapsed, cached := h.hashChildren(n, db)
    96  	hashed, lenEncoded := h.store(collapsed, db, force)
    97  	// Cache the hash of the node for later reuse and remove
    98  	// the dirty flag in commit mode. It's fine to assign these values directly
    99  	// without copying the node first because hashChildren copies it.
   100  	cachedHash, _ := hashed.(hashNode)
   101  	switch cn := cached.(type) {
   102  	case *shortNode:
   103  		cn.flags.hash = cachedHash
   104  		cn.flags.lenEncoded = lenEncoded
   105  		if db != nil {
   106  			cn.flags.dirty = false
   107  		}
   108  	case *fullNode:
   109  		cn.flags.hash = cachedHash
   110  		cn.flags.lenEncoded = lenEncoded
   111  		if db != nil {
   112  			cn.flags.dirty = false
   113  		}
   114  	}
   115  	return hashed, cached
   116  }
   117  
   118  func (h *hasher) hashRoot(n node, db *Database, force bool) (node, node) {
   119  	// If we're not storing the node, just hashing, use available cached data
   120  	if hash, dirty := n.cache(); hash != nil {
   121  		if db == nil {
   122  			return hash, n
   123  		}
   124  		if !dirty {
   125  			switch n.(type) {
   126  			case *fullNode, *shortNode:
   127  				return hash, hash
   128  			default:
   129  				return hash, n
   130  			}
   131  		}
   132  	}
   133  	// Trie not processed yet or needs storage, walk the children
   134  	collapsed, cached := h.hashChildrenFromRoot(n, db)
   135  	hashed, lenEncoded := h.store(collapsed, db, force)
   136  	// Cache the hash of the node for later reuse and remove
   137  	// the dirty flag in commit mode. It's fine to assign these values directly
   138  	// without copying the node first because hashChildren copies it.
   139  	cachedHash, _ := hashed.(hashNode)
   140  	switch cn := cached.(type) {
   141  	case *shortNode:
   142  		cn.flags.hash = cachedHash
   143  		cn.flags.lenEncoded = lenEncoded
   144  		if db != nil {
   145  			cn.flags.dirty = false
   146  		}
   147  	case *fullNode:
   148  		cn.flags.hash = cachedHash
   149  		cn.flags.lenEncoded = lenEncoded
   150  		if db != nil {
   151  			cn.flags.dirty = false
   152  		}
   153  	}
   154  	return hashed, cached
   155  }
   156  
   157  // hashChildren replaces the children of a node with their hashes if the encoded
   158  // size of the child is larger than a hash, returning the collapsed node as well
   159  // as a replacement for the original node with the child hashes cached in.
   160  func (h *hasher) hashChildren(original node, db *Database) (node, node) {
   161  	switch n := original.(type) {
   162  	case *shortNode:
   163  		// Hash the short node's child, caching the newly hashed subtree
   164  		collapsed, cached := n.copy(), n.copy()
   165  		collapsed.Key = hexToCompact(n.Key)
   166  		cached.Key = common.CopyBytes(n.Key)
   167  
   168  		if _, ok := n.Val.(valueNode); !ok {
   169  			collapsed.Val, cached.Val = h.hash(n.Val, db, false)
   170  		}
   171  		return collapsed, cached
   172  
   173  	case *fullNode:
   174  		// Hash the full node's children, caching the newly hashed subtrees
   175  		collapsed, cached := n.copy(), n.copy()
   176  
   177  		for i := 0; i < 16; i++ {
   178  			if n.Children[i] != nil {
   179  				collapsed.Children[i], cached.Children[i] = h.hash(n.Children[i], db, false)
   180  			}
   181  		}
   182  		cached.Children[16] = n.Children[16]
   183  		return collapsed, cached
   184  
   185  	default:
   186  		// Value and hash nodes don't have children so they're left as were
   187  		return n, original
   188  	}
   189  }
   190  
   191  type hashResult struct {
   192  	index     int
   193  	collapsed node
   194  	cached    node
   195  }
   196  
   197  func (h *hasher) hashChildrenFromRoot(original node, db *Database) (node, node) {
   198  	switch n := original.(type) {
   199  	case *shortNode:
   200  		// Hash the short node's child, caching the newly hashed subtree
   201  		collapsed, cached := n.copy(), n.copy()
   202  		collapsed.Key = hexToCompact(n.Key)
   203  		cached.Key = common.CopyBytes(n.Key)
   204  
   205  		if _, ok := n.Val.(valueNode); !ok {
   206  			collapsed.Val, cached.Val = h.hash(n.Val, db, false)
   207  		}
   208  		return collapsed, cached
   209  
   210  	case *fullNode:
   211  		// Hash the full node's children, caching the newly hashed subtrees
   212  		collapsed, cached := n.copy(), n.copy()
   213  
   214  		hashResultCh := make(chan hashResult, 16)
   215  		numRootChildren := 0
   216  		for i := 0; i < 16; i++ {
   217  			if n.Children[i] != nil {
   218  				numRootChildren++
   219  				go func(i int, n node) {
   220  					childHasher := newHasher(h.onleaf)
   221  					defer returnHasherToPool(childHasher)
   222  					collapsedFromChild, cachedFromChild := childHasher.hash(n, db, false)
   223  					hashResultCh <- hashResult{i, collapsedFromChild, cachedFromChild}
   224  				}(i, n.Children[i])
   225  			}
   226  		}
   227  
   228  		for i := 0; i < numRootChildren; i++ {
   229  			hashResult := <-hashResultCh
   230  			idx := hashResult.index
   231  			collapsed.Children[idx], cached.Children[idx] = hashResult.collapsed, hashResult.cached
   232  		}
   233  
   234  		cached.Children[16] = n.Children[16]
   235  		return collapsed, cached
   236  
   237  	default:
   238  		// Value and hash nodes don't have children so they're left as were
   239  		return n, original
   240  	}
   241  }
   242  
   243  // store hashes the node n and if we have a storage layer specified, it writes
   244  // the key/value pair to it and tracks any node->child references as well as any
   245  // node->external trie references.
   246  func (h *hasher) store(n node, db *Database, force bool) (node, uint16) {
   247  	// Don't store hashes or empty nodes.
   248  	if _, isHash := n.(hashNode); n == nil || isHash {
   249  		return n, 0
   250  	}
   251  	hash, _ := n.cache()
   252  	lenEncoded := n.lenEncoded()
   253  	if hash == nil || lenEncoded == 0 {
   254  		// Generate the RLP encoding of the node
   255  		h.tmp.Reset()
   256  		if err := rlp.Encode(&h.tmp, n); err != nil {
   257  			panic("encode error: " + err.Error())
   258  		}
   259  
   260  		lenEncoded = uint16(len(h.tmp))
   261  	}
   262  	if lenEncoded < 32 && !force {
   263  		return n, lenEncoded // Nodes smaller than 32 bytes are stored inside their parent
   264  	}
   265  	if hash == nil {
   266  		hash = h.makeHashNode(h.tmp)
   267  	}
   268  	if db != nil {
   269  		// We are pooling the trie nodes into an intermediate memory cache
   270  		hash := common.BytesToHash(hash)
   271  
   272  		db.lock.Lock()
   273  		db.insert(hash, lenEncoded, n)
   274  		db.lock.Unlock()
   275  
   276  		// Track external references from account->storage trie
   277  		if h.onleaf != nil {
   278  			switch n := n.(type) {
   279  			case *shortNode:
   280  				if child, ok := n.Val.(valueNode); ok {
   281  					h.onleaf(nil, nil, child, hash, 0)
   282  				}
   283  			case *fullNode:
   284  				for i := 0; i < 16; i++ {
   285  					if child, ok := n.Children[i].(valueNode); ok {
   286  						h.onleaf(nil, nil, child, hash, 0)
   287  					}
   288  				}
   289  			}
   290  		}
   291  	}
   292  	return hash, lenEncoded
   293  }
   294  
   295  func (h *hasher) makeHashNode(data []byte) hashNode {
   296  	n := make(hashNode, h.sha.Size())
   297  	h.sha.Reset()
   298  	h.sha.Write(data)
   299  	h.sha.Read(n)
   300  	return n
   301  }