|
|
|
@ -17,7 +17,6 @@ |
|
|
|
|
package trie |
|
|
|
|
|
|
|
|
|
import ( |
|
|
|
|
"bytes" |
|
|
|
|
"hash" |
|
|
|
|
"sync" |
|
|
|
|
|
|
|
|
@ -27,17 +26,39 @@ import ( |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
type hasher struct { |
|
|
|
|
tmp *bytes.Buffer |
|
|
|
|
sha hash.Hash |
|
|
|
|
tmp sliceBuffer |
|
|
|
|
sha keccakState |
|
|
|
|
cachegen uint16 |
|
|
|
|
cachelimit uint16 |
|
|
|
|
onleaf LeafCallback |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// keccakState wraps sha3.state. In addition to the usual hash methods, it also supports
|
|
|
|
|
// Read to get a variable amount of data from the hash state. Read is faster than Sum
|
|
|
|
|
// because it doesn't copy the internal state, but also modifies the internal state.
|
|
|
|
|
type keccakState interface { |
|
|
|
|
hash.Hash |
|
|
|
|
Read([]byte) (int, error) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
type sliceBuffer []byte |
|
|
|
|
|
|
|
|
|
func (b *sliceBuffer) Write(data []byte) (n int, err error) { |
|
|
|
|
*b = append(*b, data...) |
|
|
|
|
return len(data), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (b *sliceBuffer) Reset() { |
|
|
|
|
*b = (*b)[:0] |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// hashers live in a global db.
|
|
|
|
|
var hasherPool = sync.Pool{ |
|
|
|
|
New: func() interface{} { |
|
|
|
|
return &hasher{tmp: new(bytes.Buffer), sha: sha3.NewKeccak256()} |
|
|
|
|
return &hasher{ |
|
|
|
|
tmp: make(sliceBuffer, 0, 550), // cap is as large as a full fullNode.
|
|
|
|
|
sha: sha3.NewKeccak256().(keccakState), |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -157,26 +178,23 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { |
|
|
|
|
} |
|
|
|
|
// Generate the RLP encoding of the node
|
|
|
|
|
h.tmp.Reset() |
|
|
|
|
if err := rlp.Encode(h.tmp, n); err != nil { |
|
|
|
|
if err := rlp.Encode(&h.tmp, n); err != nil { |
|
|
|
|
panic("encode error: " + err.Error()) |
|
|
|
|
} |
|
|
|
|
if h.tmp.Len() < 32 && !force { |
|
|
|
|
if len(h.tmp) < 32 && !force { |
|
|
|
|
return n, nil // Nodes smaller than 32 bytes are stored inside their parent
|
|
|
|
|
} |
|
|
|
|
// Larger nodes are replaced by their hash and stored in the database.
|
|
|
|
|
hash, _ := n.cache() |
|
|
|
|
if hash == nil { |
|
|
|
|
h.sha.Reset() |
|
|
|
|
h.sha.Write(h.tmp.Bytes()) |
|
|
|
|
hash = hashNode(h.sha.Sum(nil)) |
|
|
|
|
hash = h.makeHashNode(h.tmp) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if db != nil { |
|
|
|
|
// We are pooling the trie nodes into an intermediate memory cache
|
|
|
|
|
db.lock.Lock() |
|
|
|
|
|
|
|
|
|
hash := common.BytesToHash(hash) |
|
|
|
|
db.insert(hash, h.tmp.Bytes()) |
|
|
|
|
|
|
|
|
|
db.insert(hash, h.tmp) |
|
|
|
|
// Track all direct parent->child node references
|
|
|
|
|
switch n := n.(type) { |
|
|
|
|
case *shortNode: |
|
|
|
@ -210,3 +228,11 @@ func (h *hasher) store(n node, db *Database, force bool) (node, error) { |
|
|
|
|
} |
|
|
|
|
return hash, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (h *hasher) makeHashNode(data []byte) hashNode { |
|
|
|
|
n := make(hashNode, h.sha.Size()) |
|
|
|
|
h.sha.Reset() |
|
|
|
|
h.sha.Write(data) |
|
|
|
|
h.sha.Read(n) |
|
|
|
|
return n |
|
|
|
|
} |
|
|
|
|