core/state: optimize transient storage (#33695)
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

Optimizes the transient storage. Turns it from a map of maps into a single map keyed by <account,slot>.
This commit is contained in:
cui 2026-04-14 21:39:42 +08:00 committed by GitHub
parent c690d6041e
commit 2414861d36
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 27 additions and 31 deletions

View file

@ -641,7 +641,7 @@ func (test *snapshotTest) checkEqual(state, checkstate *StateDB) error {
{ {
have := state.transientStorage have := state.transientStorage
want := checkstate.transientStorage want := checkstate.transientStorage
if !maps.EqualFunc(have, want, maps.Equal) { if !maps.Equal(have, want) {
return fmt.Errorf("transient storage differs ,have\n%v\nwant\n%v", return fmt.Errorf("transient storage differs ,have\n%v\nwant\n%v",
have.PrettyPrint(), have.PrettyPrint(),
want.PrettyPrint()) want.PrettyPrint())

View file

@ -25,8 +25,13 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
) )
type transientStorageKey struct {
addr common.Address
key common.Hash
}
// transientStorage is a representation of EIP-1153 "Transient Storage". // transientStorage is a representation of EIP-1153 "Transient Storage".
type transientStorage map[common.Address]Storage type transientStorage map[transientStorageKey]common.Hash
// newTransientStorage creates a new instance of a transientStorage. // newTransientStorage creates a new instance of a transientStorage.
func newTransientStorage() transientStorage { func newTransientStorage() transientStorage {
@ -35,52 +40,43 @@ func newTransientStorage() transientStorage {
// Set sets the transient-storage `value` for `key` at the given `addr`. // Set sets the transient-storage `value` for `key` at the given `addr`.
func (t transientStorage) Set(addr common.Address, key, value common.Hash) { func (t transientStorage) Set(addr common.Address, key, value common.Hash) {
tsKey := transientStorageKey{addr: addr, key: key}
if value == (common.Hash{}) { // this is a 'delete' if value == (common.Hash{}) { // this is a 'delete'
if _, ok := t[addr]; ok { delete(t, tsKey)
delete(t[addr], key)
if len(t[addr]) == 0 {
delete(t, addr)
}
}
} else { } else {
if _, ok := t[addr]; !ok { t[tsKey] = value
t[addr] = make(Storage)
}
t[addr][key] = value
} }
} }
// Get gets the transient storage for `key` at the given `addr`. // Get gets the transient storage for `key` at the given `addr`.
func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash { func (t transientStorage) Get(addr common.Address, key common.Hash) common.Hash {
val, ok := t[addr] tsKey := transientStorageKey{addr: addr, key: key}
if !ok { return t[tsKey]
return common.Hash{}
}
return val[key]
} }
// Copy does a deep copy of the transientStorage // Copy does a deep copy of the transientStorage
func (t transientStorage) Copy() transientStorage { func (t transientStorage) Copy() transientStorage {
storage := make(transientStorage) return maps.Clone(t)
for key, value := range t {
storage[key] = value.Copy()
}
return storage
} }
// PrettyPrint prints the contents of the access list in a human-readable form // PrettyPrint prints the contents of the access list in a human-readable form
func (t transientStorage) PrettyPrint() string { func (t transientStorage) PrettyPrint() string {
out := new(strings.Builder) out := new(strings.Builder)
sortedAddrs := slices.Collect(maps.Keys(t)) sortedTSKeys := slices.Collect(maps.Keys(t))
slices.SortFunc(sortedAddrs, common.Address.Cmp) slices.SortFunc(sortedTSKeys, func(a, b transientStorageKey) int {
r := a.addr.Cmp(b.addr)
if r != 0 {
return r
}
return a.key.Cmp(b.key)
})
for _, addr := range sortedAddrs { for i := 0; i < len(sortedTSKeys); {
fmt.Fprintf(out, "%#x:", addr) tsKey := sortedTSKeys[i]
storage := t[addr] fmt.Fprintf(out, "%#x:", tsKey.addr)
sortedKeys := slices.Collect(maps.Keys(storage)) for ; i < len(sortedTSKeys) && sortedTSKeys[i].addr == tsKey.addr; i++ {
slices.SortFunc(sortedKeys, common.Hash.Cmp) tsKey2 := sortedTSKeys[i]
for _, key := range sortedKeys { fmt.Fprintf(out, " %X : %X\n", tsKey2.key, t[tsKey2])
fmt.Fprintf(out, " %X : %X\n", key, storage[key])
} }
} }
return out.String() return out.String()