diff --git a/core/rawdb/accessors_trie.go b/core/rawdb/accessors_trie.go index 8bd6b71eee..e154ab527b 100644 --- a/core/rawdb/accessors_trie.go +++ b/core/rawdb/accessors_trie.go @@ -18,7 +18,6 @@ package rawdb import ( "fmt" - "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" @@ -45,25 +44,6 @@ const HashScheme = "hash" // on extra state diffs to survive deep reorg. const PathScheme = "path" -// hasher is used to compute the sha256 hash of the provided data. -type hasher struct{ sha crypto.KeccakState } - -var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, -} - -func newHasher() *hasher { - return hasherPool.Get().(*hasher) -} - -func (h *hasher) hash(data []byte) common.Hash { - return crypto.HashData(h.sha, data) -} - -func (h *hasher) release() { - hasherPool.Put(h) -} - // ReadAccountTrieNode retrieves the account trie node with the specified node path. func ReadAccountTrieNode(db ethdb.KeyValueReader, path []byte) []byte { data, _ := db.Get(accountTrieNodeKey(path)) @@ -170,9 +150,7 @@ func HasTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash c if len(blob) == 0 { return false } - h := newHasher() - defer h.release() - return h.hash(blob) == hash // exists but not match + return crypto.Keccak256Hash(blob) == hash // exists but not match default: panic(fmt.Sprintf("Unknown scheme %v", scheme)) } @@ -194,9 +172,7 @@ func ReadTrieNode(db ethdb.KeyValueReader, owner common.Hash, path []byte, hash if len(blob) == 0 { return nil } - h := newHasher() - defer h.release() - if h.hash(blob) != hash { + if crypto.Keccak256Hash(blob) != hash { return nil // exists but not match } return blob diff --git a/core/state/reader.go b/core/state/reader.go index 5ad0385e9e..09edf6ab8d 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -33,24 +33,6 @@ import ( "github.com/ethereum/go-ethereum/triedb/database" ) -// bufferPool holds the buffers for keccak calculation. -var bufferPool = sync.Pool{ - New: func() interface{} { - return crypto.NewKeccakState() - }, -} - -// allocBuff allocates the keccak buffer from the pool -func allocBuff() crypto.KeccakState { - return bufferPool.Get().(crypto.KeccakState) -} - -// releaseBuff returns the provided keccak buffer to the pool. It's unnecessary -// to clear the buffer, as it will be cleared before the calculation. -func releaseBuff(buff crypto.KeccakState) { - bufferPool.Put(buff) -} - // ContractCodeReader defines the interface for accessing contract code. type ContractCodeReader interface { // Code retrieves a particular contract's code. @@ -167,10 +149,7 @@ func newFlatReader(reader database.StateReader) *flatReader { // // The returned account might be nil if it's not existent. func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) { - buff := allocBuff() - defer releaseBuff(buff) - - account, err := r.reader.Account(crypto.HashData(buff, addr.Bytes())) + account, err := r.reader.Account(crypto.Keccak256Hash(addr.Bytes())) if err != nil { return nil, err } @@ -200,11 +179,8 @@ func (r *flatReader) Account(addr common.Address) (*types.StateAccount, error) { // // The returned storage slot might be empty if it's not existent. func (r *flatReader) Storage(addr common.Address, key common.Hash) (common.Hash, error) { - buff := allocBuff() - defer releaseBuff(buff) - - addrHash := crypto.HashData(buff, addr.Bytes()) - slotHash := crypto.HashData(buff, key.Bytes()) + addrHash := crypto.Keccak256Hash(addr.Bytes()) + slotHash := crypto.Keccak256Hash(key.Bytes()) ret, err := r.reader.Storage(addrHash, slotHash) if err != nil { return common.Hash{}, err diff --git a/core/types/hashing.go b/core/types/hashing.go index 224d7a87ea..3cc22d50d1 100644 --- a/core/types/hashing.go +++ b/core/types/hashing.go @@ -25,12 +25,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" - "golang.org/x/crypto/sha3" ) // hasherPool holds LegacyKeccak256 hashers for rlpHash. var hasherPool = sync.Pool{ - New: func() interface{} { return sha3.NewLegacyKeccak256() }, + New: func() interface{} { return crypto.NewKeccakState() }, } // encodeBufferPool holds temporary encoder buffers for DeriveSha and TX encoding. diff --git a/core/vm/evm.go b/core/vm/evm.go index c28dcb2554..ecb0f118ec 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -555,7 +555,8 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { - contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), crypto.Keccak256(code)) + inithash := crypto.HashData(evm.interpreter.hasher, code) + contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:]) return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) } diff --git a/core/vm/instructions.go b/core/vm/instructions.go index 0b3b1d1569..63bb6d2d51 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -22,7 +22,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" ) @@ -234,11 +233,7 @@ func opKeccak256(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ( offset, size := scope.Stack.pop(), scope.Stack.peek() data := scope.Memory.GetPtr(offset.Uint64(), size.Uint64()) - if interpreter.hasher == nil { - interpreter.hasher = crypto.NewKeccakState() - } else { - interpreter.hasher.Reset() - } + interpreter.hasher.Reset() interpreter.hasher.Write(data) interpreter.hasher.Read(interpreter.hasherBuf[:]) diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index a0038d1aa8..a62c3c843d 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -150,7 +150,7 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter { } } evm.Config.ExtraEips = extraEips - return &EVMInterpreter{evm: evm, table: table} + return &EVMInterpreter{evm: evm, table: table, hasher: crypto.NewKeccakState()} } // Run loops and evaluates the contract's code with the given input data and returns diff --git a/crypto/crypto.go b/crypto/crypto.go index 13e9b134f0..09596c05ce 100644 --- a/crypto/crypto.go +++ b/crypto/crypto.go @@ -28,6 +28,7 @@ import ( "io" "math/big" "os" + "sync" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" @@ -73,6 +74,12 @@ func NewKeccakState() KeccakState { return sha3.NewLegacyKeccak256().(KeccakState) } +var hasherPool = sync.Pool{ + New: func() any { + return sha3.NewLegacyKeccak256().(KeccakState) + }, +} + // HashData hashes the provided data using the KeccakState and returns a 32 byte hash func HashData(kh KeccakState, data []byte) (h common.Hash) { kh.Reset() @@ -84,22 +91,26 @@ func HashData(kh KeccakState, data []byte) (h common.Hash) { // Keccak256 calculates and returns the Keccak256 hash of the input data. func Keccak256(data ...[]byte) []byte { b := make([]byte, 32) - d := NewKeccakState() + d := hasherPool.Get().(KeccakState) + d.Reset() for _, b := range data { d.Write(b) } d.Read(b) + hasherPool.Put(d) return b } // Keccak256Hash calculates and returns the Keccak256 hash of the input data, // converting it to an internal Hash data structure. func Keccak256Hash(data ...[]byte) (h common.Hash) { - d := NewKeccakState() + d := hasherPool.Get().(KeccakState) + d.Reset() for _, b := range data { d.Write(b) } d.Read(h[:]) + hasherPool.Put(d) return h } diff --git a/trie/hasher.go b/trie/hasher.go index 614640ae3a..393cb0bd4d 100644 --- a/trie/hasher.go +++ b/trie/hasher.go @@ -34,7 +34,7 @@ type hasher struct { // hasherPool holds pureHashers var hasherPool = sync.Pool{ - New: func() interface{} { + New: func() any { return &hasher{ tmp: make([]byte, 0, 550), // cap is as large as a full fullNode. sha: crypto.NewKeccakState(), diff --git a/trie/sync.go b/trie/sync.go index 3b7caae5b1..8d0ce6901c 100644 --- a/trie/sync.go +++ b/trie/sync.go @@ -729,9 +729,7 @@ func (s *Sync) hasNode(owner common.Hash, path []byte, hash common.Hash) (exists } else { blob = rawdb.ReadStorageTrieNode(s.database, owner, path) } - h := newBlobHasher() - defer h.release() - exists = hash == h.hash(blob) + exists = hash == crypto.Keccak256Hash(blob) inconsistent = !exists && len(blob) != 0 return exists, inconsistent } @@ -746,23 +744,3 @@ func ResolvePath(path []byte) (common.Hash, []byte) { } return owner, path } - -// blobHasher is used to compute the sha256 hash of the provided data. -type blobHasher struct{ state crypto.KeccakState } - -// blobHasherPool is the pool for reusing pre-allocated hash state. -var blobHasherPool = sync.Pool{ - New: func() interface{} { return &blobHasher{state: crypto.NewKeccakState()} }, -} - -func newBlobHasher() *blobHasher { - return blobHasherPool.Get().(*blobHasher) -} - -func (h *blobHasher) hash(data []byte) common.Hash { - return crypto.HashData(h.state, data) -} - -func (h *blobHasher) release() { - blobHasherPool.Put(h) -} diff --git a/triedb/pathdb/disklayer.go b/triedb/pathdb/disklayer.go index f3a60a507d..b8869888d9 100644 --- a/triedb/pathdb/disklayer.go +++ b/triedb/pathdb/disklayer.go @@ -115,15 +115,12 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co dirtyNodeMissMeter.Mark(1) // Try to retrieve the trie node from the clean memory cache - h := newHasher() - defer h.release() - key := nodeCacheKey(owner, path) if dl.nodes != nil { if blob := dl.nodes.Get(nil, key); len(blob) > 0 { cleanNodeHitMeter.Mark(1) cleanNodeReadMeter.Mark(int64(len(blob))) - return blob, h.hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil + return blob, crypto.Keccak256Hash(blob), &nodeLoc{loc: locCleanCache, depth: depth}, nil } cleanNodeMissMeter.Mark(1) } @@ -138,7 +135,7 @@ func (dl *diskLayer) node(owner common.Hash, path []byte, depth int) ([]byte, co dl.nodes.Set(key, blob) cleanNodeWriteMeter.Mark(int64(len(blob))) } - return blob, h.hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil + return blob, crypto.Keccak256Hash(blob), &nodeLoc{loc: locDiskLayer, depth: depth}, nil } // account directly retrieves the account RLP associated with a particular @@ -359,22 +356,3 @@ func (dl *diskLayer) resetCache() { dl.nodes.Reset() } } - -// hasher is used to compute the sha256 hash of the provided data. -type hasher struct{ sha crypto.KeccakState } - -var hasherPool = sync.Pool{ - New: func() interface{} { return &hasher{sha: crypto.NewKeccakState()} }, -} - -func newHasher() *hasher { - return hasherPool.Get().(*hasher) -} - -func (h *hasher) hash(data []byte) common.Hash { - return crypto.HashData(h.sha, data) -} - -func (h *hasher) release() { - hasherPool.Put(h) -} diff --git a/triedb/pathdb/execute.go b/triedb/pathdb/execute.go index 2400f280a3..db1e679277 100644 --- a/triedb/pathdb/execute.go +++ b/triedb/pathdb/execute.go @@ -22,6 +22,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie/trienode" @@ -85,10 +86,9 @@ func apply(db database.NodeDatabase, prevRoot common.Hash, postRoot common.Hash, func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) error { // The account was present in prev-state, decode it from the // 'slim-rlp' format bytes. - h := newHasher() - defer h.release() + h := crypto.NewKeccakState() - addrHash := h.hash(addr.Bytes()) + addrHash := crypto.HashData(h, addr.Bytes()) prev, err := types.FullAccount(ctx.accounts[addr]) if err != nil { return err @@ -113,7 +113,7 @@ func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) for key, val := range ctx.storages[addr] { tkey := key if ctx.rawStorageKey { - tkey = h.hash(key.Bytes()) + tkey = crypto.HashData(h, key.Bytes()) } var err error if len(val) == 0 { @@ -149,10 +149,9 @@ func updateAccount(ctx *context, db database.NodeDatabase, addr common.Address) // account and storage is wiped out correctly. func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address) error { // The account must be existent in post-state, load the account. - h := newHasher() - defer h.release() + h := crypto.NewKeccakState() - addrHash := h.hash(addr.Bytes()) + addrHash := crypto.HashData(h, addr.Bytes()) blob, err := ctx.accountTrie.Get(addrHash.Bytes()) if err != nil { return err @@ -174,7 +173,7 @@ func deleteAccount(ctx *context, db database.NodeDatabase, addr common.Address) } tkey := key if ctx.rawStorageKey { - tkey = h.hash(key.Bytes()) + tkey = crypto.HashData(h, key.Bytes()) } if err := st.Delete(tkey.Bytes()); err != nil { return err