Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 17 additions & 13 deletions core/state/statedb.libevm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,26 +46,28 @@ func TestStateDBCommitPropagatesOptions(t *testing.T) {
},
},
)
var rec snapTreeRecorder
sdb, err := New(types.EmptyRootHash, NewDatabaseWithNodeDB(memdb, triedb), &rec)
trieRec, _ := triedb.Backend().(*triedbRecorder)
var snapRec snapTreeRecorder
sdb, err := New(types.EmptyRootHash, NewDatabaseWithNodeDB(memdb, triedb), &snapRec)
require.NoError(t, err, "New()")

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

const snapshotPayload = "hello world"
const trieDBPayload = "goodbye world"
var (
parentHash = common.HexToHash("0x0102030405060708090a0b0c0d0e0f1011121314151617181920212223242526")
currentHash = common.HexToHash("0x1234567890123456789012345678901234567890123456789012345678901234")
)
snapshotOpt := stateconf.WithSnapshotUpdatePayload(snapshotPayload)
triedbOpt := stateconf.WithTrieDBUpdatePayload(trieDBPayload)
triedbOpt := stateconf.WithTrieDBUpdatePayload(parentHash, currentHash)
_, err = sdb.Commit(0, false, stateconf.WithSnapshotUpdateOpts(snapshotOpt), stateconf.WithTrieDBUpdateOpts(triedbOpt))
require.NoErrorf(t, err, "%T.Commit(..., %T, %T)", sdb, snapshotOpt, triedbOpt)

