trie/bintrie: use a sync.Pool when hashing binary tree nodes (#33989)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

Binary tree hashing is quite slow, owing to many factors. One of them is
the GC pressure that is the consequence of allocating many hashers, as a
binary tree has 4x the size of an MPT. This PR introduces an
optimization that already exists for the MPT: keep a pool of hashers, in
order to reduce the amount of allocations.
This commit is contained in:
Guillaume Ballet 2026-03-12 10:20:12 +01:00 committed by GitHub
parent 95b9a2ed77
commit 1c9ddee16f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 8 deletions

39
trie/bintrie/hasher.go Normal file
View file

@ -0,0 +1,39 @@
// Copyright 2026 go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package bintrie
import (
"crypto/sha256"
"hash"
"sync"
)
var sha256Pool = sync.Pool{
New: func() any {
return sha256.New()
},
}
func newSha256() hash.Hash {
h := sha256Pool.Get().(hash.Hash)
h.Reset()
return h
}
func returnSha256(h hash.Hash) {
sha256Pool.Put(h)
}

View file

@ -17,7 +17,6 @@
package bintrie
import (
"crypto/sha256"
"errors"
"fmt"
@ -125,7 +124,8 @@ func (bt *InternalNode) Hash() common.Hash {
return bt.hash
}
h := sha256.New()
h := newSha256()
defer returnSha256(h)
if bt.left != nil {
h.Write(bt.left.Hash().Bytes())
} else {

View file

@ -18,7 +18,6 @@ package bintrie
import (
"bytes"
"crypto/sha256"
"github.com/ethereum/go-ethereum/common"
"github.com/holiman/uint256"
@ -51,7 +50,8 @@ func GetBinaryTreeKey(addr common.Address, key []byte) []byte {
}
func getBinaryTreeKey(addr common.Address, offset []byte, overflow bool) []byte {
hasher := sha256.New()
hasher := newSha256()
defer returnSha256(hasher)
hasher.Write(zeroHash[:12])
hasher.Write(addr[:])
var buf [32]byte

View file

@ -18,7 +18,6 @@ package bintrie
import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"slices"
@ -114,14 +113,17 @@ func (bt *StemNode) Hash() common.Hash {
}
var data [StemNodeWidth]common.Hash
h := newSha256()
defer returnSha256(h)
for i, v := range bt.Values {
if v != nil {
h := sha256.Sum256(v)
data[i] = common.BytesToHash(h[:])
h.Reset()
h.Write(v)
h.Sum(data[i][:0])
}
}
h.Reset()
h := sha256.New()
for level := 1; level <= 8; level++ {
for i := range StemNodeWidth / (1 << level) {
h.Reset()