trie: stacktrie pool hashing slices

This commit is contained in:
Martin Holst Swende 2024-11-11 15:18:42 +01:00
parent 0323853ada
commit 22f86a7668
No known key found for this signature in database
GPG Key ID: 683B438C05A5DDF0
2 changed files with 32 additions and 4 deletions

View File

@ -188,6 +188,14 @@ func (h *hasher) hashData(data []byte) hashNode {
return n return n
} }
// hashDataTo hashes the provided data to the dest buffer (must be at least
// 32 byte large)
func (h *hasher) hashDataTo(data []byte, dest []byte) {
h.sha.Reset()
h.sha.Write(data)
h.sha.Read(dest)
}
// proofHash is used to construct trie proofs, and returns the 'collapsed' // proofHash is used to construct trie proofs, and returns the 'collapsed'
// node (for later RLP encoding) as well as the hashed node -- unless the // node (for later RLP encoding) as well as the hashed node -- unless the
// node is smaller than 32 bytes, in which case it will be returned as is. // node is smaller than 32 bytes, in which case it will be returned as is.

View File

@ -27,6 +27,7 @@ import (
var ( var (
stPool = sync.Pool{New: func() any { return new(stNode) }} stPool = sync.Pool{New: func() any { return new(stNode) }}
bPool = sync.Pool{New: func() any { return make([]byte, 0, 32) }}
_ = types.TrieHasher((*StackTrie)(nil)) _ = types.TrieHasher((*StackTrie)(nil))
) )
@ -145,6 +146,12 @@ const (
) )
func (n *stNode) reset() *stNode { func (n *stNode) reset() *stNode {
if n.typ == hashedNode {
// On hashnodes, we 'own' the val: it is guaranteed to be not held
// by external caller. Hence, when we arrive here, we can put it back
// into the pool
bPool.Put(n.val)
}
n.key = n.key[:0] n.key = n.key[:0]
n.val = nil n.val = nil
for i := range n.children { for i := range n.children {
@ -342,11 +349,16 @@ func (t *StackTrie) hash(st *stNode, path []byte) {
} }
t.hash(child, append(path, byte(i))) t.hash(child, append(path, byte(i)))
nodes.Children[i] = child.val nodes.Children[i] = child.val
st.children[i] = nil
stPool.Put(child.reset()) // Release child back to pool.
} }
nodes.encode(t.h.encbuf) nodes.encode(t.h.encbuf)
blob = t.h.encodedBytes() blob = t.h.encodedBytes()
for i, child := range st.children {
if child == nil {
continue
}
st.children[i] = nil
stPool.Put(child.reset()) // Release child back to pool.
}
case extNode: case extNode:
// recursively hash and commit child as the first step // recursively hash and commit child as the first step
@ -381,15 +393,23 @@ func (t *StackTrie) hash(st *stNode, path []byte) {
st.typ = hashedNode st.typ = hashedNode
st.key = st.key[:0] st.key = st.key[:0]
st.val = nil // Release reference to potentially externally held slice.
// Skip committing the non-root node if the size is smaller than 32 bytes // Skip committing the non-root node if the size is smaller than 32 bytes
// as tiny nodes are always embedded in their parent except root node. // as tiny nodes are always embedded in their parent except root node.
if len(blob) < 32 && len(path) > 0 { if len(blob) < 32 && len(path) > 0 {
st.val = common.CopyBytes(blob) val := bPool.Get().([]byte)
val = val[:len(blob)]
copy(val, blob)
st.val = val
return return
} }
// Write the hash to the 'val'. We allocate a new val here to not mutate // Write the hash to the 'val'. We allocate a new val here to not mutate
// input values. // input values.
st.val = t.h.hashData(blob) val := bPool.Get().([]byte)
val = val[:32]
t.h.hashDataTo(blob, val)
st.val = val
// Invoke the callback it's provided. Notably, the path and blob slices are // Invoke the callback it's provided. Notably, the path and blob slices are
// volatile, please deep-copy the slices in callback if the contents need // volatile, please deep-copy the slices in callback if the contents need