github.com/theQRL/go-zond@v0.1.1/trie/committer.go (about)

     1  // Copyright 2020 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  	"fmt"
    21  
    22  	"github.com/theQRL/go-zond/common"
    23  	"github.com/theQRL/go-zond/trie/trienode"
    24  )
    25  
    26  // committer is the tool used for the trie Commit operation. The committer will
    27  // capture all dirty nodes during the commit process and keep them cached in
    28  // insertion order.
    29  type committer struct {
    30  	nodes       *trienode.NodeSet
    31  	tracer      *tracer
    32  	collectLeaf bool
    33  }
    34  
    35  // newCommitter creates a new committer or picks one from the pool.
    36  func newCommitter(nodeset *trienode.NodeSet, tracer *tracer, collectLeaf bool) *committer {
    37  	return &committer{
    38  		nodes:       nodeset,
    39  		tracer:      tracer,
    40  		collectLeaf: collectLeaf,
    41  	}
    42  }
    43  
    44  // Commit collapses a node down into a hash node.
    45  func (c *committer) Commit(n node) hashNode {
    46  	return c.commit(nil, n).(hashNode)
    47  }
    48  
    49  // commit collapses a node down into a hash node and returns it.
    50  func (c *committer) commit(path []byte, n node) node {
    51  	// if this path is clean, use available cached data
    52  	hash, dirty := n.cache()
    53  	if hash != nil && !dirty {
    54  		return hash
    55  	}
    56  	// Commit children, then parent, and remove the dirty flag.
    57  	switch cn := n.(type) {
    58  	case *shortNode:
    59  		// Commit child
    60  		collapsed := cn.copy()
    61  
    62  		// If the child is fullNode, recursively commit,
    63  		// otherwise it can only be hashNode or valueNode.
    64  		if _, ok := cn.Val.(*fullNode); ok {
    65  			collapsed.Val = c.commit(append(path, cn.Key...), cn.Val)
    66  		}
    67  		// The key needs to be copied, since we're adding it to the
    68  		// modified nodeset.
    69  		collapsed.Key = hexToCompact(cn.Key)
    70  		hashedNode := c.store(path, collapsed)
    71  		if hn, ok := hashedNode.(hashNode); ok {
    72  			return hn
    73  		}
    74  		return collapsed
    75  	case *fullNode:
    76  		hashedKids := c.commitChildren(path, cn)
    77  		collapsed := cn.copy()
    78  		collapsed.Children = hashedKids
    79  
    80  		hashedNode := c.store(path, collapsed)
    81  		if hn, ok := hashedNode.(hashNode); ok {
    82  			return hn
    83  		}
    84  		return collapsed
    85  	case hashNode:
    86  		return cn
    87  	default:
    88  		// nil, valuenode shouldn't be committed
    89  		panic(fmt.Sprintf("%T: invalid node: %v", n, n))
    90  	}
    91  }
    92  
    93  // commitChildren commits the children of the given fullnode
    94  func (c *committer) commitChildren(path []byte, n *fullNode) [17]node {
    95  	var children [17]node
    96  	for i := 0; i < 16; i++ {
    97  		child := n.Children[i]
    98  		if child == nil {
    99  			continue
   100  		}
   101  		// If it's the hashed child, save the hash value directly.
   102  		// Note: it's impossible that the child in range [0, 15]
   103  		// is a valueNode.
   104  		if hn, ok := child.(hashNode); ok {
   105  			children[i] = hn
   106  			continue
   107  		}
   108  		// Commit the child recursively and store the "hashed" value.
   109  		// Note the returned node can be some embedded nodes, so it's
   110  		// possible the type is not hashNode.
   111  		children[i] = c.commit(append(path, byte(i)), child)
   112  	}
   113  	// For the 17th child, it's possible the type is valuenode.
   114  	if n.Children[16] != nil {
   115  		children[16] = n.Children[16]
   116  	}
   117  	return children
   118  }
   119  
   120  // store hashes the node n and adds it to the modified nodeset. If leaf collection
   121  // is enabled, leaf nodes will be tracked in the modified nodeset as well.
   122  func (c *committer) store(path []byte, n node) node {
   123  	// Larger nodes are replaced by their hash and stored in the database.
   124  	var hash, _ = n.cache()
   125  
   126  	// This was not generated - must be a small node stored in the parent.
   127  	// In theory, we should check if the node is leaf here (embedded node
   128  	// usually is leaf node). But small value (less than 32bytes) is not
   129  	// our target (leaves in account trie only).
   130  	if hash == nil {
   131  		// The node is embedded in its parent, in other words, this node
   132  		// will not be stored in the database independently, mark it as
   133  		// deleted only if the node was existent in database before.
   134  		_, ok := c.tracer.accessList[string(path)]
   135  		if ok {
   136  			c.nodes.AddNode(path, trienode.NewDeleted())
   137  		}
   138  		return n
   139  	}
   140  	// Collect the dirty node to nodeset for return.
   141  	nhash := common.BytesToHash(hash)
   142  	c.nodes.AddNode(path, trienode.New(nhash, nodeToBytes(n)))
   143  
   144  	// Collect the corresponding leaf node if it's required. We don't check
   145  	// full node since it's impossible to store value in fullNode. The key
   146  	// length of leaves should be exactly same.
   147  	if c.collectLeaf {
   148  		if sn, ok := n.(*shortNode); ok {
   149  			if val, ok := sn.Val.(valueNode); ok {
   150  				c.nodes.AddLeaf(nhash, val)
   151  			}
   152  		}
   153  	}
   154  	return hash
   155  }
   156  
   157  // mptResolver the children resolver in merkle-patricia-tree.
   158  type mptResolver struct{}
   159  
   160  // ForEach implements childResolver, decodes the provided node and
   161  // traverses the children inside.
   162  func (resolver mptResolver) ForEach(node []byte, onChild func(common.Hash)) {
   163  	forGatherChildren(mustDecodeNodeUnsafe(nil, node), onChild)
   164  }
   165  
   166  // forGatherChildren traverses the node hierarchy and invokes the callback
   167  // for all the hashnode children.
   168  func forGatherChildren(n node, onChild func(hash common.Hash)) {
   169  	switch n := n.(type) {
   170  	case *shortNode:
   171  		forGatherChildren(n.Val, onChild)
   172  	case *fullNode:
   173  		for i := 0; i < 16; i++ {
   174  			forGatherChildren(n.Children[i], onChild)
   175  		}
   176  	case hashNode:
   177  		onChild(common.BytesToHash(n))
   178  	case valueNode, nil:
   179  	default:
   180  		panic(fmt.Sprintf("unknown node type: %T", n))
   181  	}
   182  }