diff --git a/core/state/statedb.go b/core/state/statedb.go index 3b706002e765..eb0f0117bf8a 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -63,7 +63,7 @@ type StateDB struct { prefetcher *triePrefetcher trie Trie hasher crypto.KeccakState - snaps *snapshot.Tree // Nil if snapshot is not available + snaps SnapshotTree // Nil if snapshot is not available snap snapshot.Snapshot // Nil if snapshot is not available // originalRoot is the pre-state root, before any changes were made. @@ -141,7 +141,8 @@ type StateDB struct { } // New creates a new state from a given trie. -func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { +func New(root common.Hash, db Database, snaps SnapshotTree) (*StateDB, error) { + snaps = clearTypedNilPointer(snaps) tr, err := db.OpenTrie(root) if err != nil { return nil, err diff --git a/core/state/statedb.libevm.go b/core/state/statedb.libevm.go new file mode 100644 index 000000000000..ecdfa58660f9 --- /dev/null +++ b/core/state/statedb.libevm.go @@ -0,0 +1,51 @@ +// Copyright 2024 the libevm authors. +// +// The libevm additions to go-ethereum are free software: you can redistribute +// them and/or modify them 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 libevm additions are distributed in the hope that they 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 +// . + +package state + +import ( + "reflect" + + "github.com/ava-labs/libevm/common" + "github.com/ava-labs/libevm/core/state/snapshot" +) + +// SnapshotTree mirrors the functionality of a [snapshot.Tree], allowing for +// drop-in replacements. +type SnapshotTree interface { + Cap(common.Hash, int) error + Snapshot(common.Hash) snapshot.Snapshot + StorageIterator(root, account, seek common.Hash) (snapshot.StorageIterator, error) + Update( + blockRoot common.Hash, + parentRoot common.Hash, + destructs map[common.Hash]struct{}, + accounts map[common.Hash][]byte, + storage map[common.Hash]map[common.Hash][]byte, + ) error +} + +var _ SnapshotTree = (*snapshot.Tree)(nil) + +// clearTypedNilPointer returns nil if `snaps == nil` or if it holds a nil +// pointer. The default geth behaviour expected a [snapshot.Tree] pointer +// instead of a SnapshotTree interface, which could result in typed-nil bugs. +func clearTypedNilPointer(snaps SnapshotTree) SnapshotTree { + if v := reflect.ValueOf(snaps); v.Kind() == reflect.Pointer && v.IsNil() { + return nil + } + return snaps +}