core/state: make statedb/stateobjects reuse a hasher

This commit is contained in:
Martin Holst Swende 2020-02-07 10:39:08 +01:00
parent 31e89911b1
commit 3f4bc341c5
No known key found for this signature in database
GPG key ID: 683B438C05A5DDF0
4 changed files with 37 additions and 4 deletions

View file

@ -325,6 +325,7 @@ func (s *stateObject) updateTrie(db Database) Trie {
var storage map[common.Hash][]byte var storage map[common.Hash][]byte
// Insert all the pending updates into the trie // Insert all the pending updates into the trie
tr := s.getTrie(db) tr := s.getTrie(db)
hasher := s.db.hasher
for key, value := range s.pendingStorage { for key, value := range s.pendingStorage {
// Skip noop changes, persist actual changes // Skip noop changes, persist actual changes
if value == s.originStorage[key] { if value == s.originStorage[key] {
@ -349,7 +350,7 @@ func (s *stateObject) updateTrie(db Database) Trie {
s.db.snapStorage[s.addrHash] = storage s.db.snapStorage[s.addrHash] = storage
} }
} }
storage[crypto.Keccak256Hash(key[:])] = v // v will be nil if value is 0x00 storage[crypto.HashData(hasher, key[:])] = v // v will be nil if value is 0x00
} }
} }
if len(s.pendingStorage) > 0 { if len(s.pendingStorage) > 0 {

View file

@ -64,8 +64,9 @@ func (n *proofList) Delete(key []byte) error {
// * Contracts // * Contracts
// * Accounts // * Accounts
type StateDB struct { type StateDB struct {
db Database db Database
trie Trie trie Trie
hasher crypto.KeccakHasher
snaps *snapshot.Tree snaps *snapshot.Tree
snap snapshot.Snapshot snap snapshot.Snapshot
@ -131,6 +132,7 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
logs: make(map[common.Hash][]*types.Log), logs: make(map[common.Hash][]*types.Log),
preimages: make(map[common.Hash][]byte), preimages: make(map[common.Hash][]byte),
journal: newJournal(), journal: newJournal(),
hasher: crypto.NewKeccakHasher(),
} }
if sdb.snaps != nil { if sdb.snaps != nil {
if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil { if sdb.snap = sdb.snaps.Snapshot(root); sdb.snap != nil {
@ -516,7 +518,7 @@ func (s *StateDB) getDeletedStateObject(addr common.Address) *stateObject {
defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now()) defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now())
} }
var acc *snapshot.Account var acc *snapshot.Account
if acc, err = s.snap.Account(crypto.Keccak256Hash(addr[:])); err == nil { if acc, err = s.snap.Account(crypto.HashData(s.hasher, addr[:])); err == nil {
if acc == nil { if acc == nil {
return nil return nil
} }
@ -648,6 +650,7 @@ func (s *StateDB) Copy() *StateDB {
logSize: s.logSize, logSize: s.logSize,
preimages: make(map[common.Hash][]byte, len(s.preimages)), preimages: make(map[common.Hash][]byte, len(s.preimages)),
journal: newJournal(), journal: newJournal(),
hasher: crypto.NewKeccakHasher(),
} }
// Copy the dirty states, logs, and preimages // Copy the dirty states, logs, and preimages
for addr := range s.journal.dirties { for addr := range s.journal.dirties {

View file

@ -24,6 +24,7 @@ import (
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
"hash"
"io" "io"
"io/ioutil" "io/ioutil"
"math/big" "math/big"
@ -51,6 +52,27 @@ var (
var errInvalidPubkey = errors.New("invalid secp256k1 public key") var errInvalidPubkey = errors.New("invalid secp256k1 public key")
// KeccakHasher wraps sha3.state. In addition to the usual hash methods, it also supports
// Read to get a variable amount of data from the hash state. Read is faster than Sum
// because it doesn't copy the internal state, but also modifies the internal state.
type KeccakHasher interface {
hash.Hash
Read([]byte) (int, error)
}
func NewKeccakHasher() KeccakHasher {
return sha3.NewLegacyKeccak256().(KeccakHasher)
}
// hashData hashes the provided data and returns a 32 byte hash
// This method is not threadsafe
func HashData(kh KeccakHasher, data []byte) (h common.Hash) {
kh.Reset()
kh.Write(data)
kh.Read(h[:])
return h
}
// Keccak256 calculates and returns the Keccak256 hash of the input data. // Keccak256 calculates and returns the Keccak256 hash of the input data.
func Keccak256(data ...[]byte) []byte { func Keccak256(data ...[]byte) []byte {
d := sha3.NewLegacyKeccak256() d := sha3.NewLegacyKeccak256()

View file

@ -42,6 +42,13 @@ func TestKeccak256Hash(t *testing.T) {
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp) checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := Keccak256Hash(in); return h[:] }, msg, exp)
} }
func TestKeccak256Hasher(t *testing.T) {
msg := []byte("abc")
exp, _ := hex.DecodeString("4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45")
hasher := NewKeccakHasher()
checkhash(t, "Sha3-256-array", func(in []byte) []byte { h := HashData(hasher, in); return h[:] }, msg, exp)
}
func TestToECDSAErrors(t *testing.T) { func TestToECDSAErrors(t *testing.T) {
if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil { if _, err := HexToECDSA("0000000000000000000000000000000000000000000000000000000000000000"); err == nil {
t.Fatal("HexToECDSA should've returned error") t.Fatal("HexToECDSA should've returned error")