trie, core: polish

This commit is contained in:
Gary Rong 2025-09-02 11:29:29 +08:00 committed by Felix Lange
parent 89546e19d9
commit 8b1071fc34
4 changed files with 37 additions and 32 deletions

View file

@ -27,7 +27,7 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
// hasherPool holds LegacyKeccak256 hashers for rlpHash.
// hasherPool holds LegacyKeccak256 buffer for rlpHash.
var hasherPool = sync.Pool{
New: func() interface{} { return crypto.NewKeccakState() },
}

View file

@ -74,15 +74,25 @@ func TestEIP2718DeriveSha(t *testing.T) {
}
}
// goos: darwin
// goarch: arm64
// pkg: github.com/ethereum/go-ethereum/core/types
// cpu: Apple M1 Pro
// BenchmarkDeriveSha200
// BenchmarkDeriveSha200/std_trie
// BenchmarkDeriveSha200/std_trie-8 6754 174074 ns/op 80054 B/op 1926 allocs/op
// BenchmarkDeriveSha200/stack_trie
// BenchmarkDeriveSha200/stack_trie-8 7296 162675 ns/op 745 B/op 19 allocs/op
func BenchmarkDeriveSha200(b *testing.B) {
txs, err := genTxs(200)
if err != nil {
b.Fatal(err)
}
want := types.DeriveSha(txs, trie.NewListHasher())
var have common.Hash
b.Run("std_trie", func(b *testing.B) {
b.ReportAllocs()
var have common.Hash
for b.Loop() {
have = types.DeriveSha(txs, trie.NewListHasher())
}
@ -94,6 +104,7 @@ func BenchmarkDeriveSha200(b *testing.B) {
st := trie.NewStackTrie(nil)
b.Run("stack_trie", func(b *testing.B) {
b.ReportAllocs()
var have common.Hash
for b.Loop() {
st.Reset()
have = types.DeriveSha(txs, st)

View file

@ -79,7 +79,7 @@ func newUnsafeBytesPool(sliceCap, nitems int) *unsafeBytesPool {
}
}
// Get returns a slice.
// Get returns a slice with pre-allocated space.
func (bp *unsafeBytesPool) get() []byte {
if len(bp.items) > 0 {
last := bp.items[len(bp.items)-1]
@ -89,8 +89,8 @@ func (bp *unsafeBytesPool) get() []byte {
return make([]byte, 0, bp.w)
}
// put returns a slice to the pool. This method
// will ignore slices that are too small or too large (>3x the cap)
// put returns a slice to the pool. This method will ignore slices that are
// too small or too large (>3x the cap)
func (bp *unsafeBytesPool) put(b []byte) {
if c := cap(b); c < bp.w || c > 3*bp.w {
return

View file

@ -77,8 +77,8 @@ func (t *StackTrie) grow(key []byte) {
// Update inserts a (key, value) pair into the stack trie.
//
// Note the supplied key value pair is copied and managed internally, they are
// safe to be modified after this method returns.
// Note the supplied key value pair is copied and managed internally,
// they are safe to be modified after this method returns.
func (t *StackTrie) Update(key, value []byte) error {
if len(value) == 0 {
return errors.New("trying to insert empty (deletion)")
@ -120,14 +120,16 @@ func (t *StackTrie) TrieKey(key []byte) []byte {
// stNode represents a node within a StackTrie
type stNode struct {
typ uint8 // node type (as in branch, ext, leaf)
key []byte // key chunk covered by this (leaf|ext) node
val []byte // value contained by this node if it's a leaf
children [16]*stNode // list of children (for branch and exts)
key []byte // exclusive owned key chunk covered by this (leaf|ext) node
val []byte // exclusive owned value contained by this node (leaf: value; hash: hash)
children [16]*stNode // list of children (for branch and ext)
}
// newLeaf constructs a leaf node with provided node key and value. The key
// will be deep-copied in the function and safe to modify afterwards, but
// value is not.
// newLeaf constructs a leaf node with provided node key and value.
//
// The key is deep-copied within the function, so it can be safely modified
// afterwards. The value is retained directly without copying, as it is
// exclusively owned by the stackTrie.
func newLeaf(key, val []byte) *stNode {
st := stPool.Get().(*stNode)
st.typ = leafNode
@ -158,8 +160,8 @@ const (
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
// 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]
@ -184,11 +186,6 @@ func (n *stNode) getDiffIndex(key []byte) int {
}
// Helper function to that inserts a (key, value) pair into the trie.
//
// - The key is not retained by this method, but always copied if needed.
// - The value is retained by this method, as long as the leaf that it represents
// remains unhashed. However: it is never modified.
// - The path is not retained by this method.
func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
switch st.typ {
case branchNode: /* Branch */
@ -247,16 +244,14 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
}
var p *stNode
if diffidx == 0 {
// the break is on the first byte, so
// the current node is converted into
// a branch node.
// the break is on the first byte, so the current node
// is converted into a branch node.
st.children[0] = nil
p = st
st.typ = branchNode
p = st
} else {
// the common prefix is at least one byte
// long, insert a new intermediate branch
// node.
// the common prefix is at least one byte long, insert
// a new intermediate branch node.
st.children[0] = stPool.Get().(*stNode)
st.children[0].typ = branchNode
p = st.children[0]
@ -292,8 +287,8 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
if diffidx == 0 {
// Convert current leaf into a branch
st.typ = branchNode
p = st
st.children[0] = nil
p = st
} else {
// Convert current node into an ext,
// and insert a child branch node.
@ -319,9 +314,7 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
st.val = nil
case emptyNode: /* Empty */
st.typ = leafNode
st.key = append(st.key, key...) // deep-copy the key as it's volatile
st.val = value
*st = *newLeaf(key, value)
case hashedNode:
panic("trying to insert into hash")
@ -405,7 +398,8 @@ func (t *StackTrie) hash(st *stNode, path []byte) {
st.typ = hashedNode
st.key = st.key[:0]
// Release reference to (potentially externally held) value-slice.
// Release reference to value slice which is exclusively owned
// by stackTrie itself.
if cap(st.val) > 0 && t.vPool != nil {
t.vPool.put(st.val)
}