@@ -23,7 +23,6 @@ import (
23
23
24
24
"github.com/ethereum/go-ethereum/common"
25
25
"github.com/ethereum/go-ethereum/crypto"
26
- "github.com/ethereum/go-ethereum/rlp"
27
26
"golang.org/x/crypto/sha3"
28
27
)
29
28
@@ -33,10 +32,9 @@ const leafChanSize = 200
33
32
34
33
// leaf represents a trie leaf value
35
34
type leaf struct {
36
- size int // size of the rlp data (estimate)
37
- hash common.Hash // hash of rlp data
38
- node node // the node to commit
39
- vnodes bool // set to true if the node (possibly) contains a valueNode
35
+ size int // size of the rlp data (estimate)
36
+ hash common.Hash // hash of rlp data
37
+ node node // the node to commit
40
38
}
41
39
42
40
// committer is a type used for the trie Commit operation. A committer has some
@@ -74,26 +72,20 @@ func returnCommitterToPool(h *committer) {
74
72
committerPool .Put (h )
75
73
}
76
74
77
- // commitNeeded returns 'false' if the given node is already in sync with db
78
- func (c * committer ) commitNeeded (n node ) bool {
79
- hash , dirty := n .cache ()
80
- return hash == nil || dirty
81
- }
82
-
83
75
// commit collapses a node down into a hash node and inserts it into the database
84
76
func (c * committer ) Commit (n node , db * Database ) (hashNode , error ) {
85
77
if db == nil {
86
78
return nil , errors .New ("no db provided" )
87
79
}
88
- h , err := c .commit (n , db , true )
80
+ h , err := c .commit (n , db )
89
81
if err != nil {
90
82
return nil , err
91
83
}
92
84
return h .(hashNode ), nil
93
85
}
94
86
95
87
// commit collapses a node down into a hash node and inserts it into the database
96
- func (c * committer ) commit (n node , db * Database , force bool ) (node , error ) {
88
+ func (c * committer ) commit (n node , db * Database ) (node , error ) {
97
89
// if this path is clean, use available cached data
98
90
hash , dirty := n .cache ()
99
91
if hash != nil && ! dirty {
@@ -104,87 +96,90 @@ func (c *committer) commit(n node, db *Database, force bool) (node, error) {
104
96
case * shortNode :
105
97
// Commit child
106
98
collapsed := cn .copy ()
107
- if _ , ok := cn .Val .(valueNode ); ! ok {
108
- childV , err := c .commit (cn .Val , db , false )
99
+
100
+ // If the child is fullnode, recursively commit.
101
+ // Otherwise it can only be hashNode or valueNode.
102
+ if _ , ok := cn .Val .(* fullNode ); ok {
103
+ childV , err := c .commit (cn .Val , db )
109
104
if err != nil {
110
105
return nil , err
111
106
}
112
107
collapsed .Val = childV
113
108
}
114
109
// The key needs to be copied, since we're delivering it to database
115
110
collapsed .Key = hexToCompact (cn .Key )
116
- hashedNode := c .store (collapsed , db , force , true )
111
+ hashedNode := c .store (collapsed , db )
117
112
if hn , ok := hashedNode .(hashNode ); ok {
118
113
return hn , nil
119
114
}
120
115
return collapsed , nil
121
116
case * fullNode :
122
- hashedKids , hasVnodes , err := c .commitChildren (cn , db , force )
117
+ hashedKids , err := c .commitChildren (cn , db )
123
118
if err != nil {
124
119
return nil , err
125
120
}
126
121
collapsed := cn .copy ()
127
122
collapsed .Children = hashedKids
128
123
129
- hashedNode := c .store (collapsed , db , force , hasVnodes )
124
+ hashedNode := c .store (collapsed , db )
130
125
if hn , ok := hashedNode .(hashNode ); ok {
131
126
return hn , nil
132
127
}
133
128
return collapsed , nil
134
- case valueNode :
135
- return c .store (cn , db , force , false ), nil
136
- // hashnodes aren't stored
137
129
case hashNode :
138
130
return cn , nil
131
+ default :
132
+ // nil, valuenode shouldn't be committed
133
+ panic (fmt .Sprintf ("%T: invalid node: %v" , n , n ))
139
134
}
140
- return hash , nil
141
135
}
142
136
143
137
// commitChildren commits the children of the given fullnode
144
- func (c * committer ) commitChildren (n * fullNode , db * Database , force bool ) ([17 ]node , bool , error ) {
138
+ func (c * committer ) commitChildren (n * fullNode , db * Database ) ([17 ]node , error ) {
145
139
var children [17 ]node
146
- var hasValueNodeChildren = false
147
- for i , child := range n .Children {
140
+ for i := 0 ; i < 16 ; i ++ {
141
+ child := n .Children [ i ]
148
142
if child == nil {
149
143
continue
150
144
}
151
- hnode , err := c .commit (child , db , false )
152
- if err != nil {
153
- return children , false , err
145
+ // If it's the hashed child, save the hash value directly.
146
+ // Note: it's impossible that the child in range [0, 15]
147
+ // is a valuenode.
148
+ if hn , ok := child .(hashNode ); ok {
149
+ children [i ] = hn
150
+ continue
154
151
}
155
- children [i ] = hnode
156
- if _ , ok := hnode .(valueNode ); ok {
157
- hasValueNodeChildren = true
152
+ // Commit the child recursively and store the "hashed" value.
153
+ // Note the returned node can be some embedded nodes, so it's
154
+ // possible the type is not hashnode.
155
+ hashed , err := c .commit (child , db )
156
+ if err != nil {
157
+ return children , err
158
158
}
159
+ children [i ] = hashed
159
160
}
160
- return children , hasValueNodeChildren , nil
161
+ // For the 17th child, it's possible the type is valuenode.
162
+ if n .Children [16 ] != nil {
163
+ children [16 ] = n .Children [16 ]
164
+ }
165
+ return children , nil
161
166
}
162
167
163
168
// store hashes the node n and if we have a storage layer specified, it writes
164
169
// the key/value pair to it and tracks any node->child references as well as any
165
170
// node->external trie references.
166
- func (c * committer ) store (n node , db * Database , force bool , hasVnodeChildren bool ) node {
171
+ func (c * committer ) store (n node , db * Database ) node {
167
172
// Larger nodes are replaced by their hash and stored in the database.
168
173
var (
169
174
hash , _ = n .cache ()
170
175
size int
171
176
)
172
177
if hash == nil {
173
- if vn , ok := n .(valueNode ); ok {
174
- c .tmp .Reset ()
175
- if err := rlp .Encode (& c .tmp , vn ); err != nil {
176
- panic ("encode error: " + err .Error ())
177
- }
178
- size = len (c .tmp )
179
- if size < 32 && ! force {
180
- return n // Nodes smaller than 32 bytes are stored inside their parent
181
- }
182
- hash = c .makeHashNode (c .tmp )
183
- } else {
184
- // This was not generated - must be a small node stored in the parent
185
- // No need to do anything here
186
- return n
187
- }
178
+ // This was not generated - must be a small node stored in the parent.
179
+ // In theory we should apply the leafCall here if it's not nil(embedded
180
+ // node usually contains value). But small value(less than 32bytes) is
181
+ // not our target.
182
+ return n
188
183
} else {
189
184
// We have the hash already, estimate the RLP encoding-size of the node.
190
185
// The size is used for mem tracking, does not need to be exact
@@ -194,10 +189,9 @@ func (c *committer) store(n node, db *Database, force bool, hasVnodeChildren boo
194
189
// The leaf channel will be active only when there an active leaf-callback
195
190
if c .leafCh != nil {
196
191
c .leafCh <- & leaf {
197
- size : size ,
198
- hash : common .BytesToHash (hash ),
199
- node : n ,
200
- vnodes : hasVnodeChildren ,
192
+ size : size ,
193
+ hash : common .BytesToHash (hash ),
194
+ node : n ,
201
195
}
202
196
} else if db != nil {
203
197
// No leaf-callback used, but there's still a database. Do serial
@@ -209,30 +203,30 @@ func (c *committer) store(n node, db *Database, force bool, hasVnodeChildren boo
209
203
return hash
210
204
}
211
205
212
- // commitLoop does the actual insert + leaf callback for nodes
206
+ // commitLoop does the actual insert + leaf callback for nodes.
213
207
func (c * committer ) commitLoop (db * Database ) {
214
208
for item := range c .leafCh {
215
209
var (
216
- hash = item .hash
217
- size = item .size
218
- n = item .node
219
- hasVnodes = item .vnodes
210
+ hash = item .hash
211
+ size = item .size
212
+ n = item .node
220
213
)
221
214
// We are pooling the trie nodes into an intermediate memory cache
222
215
db .lock .Lock ()
223
216
db .insert (hash , size , n )
224
217
db .lock .Unlock ()
225
- if c .onleaf != nil && hasVnodes {
218
+
219
+ if c .onleaf != nil {
226
220
switch n := n .(type ) {
227
221
case * shortNode :
228
222
if child , ok := n .Val .(valueNode ); ok {
229
223
c .onleaf (nil , child , hash )
230
224
}
231
225
case * fullNode :
232
- for i := 0 ; i < 16 ; i ++ {
233
- if child , ok := n . Children [ i ].( valueNode ); ok {
234
- c . onleaf ( nil , child , hash )
235
- }
226
+ // For children in range [0, 15], it's impossible
227
+ // to contain valuenode. Only check the 17th child.
228
+ if n . Children [ 16 ] != nil {
229
+ c . onleaf ( nil , n . Children [ 16 ].( valueNode ), hash )
236
230
}
237
231
}
238
232
}
0 commit comments