17
17
package trie
18
18
19
19
import (
20
- "bytes"
21
20
"hash"
22
21
"sync"
23
22
@@ -27,17 +26,39 @@ import (
27
26
)
28
27
29
28
type hasher struct {
30
- tmp * bytes. Buffer
31
- sha hash. Hash
29
+ tmp sliceBuffer
30
+ sha keccakState
32
31
cachegen uint16
33
32
cachelimit uint16
34
33
onleaf LeafCallback
35
34
}
36
35
36
+ // keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
37
+ // Read to get a variable amount of data from the hash state. Read is faster than Sum
38
+ // because it doesn't copy the internal state, but also modifies the internal state.
39
+ type keccakState interface {
40
+ hash.Hash
41
+ Read ([]byte ) (int , error )
42
+ }
43
+
44
+ type sliceBuffer []byte
45
+
46
+ func (b * sliceBuffer ) Write (data []byte ) (n int , err error ) {
47
+ * b = append (* b , data ... )
48
+ return len (data ), nil
49
+ }
50
+
51
+ func (b * sliceBuffer ) Reset () {
52
+ * b = (* b )[:0 ]
53
+ }
54
+
37
55
// hashers live in a global db.
38
56
var hasherPool = sync.Pool {
39
57
New : func () interface {} {
40
- return & hasher {tmp : new (bytes.Buffer ), sha : sha3 .NewKeccak256 ()}
58
+ return & hasher {
59
+ tmp : make (sliceBuffer , 0 , 550 ), // cap is as large as a full fullNode.
60
+ sha : sha3 .NewKeccak256 ().(keccakState ),
61
+ }
41
62
},
42
63
}
43
64
@@ -157,26 +178,23 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
157
178
}
158
179
// Generate the RLP encoding of the node
159
180
h .tmp .Reset ()
160
- if err := rlp .Encode (h .tmp , n ); err != nil {
181
+ if err := rlp .Encode (& h .tmp , n ); err != nil {
161
182
panic ("encode error: " + err .Error ())
162
183
}
163
- if h .tmp . Len ( ) < 32 && ! force {
184
+ if len ( h .tmp ) < 32 && ! force {
164
185
return n , nil // Nodes smaller than 32 bytes are stored inside their parent
165
186
}
166
187
// Larger nodes are replaced by their hash and stored in the database.
167
188
hash , _ := n .cache ()
168
189
if hash == nil {
169
- h .sha .Reset ()
170
- h .sha .Write (h .tmp .Bytes ())
171
- hash = hashNode (h .sha .Sum (nil ))
190
+ hash = h .makeHashNode (h .tmp )
172
191
}
192
+
173
193
if db != nil {
174
194
// We are pooling the trie nodes into an intermediate memory cache
175
195
db .lock .Lock ()
176
-
177
196
hash := common .BytesToHash (hash )
178
- db .insert (hash , h .tmp .Bytes ())
179
-
197
+ db .insert (hash , h .tmp )
180
198
// Track all direct parent->child node references
181
199
switch n := n .(type ) {
182
200
case * shortNode :
@@ -210,3 +228,11 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) {
210
228
}
211
229
return hash , nil
212
230
}
231
+
232
+ func (h * hasher ) makeHashNode (data []byte ) hashNode {
233
+ n := make (hashNode , h .sha .Size ())
234
+ h .sha .Reset ()
235
+ h .sha .Write (data )
236
+ h .sha .Read (n )
237
+ return n
238
+ }
0 commit comments