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 }