assert.Equalf(t, snapshotPayload, rec.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", snapshotOpt, sdb, rec)
innerTrieDB, ok := triedb.Backend().(*triedbRecorder)
if !ok {
t.Fatalf("expected %T to be a *triedbRecorder", triedb.Backend())
}
assert.Equalf(t, trieDBPayload, innerTrieDB.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", triedbOpt, sdb, rec)
require.NoErrorf(t, err, "%T.Commit(..., %T, %T)", sdb, snapshotOpt, triedbOpt)
assert.Equalf(t, snapshotPayload, snapRec.gotPayload, "%T payload propagated via %T.Commit() to %T.Update()", snapshotOpt, sdb, snapRec)
assert.Truef(t, trieRec.exists, "%T exists propagated via %T.Commit() to %T.Update()", triedbOpt, sdb, trieRec)
assert.Equalf(t, parentHash, trieRec.parentBlockHash, "%T parentHash propagated via %T.Commit() to %T.Update()", triedbOpt, sdb, trieRec)
assert.Equalf(t, currentHash, trieRec.currentBlockHash, "%T currentHash propagated via %T.Commit() to %T.Update()", triedbOpt, sdb, trieRec)
}

type snapTreeRecorder struct {
Expand Down Expand Up @@ -104,7 +106,9 @@ func (snapshotStub) Root() common.Hash {

type triedbRecorder struct {
*hashdb.Database
gotPayload any
parentBlockHash common.Hash
currentBlockHash common.Hash
exists bool
}

func (r *triedbRecorder) Update(
Expand All @@ -115,7 +119,7 @@ func (r *triedbRecorder) Update(
states *triestate.Set,
opts ...stateconf.TrieDBUpdateOption,
) error {
r.gotPayload = stateconf.ExtractTrieDBUpdatePayload(opts...)
r.parentBlockHash, r.currentBlockHash, r.exists = stateconf.ExtractTrieDBUpdatePayload(opts...)
return r.Database.Update(root, parent, block, nodes, states)
}

Expand Down
36 changes: 19 additions & 17 deletions libevm/stateconf/conf.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@
package stateconf

import (
"github.com/ava-labs/libevm/common"
"github.com/ava-labs/libevm/libevm/options"
)

// A StateDBCommitOption configures the behaviour of all update calls within the
// state.StateDB.Commit() implementations.
// This is provided in two distinct types to allow customizability to both
// snapshot and trie database updates, but are ignored in libevm implementations.
// A StateDBCommitOption configures the behaviour of state.StateDB.Commit()
type StateDBCommitOption = options.Option[stateDBCommitConfig]

type stateDBCommitConfig struct {
Expand All @@ -34,10 +32,9 @@ type stateDBCommitConfig struct {

// WithSnapshotUpdateOpts returns a StateDBCommitOption carrying a list of
// SnapshotUpdateOptions.
// If the list is not of length 1, the last option in the list is used.
// If multiple such options are used, only the last will be applied as they overwrite each other.
func WithSnapshotUpdateOpts(opts ...SnapshotUpdateOption) StateDBCommitOption {
return options.Func[stateDBCommitConfig](func(c *stateDBCommitConfig) {
// I don't like append() because there's no way to remove options, but that's a weakly held opinion
c.snapshotOpts = opts
})
}
Expand All @@ -49,11 +46,10 @@ func ExtractSnapshotUpdateOpts(opts ...StateDBCommitOption) []SnapshotUpdateOpti
}

// WithTrieDBUpdateOpts returns a StateDBCommitOption carrying a list of
// TrieDBUpdateOptions. If the list is not of length 1, the last option in the
// list is used.
// TrieDBUpdateOptions. If multiple such options are used, only the last will be
// applied as they overwrite each other.
func WithTrieDBUpdateOpts(opts ...TrieDBUpdateOption) StateDBCommitOption {
return options.Func[stateDBCommitConfig](func(c *stateDBCommitConfig) {
// I don't like append() because there's no way to remove options, but that's a weakly held opinion
c.triedbOpts = opts
})
}
Expand Down Expand Up @@ -93,21 +89,27 @@ func ExtractSnapshotUpdatePayload(opts ...SnapshotUpdateOption) any {
type TrieDBUpdateOption = options.Option[triedbUpdateConfig]

type triedbUpdateConfig struct {
payload any
parentBlockHash *common.Hash
currentBlockHash *common.Hash
}

// WithTrieDBUpdatePayload returns a TrieDBUpdateOption carrying an arbitrary
// payload. It acts only as a carrier to exploit existing function plumbing and
// WithTrieDBUpdatePayload returns a TrieDBUpdateOption carrying two block hashes.
// It acts only as a carrier to exploit existing function plumbing and
// the effect on behaviour is left to the implementation receiving it.
func WithTrieDBUpdatePayload(p any) TrieDBUpdateOption {
func WithTrieDBUpdatePayload(parent common.Hash, current common.Hash) TrieDBUpdateOption {
return options.Func[triedbUpdateConfig](func(c *triedbUpdateConfig) {
c.payload = p
c.parentBlockHash = &parent
c.currentBlockHash = &current
})
}

// ExtractTrieDBUpdatePayload returns the payload carried by a [WithSnapshotUpdatePayload]
// ExtractTrieDBUpdatePayload returns the payload carried by a [WithTrieDBUpdatePayload]
// option. Only one such option can be used at once; behaviour is otherwise
// undefined.
func ExtractTrieDBUpdatePayload(opts ...TrieDBUpdateOption) any {
return options.As(opts...).payload
func ExtractTrieDBUpdatePayload(opts ...TrieDBUpdateOption) (common.Hash, common.Hash, bool) {
conf := options.As(opts...)
if conf.parentBlockHash == nil && conf.currentBlockHash == nil {
return common.Hash{}, common.Hash{}, false
}
return *conf.parentBlockHash, *conf.currentBlockHash, true
}
2 changes: 1 addition & 1 deletion triedb/hashdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -549,7 +549,7 @@ func (db *Database) Initialized(genesisRoot common.Hash) bool {

// Update inserts the dirty nodes in provided nodeset into database and link the
// account trie with multiple storage tries if necessary.
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error {
func (db *Database) Update(root common.Hash, parent common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, _ ...stateconf.TrieDBUpdateOption) error {
// Ensure the parent state is present and signal a warning if not.
if parent != types.EmptyRootHash {
if blob, _ := db.node(parent); len(blob) == 0 {
Expand Down
2 changes: 1 addition & 1 deletion triedb/pathdb/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ func (db *Database) Reader(root common.Hash) (layer, error) {
//
// The passed in maps(nodes, states) will be retained to avoid copying everything.
// Therefore, these maps must not be changed afterwards.
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, opts ...stateconf.TrieDBUpdateOption) error {
func (db *Database) Update(root common.Hash, parentRoot common.Hash, block uint64, nodes *trienode.MergedNodeSet, states *triestate.Set, _ ...stateconf.TrieDBUpdateOption) error {
// Hold the lock to prevent concurrent mutations.
db.lock.Lock()
defer db.lock.Unlock()
Expand Down