However, this iteration is not performed in the order of emission for these events. The following code enforces a particular order for prevPayloadEvents:
// Collect local view of the evm logs from the previous payload.
evmEvents, err := s.evmEvents(ctx, payload.ParentHash)
if err != nil {
return nil, errors.Wrap(err, "prepare evm event logs")
}
// Ensure the proposed evm event logs are equal to the local view.
if err := evmEventsEqual(evmEvents, msg.PrevPayloadEvents); err != nil {
return nil, errors.Wrap(err, "verify prev payload events")
}
They need to have the same order as the function evmEvents returns, which is sorted by Address > Topics > Data:
This is problematic because the order is important for some events. For instance, if you submit three calls addOperator(A), removeOperator(A), addOperator(B) (in this order). You would expect a final result of operator B being added. If they are in the same block, this is not guaranteed and everything can happen based on the order of their topics and then the order of the data. In practice (because the distinguishing factor will be topic[0], i.e. the hash of the event definition), all addOperator or removeOperator calls would be processed first and then the other ones, which is not the expected behavior for the previously mentioned case.
Solution recommendation
Consider the log index when sorting (this is returned by k.engineCl.FilterLogs, which is called already, so should be easy to implement).
Description and context
In keeper.go, there is the function
ProcessStakingEvents
that iterates over all events which are emitted from the staking event (in one block): https://github.com/piplabs/story/blob/46dabe3131eb762c0c827fa3aa3eff47ec95f011/client/x/evmstaking/keeper/keeper.go#L111However, this iteration is not performed in the order of emission for these events. The following code enforces a particular order for
prevPayloadEvents
:They need to have the same order as the function
evmEvents
returns, which is sorted by Address > Topics > Data:This is problematic because the order is important for some events. For instance, if you submit three calls
addOperator(A)
,removeOperator(A)
,addOperator(B)
(in this order). You would expect a final result of operator B being added. If they are in the same block, this is not guaranteed and everything can happen based on the order of their topics and then the order of the data. In practice (because the distinguishing factor will betopic[0]
, i.e. the hash of the event definition), alladdOperator
orremoveOperator
calls would be processed first and then the other ones, which is not the expected behavior for the previously mentioned case.Solution recommendation
Consider the log index when sorting (this is returned by
k.engineCl.FilterLogs
, which is called already, so should be easy to implement).