committer.go 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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. package trie
  17. import (
  18. "fmt"
  19. "github.com/ethereum/go-ethereum/common"
  20. )
  21. // leaf represents a trie leaf node
  22. type leaf struct {
  23. blob []byte // raw blob of leaf
  24. parent common.Hash // the hash of parent node
  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 *NodeSet
  31. collectLeaf bool
  32. }
  33. // newCommitter creates a new committer or picks one from the pool.
  34. func newCommitter(owner common.Hash, collectLeaf bool) *committer {
  35. return &committer{
  36. nodes: NewNodeSet(owner),
  37. collectLeaf: collectLeaf,
  38. }
  39. }
  40. // Commit collapses a node down into a hash node and inserts it into the database
  41. func (c *committer) Commit(n node) (hashNode, *NodeSet, error) {
  42. h, err := c.commit(nil, n)
  43. if err != nil {
  44. return nil, nil, err
  45. }
  46. return h.(hashNode), c.nodes, nil
  47. }
  48. // commit collapses a node down into a hash node and inserts it into the database
  49. func (c *committer) commit(path []byte, n node) (node, error) {
  50. // if this path is clean, use available cached data
  51. hash, dirty := n.cache()
  52. if hash != nil && !dirty {
  53. return hash, nil
  54. }
  55. // Commit children, then parent, and remove the dirty flag.
  56. switch cn := n.(type) {
  57. case *shortNode:
  58. // Commit child
  59. collapsed := cn.copy()
  60. // If the child is fullNode, recursively commit,
  61. // otherwise it can only be hashNode or valueNode.
  62. if _, ok := cn.Val.(*fullNode); ok {
  63. childV, err := c.commit(append(path, cn.Key...), cn.Val)
  64. if err != nil {
  65. return nil, err
  66. }
  67. collapsed.Val = childV
  68. }
  69. // The key needs to be copied, since we're delivering it to database
  70. collapsed.Key = hexToCompact(cn.Key)
  71. hashedNode := c.store(path, collapsed)
  72. if hn, ok := hashedNode.(hashNode); ok {
  73. return hn, nil
  74. }
  75. return collapsed, nil
  76. case *fullNode:
  77. hashedKids, err := c.commitChildren(path, cn)
  78. if err != nil {
  79. return nil, err
  80. }
  81. collapsed := cn.copy()
  82. collapsed.Children = hashedKids
  83. hashedNode := c.store(path, collapsed)
  84. if hn, ok := hashedNode.(hashNode); ok {
  85. return hn, nil
  86. }
  87. return collapsed, nil
  88. case hashNode:
  89. return cn, nil
  90. default:
  91. // nil, valuenode shouldn't be committed
  92. panic(fmt.Sprintf("%T: invalid node: %v", n, n))
  93. }
  94. }
  95. // commitChildren commits the children of the given fullnode
  96. func (c *committer) commitChildren(path []byte, n *fullNode) ([17]node, error) {
  97. var children [17]node
  98. for i := 0; i < 16; i++ {
  99. child := n.Children[i]
  100. if child == nil {
  101. continue
  102. }
  103. // If it's the hashed child, save the hash value directly.
  104. // Note: it's impossible that the child in range [0, 15]
  105. // is a valueNode.
  106. if hn, ok := child.(hashNode); ok {
  107. children[i] = hn
  108. continue
  109. }
  110. // Commit the child recursively and store the "hashed" value.
  111. // Note the returned node can be some embedded nodes, so it's
  112. // possible the type is not hashNode.
  113. hashed, err := c.commit(append(path, byte(i)), child)
  114. if err != nil {
  115. return children, err
  116. }
  117. children[i] = hashed
  118. }
  119. // For the 17th child, it's possible the type is valuenode.
  120. if n.Children[16] != nil {
  121. children[16] = n.Children[16]
  122. }
  123. return children, nil
  124. }
  125. // store hashes the node n and if we have a storage layer specified, it writes
  126. // the key/value pair to it and tracks any node->child references as well as any
  127. // node->external trie references.
  128. func (c *committer) store(path []byte, n node) node {
  129. // Larger nodes are replaced by their hash and stored in the database.
  130. var hash, _ = n.cache()
  131. // This was not generated - must be a small node stored in the parent.
  132. // In theory, we should check if the node is leaf here (embedded node
  133. // usually is leaf node). But small value(less than 32bytes) is not
  134. // our target(leaves in account trie only).
  135. if hash == nil {
  136. return n
  137. }
  138. // We have the hash already, estimate the RLP encoding-size of the node.
  139. // The size is used for mem tracking, does not need to be exact
  140. var (
  141. size = estimateSize(n)
  142. nhash = common.BytesToHash(hash)
  143. mnode = &memoryNode{
  144. hash: nhash,
  145. node: simplifyNode(n),
  146. size: uint16(size),
  147. }
  148. )
  149. // Collect the dirty node to nodeset for return.
  150. c.nodes.add(string(path), mnode)
  151. // Collect the corresponding leaf node if it's required. We don't check
  152. // full node since it's impossible to store value in fullNode. The key
  153. // length of leaves should be exactly same.
  154. if c.collectLeaf {
  155. if sn, ok := n.(*shortNode); ok {
  156. if val, ok := sn.Val.(valueNode); ok {
  157. c.nodes.addLeaf(&leaf{blob: val, parent: nhash})
  158. }
  159. }
  160. }
  161. return hash
  162. }
  163. // estimateSize estimates the size of an rlp-encoded node, without actually
  164. // rlp-encoding it (zero allocs). This method has been experimentally tried, and with a trie
  165. // with 1000 leaves, the only errors above 1% are on small shortnodes, where this
  166. // method overestimates by 2 or 3 bytes (e.g. 37 instead of 35)
  167. func estimateSize(n node) int {
  168. switch n := n.(type) {
  169. case *shortNode:
  170. // A short node contains a compacted key, and a value.
  171. return 3 + len(n.Key) + estimateSize(n.Val)
  172. case *fullNode:
  173. // A full node contains up to 16 hashes (some nils), and a key
  174. s := 3
  175. for i := 0; i < 16; i++ {
  176. if child := n.Children[i]; child != nil {
  177. s += estimateSize(child)
  178. } else {
  179. s++
  180. }
  181. }
  182. return s
  183. case valueNode:
  184. return 1 + len(n)
  185. case hashNode:
  186. return 1 + len(n)
  187. default:
  188. panic(fmt.Sprintf("node type %T", n))
  189. }
  190. }