mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-23 05:06:43 +00:00
trie, core: polish
This commit is contained in:
parent
89546e19d9
commit
8b1071fc34
4 changed files with 37 additions and 32 deletions
|
|
@ -27,7 +27,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
)
|
)
|
||||||
|
|
||||||
// hasherPool holds LegacyKeccak256 hashers for rlpHash.
|
// hasherPool holds LegacyKeccak256 buffer for rlpHash.
|
||||||
var hasherPool = sync.Pool{
|
var hasherPool = sync.Pool{
|
||||||
New: func() interface{} { return crypto.NewKeccakState() },
|
New: func() interface{} { return crypto.NewKeccakState() },
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
func BenchmarkDeriveSha200(b *testing.B) {
|
||||||
txs, err := genTxs(200)
|
txs, err := genTxs(200)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
b.Fatal(err)
|
b.Fatal(err)
|
||||||
}
|
}
|
||||||
want := types.DeriveSha(txs, trie.NewListHasher())
|
want := types.DeriveSha(txs, trie.NewListHasher())
|
||||||
var have common.Hash
|
|
||||||
b.Run("std_trie", func(b *testing.B) {
|
b.Run("std_trie", func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
var have common.Hash
|
||||||
for b.Loop() {
|
for b.Loop() {
|
||||||
have = types.DeriveSha(txs, trie.NewListHasher())
|
have = types.DeriveSha(txs, trie.NewListHasher())
|
||||||
}
|
}
|
||||||
|
|
@ -94,6 +104,7 @@ func BenchmarkDeriveSha200(b *testing.B) {
|
||||||
st := trie.NewStackTrie(nil)
|
st := trie.NewStackTrie(nil)
|
||||||
b.Run("stack_trie", func(b *testing.B) {
|
b.Run("stack_trie", func(b *testing.B) {
|
||||||
b.ReportAllocs()
|
b.ReportAllocs()
|
||||||
|
var have common.Hash
|
||||||
for b.Loop() {
|
for b.Loop() {
|
||||||
st.Reset()
|
st.Reset()
|
||||||
have = types.DeriveSha(txs, st)
|
have = types.DeriveSha(txs, st)
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
func (bp *unsafeBytesPool) get() []byte {
|
||||||
if len(bp.items) > 0 {
|
if len(bp.items) > 0 {
|
||||||
last := bp.items[len(bp.items)-1]
|
last := bp.items[len(bp.items)-1]
|
||||||
|
|
@ -89,8 +89,8 @@ func (bp *unsafeBytesPool) get() []byte {
|
||||||
return make([]byte, 0, bp.w)
|
return make([]byte, 0, bp.w)
|
||||||
}
|
}
|
||||||
|
|
||||||
// put returns a slice to the pool. This method
|
// put returns a slice to the pool. This method will ignore slices that are
|
||||||
// will ignore slices that are too small or too large (>3x the cap)
|
// too small or too large (>3x the cap)
|
||||||
func (bp *unsafeBytesPool) put(b []byte) {
|
func (bp *unsafeBytesPool) put(b []byte) {
|
||||||
if c := cap(b); c < bp.w || c > 3*bp.w {
|
if c := cap(b); c < bp.w || c > 3*bp.w {
|
||||||
return
|
return
|
||||||
|
|
|
||||||
|
|
@ -77,8 +77,8 @@ func (t *StackTrie) grow(key []byte) {
|
||||||
|
|
||||||
// Update inserts a (key, value) pair into the stack trie.
|
// Update inserts a (key, value) pair into the stack trie.
|
||||||
//
|
//
|
||||||
// Note the supplied key value pair is copied and managed internally, they are
|
// Note the supplied key value pair is copied and managed internally,
|
||||||
// safe to be modified after this method returns.
|
// they are safe to be modified after this method returns.
|
||||||
func (t *StackTrie) Update(key, value []byte) error {
|
func (t *StackTrie) Update(key, value []byte) error {
|
||||||
if len(value) == 0 {
|
if len(value) == 0 {
|
||||||
return errors.New("trying to insert empty (deletion)")
|
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
|
// stNode represents a node within a StackTrie
|
||||||
type stNode struct {
|
type stNode struct {
|
||||||
typ uint8 // node type (as in branch, ext, leaf)
|
typ uint8 // node type (as in branch, ext, leaf)
|
||||||
key []byte // key chunk covered by this (leaf|ext) node
|
key []byte // exclusive owned key chunk covered by this (leaf|ext) node
|
||||||
val []byte // value contained by this node if it's a leaf
|
val []byte // exclusive owned value contained by this node (leaf: value; hash: hash)
|
||||||
children [16]*stNode // list of children (for branch and exts)
|
children [16]*stNode // list of children (for branch and ext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newLeaf constructs a leaf node with provided node key and value. The key
|
// newLeaf constructs a leaf node with provided node key and value.
|
||||||
// will be deep-copied in the function and safe to modify afterwards, but
|
//
|
||||||
// value is not.
|
// 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 {
|
func newLeaf(key, val []byte) *stNode {
|
||||||
st := stPool.Get().(*stNode)
|
st := stPool.Get().(*stNode)
|
||||||
st.typ = leafNode
|
st.typ = leafNode
|
||||||
|
|
@ -158,8 +160,8 @@ const (
|
||||||
func (n *stNode) reset() *stNode {
|
func (n *stNode) reset() *stNode {
|
||||||
if n.typ == hashedNode {
|
if n.typ == hashedNode {
|
||||||
// On hashnodes, we 'own' the val: it is guaranteed to be not held
|
// 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
|
// by external caller. Hence, when we arrive here, we can put it
|
||||||
// into the pool
|
// back into the pool
|
||||||
bPool.put(n.val)
|
bPool.put(n.val)
|
||||||
}
|
}
|
||||||
n.key = n.key[:0]
|
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.
|
// 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) {
|
func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
|
||||||
switch st.typ {
|
switch st.typ {
|
||||||
case branchNode: /* Branch */
|
case branchNode: /* Branch */
|
||||||
|
|
@ -247,16 +244,14 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
|
||||||
}
|
}
|
||||||
var p *stNode
|
var p *stNode
|
||||||
if diffidx == 0 {
|
if diffidx == 0 {
|
||||||
// the break is on the first byte, so
|
// the break is on the first byte, so the current node
|
||||||
// the current node is converted into
|
// is converted into a branch node.
|
||||||
// a branch node.
|
|
||||||
st.children[0] = nil
|
st.children[0] = nil
|
||||||
p = st
|
|
||||||
st.typ = branchNode
|
st.typ = branchNode
|
||||||
|
p = st
|
||||||
} else {
|
} else {
|
||||||
// the common prefix is at least one byte
|
// the common prefix is at least one byte long, insert
|
||||||
// long, insert a new intermediate branch
|
// a new intermediate branch node.
|
||||||
// node.
|
|
||||||
st.children[0] = stPool.Get().(*stNode)
|
st.children[0] = stPool.Get().(*stNode)
|
||||||
st.children[0].typ = branchNode
|
st.children[0].typ = branchNode
|
||||||
p = st.children[0]
|
p = st.children[0]
|
||||||
|
|
@ -292,8 +287,8 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
|
||||||
if diffidx == 0 {
|
if diffidx == 0 {
|
||||||
// Convert current leaf into a branch
|
// Convert current leaf into a branch
|
||||||
st.typ = branchNode
|
st.typ = branchNode
|
||||||
p = st
|
|
||||||
st.children[0] = nil
|
st.children[0] = nil
|
||||||
|
p = st
|
||||||
} else {
|
} else {
|
||||||
// Convert current node into an ext,
|
// Convert current node into an ext,
|
||||||
// and insert a child branch node.
|
// and insert a child branch node.
|
||||||
|
|
@ -319,9 +314,7 @@ func (t *StackTrie) insert(st *stNode, key, value []byte, path []byte) {
|
||||||
st.val = nil
|
st.val = nil
|
||||||
|
|
||||||
case emptyNode: /* Empty */
|
case emptyNode: /* Empty */
|
||||||
st.typ = leafNode
|
*st = *newLeaf(key, value)
|
||||||
st.key = append(st.key, key...) // deep-copy the key as it's volatile
|
|
||||||
st.val = value
|
|
||||||
|
|
||||||
case hashedNode:
|
case hashedNode:
|
||||||
panic("trying to insert into hash")
|
panic("trying to insert into hash")
|
||||||
|
|
@ -405,7 +398,8 @@ func (t *StackTrie) hash(st *stNode, path []byte) {
|
||||||
st.typ = hashedNode
|
st.typ = hashedNode
|
||||||
st.key = st.key[:0]
|
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 {
|
if cap(st.val) > 0 && t.vPool != nil {
|
||||||
t.vPool.put(st.val)
|
t.vPool.put(st.val)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue