Skip to content

Commit bae5586

Browse files
committed
fix: use separate types for snapshot and triedb
1 parent 15b7b85 commit bae5586

File tree

8 files changed

+123
-26
lines changed

8 files changed

+123
-26
lines changed

core/state/snapshot/snapshot.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -351,7 +351,7 @@ func (t *Tree) Snapshots(root common.Hash, limits int, nodisk bool) []Snapshot {
351351
// old parent. It is disallowed to insert a disk layer (the origin of all).
352352
//
353353
// libevm: Options are ignored and only included to match an interface method.
354-
func (t *Tree) 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, _ ...stateconf.StateUpdateOption) error {
354+
func (t *Tree) 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, _ ...stateconf.SnapshotUpdateOption) error {
355355
// Reject noop updates to avoid self-loops in the snapshot tree. This is a
356356
// special case that can only happen for Clique networks where empty blocks
357357
// don't modify the state (0 block subsidy).

core/state/statedb.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,7 +1152,7 @@ func (s *StateDB) handleDestruction(nodes *trienode.MergedNodeSet) (map[common.A
11521152
//
11531153
// The associated block number of the state transition is also provided
11541154
// for more chain context.
1155-
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, opts ...stateconf.StateUpdateOption) (common.Hash, error) {
1155+
func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, opts ...stateconf.StateDBCommitOption) (common.Hash, error) {
11561156
// Short circuit in case any database failure occurred earlier.
11571157
if s.dbErr != nil {
11581158
return common.Hash{}, fmt.Errorf("commit aborted due to earlier error: %v", s.dbErr)
@@ -1242,7 +1242,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, opts ...statecon
12421242
start := time.Now()
12431243
// Only update if there's a state transition (skip empty Clique blocks)
12441244
if parent := s.snap.Root(); parent != root {
1245-
if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages, opts...); err != nil {
1245+
if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages, stateconf.ExtractSnapshotUpdateOpts(opts...)...); err != nil {
12461246
log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err)
12471247
}
12481248
// Keep 128 diff layers in the memory, persistent layer is 129th.
@@ -1268,7 +1268,7 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool, opts ...statecon
12681268
if root != origin {
12691269
start := time.Now()
12701270
set := triestate.New(s.accountsOrigin, s.storagesOrigin, incomplete)
1271-
if err := s.db.TrieDB().Update(root, origin, block, nodes, set, opts...); err != nil {
1271+
if err := s.db.TrieDB().Update(root, origin, block, nodes, set, stateconf.ExtractTrieDBUpdateOpts(opts...)...); err != nil {
12721272
return common.Hash{}, err
12731273
}
12741274
s.originalRoot = root

core/state/statedb.libevm.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ type SnapshotTree interface {
3737
destructs map[common.Hash]struct{},
3838
accounts map[common.Hash][]byte,
3939
storage map[common.Hash]map[common.Hash][]byte,
40-
opts ...stateconf.StateUpdateOption,
40+
opts ...stateconf.SnapshotUpdateOption,
4141
) error
4242
}
4343

core/state/statedb.libevm_test.go

Lines changed: 52 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -26,23 +26,46 @@ import (
2626
"github.com/ava-labs/libevm/core/rawdb"
2727
"github.com/ava-labs/libevm/core/state/snapshot"
2828
"github.com/ava-labs/libevm/core/types"
29+
"github.com/ava-labs/libevm/ethdb"
2930
"github.com/ava-labs/libevm/libevm/stateconf"
31+
"github.com/ava-labs/libevm/trie"
32+
"github.com/ava-labs/libevm/trie/trienode"
33+
"github.com/ava-labs/libevm/trie/triestate"
34+
"github.com/ava-labs/libevm/triedb"
35+
"github.com/ava-labs/libevm/triedb/database"
36+
"github.com/ava-labs/libevm/triedb/hashdb"
3037
)
3138

3239
func TestStateDBCommitPropagatesOptions(t *testing.T) {
40+
memdb := rawdb.NewMemoryDatabase()
41+
triedb := triedb.NewDatabase(
42+
memdb,
43+
&triedb.Config{
44+
DBOverride: func(_ ethdb.Database) triedb.DBOverride {
45+
return &triedbRecorder{Database: hashdb.New(memdb, nil, &trie.MerkleResolver{})}
46+
},
47+
},
48+
)
3349
var rec snapTreeRecorder
34-
sdb, err := New(types.EmptyRootHash, NewDatabase(rawdb.NewMemoryDatabase()), &rec)
50+
sdb, err := New(types.EmptyRootHash, NewDatabaseWithNodeDB(memdb, triedb), &rec)
3551
require.NoError(t, err, "New()")
3652

3753
// Ensures that rec.Update() will be called.
3854
sdb.SetNonce(common.Address{}, 42)
3955

40-
const payload = "hello world"
41-
opt := stateconf.WithUpdatePayload(payload)
42-
_, err = sdb.Commit(0, false, opt)
43-
require.NoErrorf(t, err, "%T.Commit(..., %T)", sdb, opt)
56+
const snapshotPayload = "hello world"
57+
const trieDBPayload = "goodbye world"
58+
snapshotOpt := stateconf.WithSnapshotUpdatePayload(snapshotPayload)
59+
triedbOpt := stateconf.WithTrieDBUpdatePayload(trieDBPayload)
60+
_, err = sdb.Commit(0, false, stateconf.WithSnapshotUpdateOpts(snapshotOpt), stateconf.WithTrieDBUpdateOpts(triedbOpt))
61+
require.NoErrorf(t, err, "%T.Commit(..., %T, %T)", sdb, snapshotOpt, triedbOpt)
4462

45-
assert.Equalf(t, payload, rec.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", opt, sdb, rec)
63+
assert.Equalf(t, snapshotPayload, rec.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", snapshotOpt, sdb, rec)
64+
innerTrieDB, ok := triedb.Backend().(*triedbRecorder)
65+
if !ok {
66+
t.Fatalf("expected %T to be a *triedbRecorder", triedb.Backend())
67+
}
68+
assert.Equalf(t, trieDBPayload, innerTrieDB.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", triedbOpt, sdb, rec)
4669
}
4770

4871
type snapTreeRecorder struct {
@@ -57,9 +80,9 @@ func (*snapTreeRecorder) Cap(common.Hash, int) error {
5780
func (r *snapTreeRecorder) Update(
5881
_, _ common.Hash,
5982
_ map[common.Hash]struct{}, _ map[common.Hash][]byte, _ map[common.Hash]map[common.Hash][]byte,
60-
opts ...stateconf.StateUpdateOption,
83+
opts ...stateconf.SnapshotUpdateOption,
6184
) error {
62-
r.gotPayload = stateconf.ExtractUpdatePayload(opts...)
85+
r.gotPayload = stateconf.ExtractSnapshotUpdatePayload(opts...)
6386
return nil
6487
}
6588

@@ -78,3 +101,24 @@ func (snapshotStub) Account(common.Hash) (*types.SlimAccount, error) {
78101
func (snapshotStub) Root() common.Hash {
79102
return common.Hash{}
80103
}
104+
105+
type triedbRecorder struct {
106+
*hashdb.Database
107+
gotPayload any
108+
}
109+
110+
func (r *triedbRecorder) Update(
111+
root common.Hash,
112+
parent common.Hash,
113+
block uint64,
114+
nodes *trienode.MergedNodeSet,
115+
states *triestate.Set,
116+
opts ...stateconf.TrieDBUpdateOption,
117+
) error {
118+
r.gotPayload = stateconf.ExtractTrieDBUpdatePayload(opts...)
119+
return r.Database.Update(root, parent, block, nodes, states)
120+
}
121+
122+
func (r *triedbRecorder) Reader(_ common.Hash) (database.Reader, error) {
123+
return r.Database.Reader(common.Hash{})
124+
}

libevm/stateconf/conf.go

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,29 +17,82 @@
1717
// Package stateconf configures state management.
1818
package stateconf
1919

20-
import "github.com/ava-labs/libevm/libevm/options"
20+
import (
21+
"github.com/ava-labs/libevm/libevm/options"
22+
)
2123

22-
// A StateUpdateOption configures the behaviour of
24+
// A StateDBCommitOption configures the behaviour of all update calls within the
25+
// state.StateDB.Commit() implementations.
26+
type StateDBCommitOption = options.Option[stateDBCommitConfig]
27+
28+
type stateDBCommitConfig struct {
29+
snapshotOpts []SnapshotUpdateOption
30+
triedbOpts []TrieDBUpdateOption
31+
}
32+
33+
// WithSnapshotUpdateOpts returns a StateDBCommitOption carrying a list of
34+
func WithSnapshotUpdateOpts(opts ...SnapshotUpdateOption) StateDBCommitOption {
35+
return options.Func[stateDBCommitConfig](func(c *stateDBCommitConfig) {
36+
// I don't like append() because there's no way to remove options, but that's a weakly held opinion
37+
c.snapshotOpts = opts
38+
})
39+
}
40+
41+
func ExtractSnapshotUpdateOpts(opts ...StateDBCommitOption) []SnapshotUpdateOption {
42+
return options.As(opts...).snapshotOpts
43+
}
44+
45+
func WithTrieDBUpdateOpts(opts ...TrieDBUpdateOption) StateDBCommitOption {
46+
return options.Func[stateDBCommitConfig](func(c *stateDBCommitConfig) {
47+
// I don't like append() because there's no way to remove options, but that's a weakly held opinion
48+
c.triedbOpts = opts
49+
})
50+
}
51+
52+
func ExtractTrieDBUpdateOpts(opts ...StateDBCommitOption) []TrieDBUpdateOption {
53+
return options.As(opts...).triedbOpts
54+
}
55+
56+
// A SnapshotUpdateOption configures the behaviour of
2357
// state.SnapshotTree.Update() implementations. This will be removed along with
2458
// state.SnapshotTree.
25-
type StateUpdateOption = options.Option[stateUpdateOption]
59+
type SnapshotUpdateOption = options.Option[snapshotUpdateConfig]
2660

27-
type stateUpdateOption struct {
61+
type snapshotUpdateConfig struct {
2862
payload any
2963
}
3064

31-
// WithUpdatePayload returns a SnapshotUpdateOption carrying an arbitrary
65+
// WithSnapshotUpdatePayload returns a SnapshotUpdateOption carrying an arbitrary
3266
// payload. It acts only as a carrier to exploit existing function plumbing and
3367
// the effect on behaviour is left to the implementation receiving it.
34-
func WithUpdatePayload(p any) StateUpdateOption {
35-
return options.Func[stateUpdateOption](func(c *stateUpdateOption) {
68+
func WithSnapshotUpdatePayload(p any) SnapshotUpdateOption {
69+
return options.Func[snapshotUpdateConfig](func(c *snapshotUpdateConfig) {
70+
c.payload = p
71+
})
72+
}
73+
74+
// ExtractSnapshotUpdatePayload returns the payload carried by a [WithSnapshotUpdatePayload]
75+
// option. Only one such option can be used at once; behaviour is otherwise
76+
// undefined.
77+
func ExtractSnapshotUpdatePayload(opts ...SnapshotUpdateOption) any {
78+
return options.As(opts...).payload
79+
}
80+
81+
type TrieDBUpdateOption = options.Option[triedbUpdateConfig]
82+
83+
type triedbUpdateConfig struct {
84+
payload any
85+
}
86+
87+
func WithTrieDBUpdatePayload(p any) TrieDBUpdateOption {
88+
return options.Func[triedbUpdateConfig](func(c *triedbUpdateConfig) {
3689
c.payload = p
3790
})
3891
}
3992

40-
// ExtractUpdatePayload returns the payload carried by a [WithUpdatePayload]
93+
// ExtractTrieDBUpdatePayload returns the payload carried by a [WithSnapshotUpdatePayload]
4194
// option. Only one such option can be used at once; behaviour is otherwise
4295
// undefined.
43-
func ExtractUpdatePayload(opts ...StateUpdateOption) any {
96+
func ExtractTrieDBUpdatePayload(opts ...TrieDBUpdateOption) any {
4497
return options.As(opts...).payload
4598
}

triedb/database.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ type backend interface {
7171
//
7272
// The passed in maps(nodes, states) will be retained to avoid copying
7373
// everything. Therefore, these maps must not be changed afterwards.
74-
Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.StateUpdateOption) error
74+
Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error
7575

7676
// Commit writes all relevant trie nodes belonging to the specified state
7777
// to disk. Report specifies whether logs will be displayed in info level.
@@ -149,7 +149,7 @@ func (db *Database) Reader(blockRoot common.Hash) (database.Reader, error) {
149149
//
150150
// The passed in maps(nodes, states) will be retained to avoid copying everything.
151151
// Therefore, these maps must not be changed afterwards.
152-
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.StateUpdateOption) error {
152+
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error {
153153
if db.preimages != nil {
154154
db.preimages.commit(false)
155155
}

triedb/hashdb/database.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -549,7 +549,7 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {
549549

550550
// Update inserts the dirty nodes in provided nodeset into database and link the
551551
// account trie with multiple storage tries if necessary.
552-
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.StateUpdateOption) error {
552+
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error {
553553
// Ensure the parent state is present and signal a warning if not.
554554
if parent != types.EmptyRootHash {
555555
if blob, _ := db.node(parent); len(blob) == 0 {

triedb/pathdb/database.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
224224
//
225225
// The passed in maps(nodes, states) will be retained to avoid copying everything.
226226
// Therefore, these maps must not be changed afterwards.
227-
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.StateUpdateOption) error {
227+
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error {
228228
// Hold the lock to prevent concurrent mutations.
229229
db.lock.Lock()
230230
defer db.lock.Unlock()

0 commit comments

Comments
 (0)