Skip to content

Commit

Permalink
Problem: native action don't support events (evmos#338)
Browse files Browse the repository at this point in the history
* Problem: native action don't support events

Solution:
- manage the events and reverts

* Update x/evm/statedb/statedb.go

Signed-off-by: yihuang <[email protected]>

* gofumpt

* fix nil pointer

* Update x/evm/statedb/statedb.go

Co-authored-by: mmsqe <[email protected]>
Signed-off-by: yihuang <[email protected]>

* fix unit test

---------

Signed-off-by: yihuang <[email protected]>
Co-authored-by: mmsqe <[email protected]>
  • Loading branch information
yihuang and mmsqe authored Sep 8, 2023
1 parent 6687371 commit 433acb2
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 8 deletions.
2 changes: 2 additions & 0 deletions x/evm/statedb/native.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ var _ JournalEntry = nativeChange{}

type nativeChange struct {
snapshot types.MultiStore
events int
}

func (native nativeChange) Dirtied() *common.Address {
Expand All @@ -17,4 +18,5 @@ func (native nativeChange) Dirtied() *common.Address {

func (native nativeChange) Revert(s *StateDB) {
s.restoreNativeState(native.snapshot)
s.nativeEvents = s.nativeEvents[:len(s.nativeEvents)-native.events]
}
25 changes: 19 additions & 6 deletions x/evm/statedb/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,9 @@ type StateDB struct {

// Per-transaction access list
accessList *accessList

// events emitted by native action
nativeEvents sdk.Events
}

// New creates a new state from a given trie.
Expand All @@ -81,10 +84,15 @@ func New(ctx sdk.Context, keeper Keeper, txConfig TxConfig) *StateDB {
journal: newJournal(),
accessList: newAccessList(),

txConfig: txConfig,
txConfig: txConfig,
nativeEvents: sdk.Events{},
}
}

func (s *StateDB) NativeEvents() sdk.Events {
return s.nativeEvents
}

// CacheMultiStore cast the multistore to *cachemulti.Store.
// invariant: the multistore must be a `cachemulti.Store`,
// prove: it's set in constructor and only modified in `restoreNativeState` which keeps the invariant.
Expand Down Expand Up @@ -313,20 +321,23 @@ func (s *StateDB) setStateObject(object *stateObject) {
func (s *StateDB) restoreNativeState(ms sdk.MultiStore) {
manager := sdk.NewEventManager()
s.cacheCtx = s.cacheCtx.WithMultiStore(ms).WithEventManager(manager)

}

// ExecuteNativeAction executes native action in isolate,
// the writes will be revert when either the native action itself fail
// or the wrapping message call reverted.
func (s *StateDB) ExecuteNativeAction(action func(ctx sdk.Context) error) error {
snapshot := s.CacheMultiStore().Clone()
err := action(s.cacheCtx)
if err != nil {
eventManager := sdk.NewEventManager()

if err := action(s.cacheCtx.WithEventManager(eventManager)); err != nil {
s.restoreNativeState(snapshot)
return err
}
s.journal.append(nativeChange{snapshot: snapshot})

events := eventManager.Events()
s.nativeEvents = s.nativeEvents.AppendEvents(events)
s.journal.append(nativeChange{snapshot: snapshot, events: len(events)})
return nil
}

Expand Down Expand Up @@ -486,7 +497,9 @@ func (s *StateDB) Commit() error {
// commit the native cache store first,
// the states managed by precompiles and the other part of StateDB must not overlap.
s.CacheMultiStore().Write()
s.ctx.EventManager().EmitEvents(s.cacheCtx.EventManager().Events())
if len(s.nativeEvents) > 0 {
s.ctx.EventManager().EmitEvents(s.nativeEvents)
}

for _, addr := range s.journal.sortedDirties() {
obj := s.stateObjects[addr]
Expand Down
25 changes: 23 additions & 2 deletions x/evm/statedb/statedb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() {
}
for _, tc := range testCases {
suite.Run(tc.name, func() {
ctx := sdk.Context{}
ctx := sdk.Context{}.WithEventManager(sdk.NewEventManager())
keeper := NewMockKeeper()

{
Expand Down Expand Up @@ -365,7 +365,8 @@ func (suite *StateDBTestSuite) TestRevertSnapshot() {
suite.Require().NoError(db.Commit())

// check keeper should stay the same
suite.Require().Equal(originalKeeper, keeper)
suite.Require().Equal(originalKeeper.accounts, keeper.accounts)
suite.Require().Equal(originalKeeper.codes, keeper.codes)
})
}
}
Expand Down Expand Up @@ -587,14 +588,19 @@ func (suite *StateDBTestSuite) TestNativeAction() {
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
store.Set([]byte("success1"), []byte("value"))
ctx.EventManager().EmitEvent(sdk.NewEvent("success1"))
return nil
})
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
store.Set([]byte("failure1"), []byte("value"))
ctx.EventManager().EmitEvent(sdk.NewEvent("failure1"))
return errors.New("failure")
})

// check events
suite.Require().Equal(sdk.Events{{Type: "success1"}}, stateDB.NativeEvents())

// test query
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
Expand All @@ -607,14 +613,19 @@ func (suite *StateDBTestSuite) TestNativeAction() {
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
store.Set([]byte("success2"), []byte("value"))
ctx.EventManager().EmitEvent(sdk.NewEvent("success2"))
return nil
})
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
store.Set([]byte("failure2"), []byte("value"))
ctx.EventManager().EmitEvent(sdk.NewEvent("failure2"))
return errors.New("failure")
})

// check events
suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success2"}}, stateDB.NativeEvents())

// test query
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
Expand All @@ -626,13 +637,20 @@ func (suite *StateDBTestSuite) TestNativeAction() {

stateDB.RevertToSnapshot(rev1)

// check events
suite.Require().Equal(sdk.Events{{Type: "success1"}}, stateDB.NativeEvents())

_ = stateDB.Snapshot()
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
store.Set([]byte("success3"), []byte("value"))
ctx.EventManager().EmitEvent(sdk.NewEvent("success3"))
return nil
})

// check events
suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success3"}}, stateDB.NativeEvents())

// test query
stateDB.ExecuteNativeAction(func(ctx sdk.Context) error {
store := ctx.KVStore(keys["storekey"])
Expand All @@ -651,6 +669,9 @@ func (suite *StateDBTestSuite) TestNativeAction() {
suite.Require().Equal([]byte("value"), store.Get([]byte("success3")))
suite.Require().Nil(store.Get([]byte("failure1")))
suite.Require().Nil(store.Get([]byte("failure2")))

// check events
suite.Require().Equal(sdk.Events{{Type: "success1"}, {Type: "success3"}}, ctx.EventManager().Events())
}

func CollectContractStorage(db vm.StateDB) statedb.Storage {
Expand Down

0 comments on commit 433acb2

Please sign in to comment.