-
Notifications
You must be signed in to change notification settings - Fork 410
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Document event handling #581
Conversation
@alpe I took inspiration from your PR #583 and your issues, and went on to define the entire event system. This is one possible definition of how events work, let's adjust it to make it the best it can be. |
PD Does it make sense to use Go types when listing events? (It was a lot shorter than writing proper JSON all those places, which is why I did it, but maybe there is a better format we could use) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Excellent writeup and best doc on event internals I have seen in cosmos. ❤️
The Go type examples worked for me and expressed the scenarios very well. Don't worry, we can always change the doc in a new iteration.
EVENTS.md
Outdated
for all messages that it returned, which were later dispatched. | ||
|
||
Until 0.18.0, we stripped out the `message` events that were returned when dispatching `Response.messages`. However, | ||
they contain useful information to trace the topography of the call, especially when we call into native modules, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If all sdk modules would follow the distribution
event design, I would totally agree on this approach. Unfortunately the bank module emits a message
event in the keeper. Probably others as well.
We call the keeper when we transfer coins to the contract account. This would result into 2 different message events where only the wasm one is correct.
A more consistent approach was the message filtering so that we only track the message initiating the whole process via event. We do loose information going this way, but I would prefer this rather than emitting false positives.
We could also address the bank message issue by filtering out the bank message in our BankCoinTransferrer
. For native modules calling the bank keeper this would not work though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Afaik, we call the router for most dispatching (except ibc) and thus hit the message server as well.
I also hear your point about the non standard issue. But it is very useful to have a separator between the different sub messages.
How about this:
- Filter out the inconsistent message event emitted by the module.
- Always prepend a standard event type on the beginning of each submessage. We can define what it is, it is created by x/wasm and will be very consistent.
EVENTS.md
Outdated
address), it will emit a series of events that looks something like this: | ||
|
||
```go | ||
/// original execution (top-level message) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This list of events describe the process flow but as events are emitted after execution the actual order would be different. I think L321 would be the last event emitted when the original message was processed. L330 would be the first one when we handle the first contract response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can change what happens. I want to document the desired behaviour in here (which will be actual behaviour with the 0.18.0 tag), not the current behaviour.
We have control in x/wasm to do something like:
- Keeper.execute called
- call wasmvm.execute
- emit
execute
message including the data from the response - emit
wasm
andwasm-*
events from the contract - for each message in Response:
- emit some "start sub message" event (if desired)
- call the execution logic here (and emit all events like this, recursively - filtering message event)
- emit some "stop sub message event"?
- emit any other events we wish
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As to the message: module=wasm
, this is emitted in the message server and we can perform this any way we want to.
We can add it top the event manager before calling the keeper, or afterwards. I think placing it first (as in distribution) makes more sense than at the end (in bank).
What do you think the desired behaviour here is?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO to emit the events in order of processing is better than what we do now. It should not matter but for debugging and flattening, I can see the benefit.
EVENTS.md
Outdated
sdk.NewAttribute("result", hex.EncodeToString(initData)), | ||
) | ||
sdk.NewEvent( | ||
"wasm", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this event with some distance now, I don't see how it adds value. Before the contract address was not available but it is now by the wasm operation event. Would be nice to drop this functionality and let people emit custom events when needed. That would be easier to explain in dev doc and no "empty" event would be emitted by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, if I return non-empty attributes
, then it will get this wasm
event (tagged).
If I return empty attributes, it will not get this event, right?
The one issue I want to bring up (which came up from Secret network some time ago) is they want to be able to search for all actions on a contract easily. We can now search for execute._contract_address="foo"
. However, maybe we also want to include instantiate._contract_address="foo"
and migrate._contract_address="foo"
. I guess all data is there.
So, yeah, if we say don't emit wasm
event on empty attributes, I am fine with that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would go one step further and drop the whole event. Why stick with a wasm
event when we have custom events now for a contract? I don't see the use case for a client anymore. But there is complexity in wasmd to handle the case and complexity in wasm contracts for people to learn and understand the framework. Both sides would benefit from a clean design that does not support 2 ways of storing data in events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
90% of contracts just want to emit attributes.
Only a few emit multiple events.
We didn't want to make it that much more complex for all of them, which is why we didn't remove the attributes when we introduced events.
But you have a point. And with the new builder API from @uint we could even let people just add_attribute
still and just expose them as a wasm-default
event (so we keep the same cosmwasm-std api, but change the wasm interface between contract and runtime).
That is a larger discussion, and 0.16 is already cut. I feel it might be too late to make this change, but we could consider it for 1.0.0-beta.
That said, I would document both paths for now as we will support both in 0.18. If we change that for 1.0.0-beta, we can update the doc as well.
I integrated feedback on the two clear suggestions (no _code_id injection and not emitted wasm event at all if no attributes in the Response). Let's talk more about the use of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think of this proposal?
If you like it, I can flesh it out with a more complex example, where we have a multi-level tree and both instantiate and reply dispatch messages to demonstrate the ordering here.
@alpe I revised this and I think addressed you concerns in be3fcf1 Note that I would strongly like to mark every CosmWasm contract entry point called, as this can be very useful to understand a contract. I also remove the (potentially very large) result attribute from the events 79f3fad as I see no need to return them now that we have better handling of the data response with submessages and can return a chosen value to the top level |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice updates! 🌻 Two points left where we had disagreed:
Reply
: I was focused on business app working with events but I could imagine that there is space for technical ones as well to expose internals like block explorers or IBC network graphs do. 🤷 So let's find some good attributes and do thiswasmvmtypes.EventAttribute
: I do understand the value for Rust devs to create events easily but in the overall design there should not be 2 ways to create an event. Custom events are more powerful and should be preferred instead. Let's remove EventAttributes from the response 🙏 For the contract developers we could have a nice function to initialize a custom event with some defaults instead
EVENTS.md
Outdated
sdk.NewEvent( | ||
"reply", | ||
sdk.NewAttribute("_contract_addr", contractAddr.String()), | ||
sdk.NewAttribute("success", strconv.FormatBool(err == nil)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate what "success" means in this context? When the reply handling fails with an error we revert the TX.
To trace the replay call, we could store the submessage reply condition as an attribute: Always, Success, Error.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be renamed to give more clarity.
When reply is called, it receives the result of a sub message processing, which is either "Ok" or "Err".
If I have RelyOn::Always, is is useful to see if I am processing a success call, or handling an error callback.
The main use-case is for devs having some visibility.
Do you have an idea for a better name?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about ("submsg", "ok")
and ("submsg", "err")
as the two options here? To show if we are processing a success case or handling an error.
Better suggestions welcome
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how about: "mode": "handle_success" || "handle_failure"
Codecov Report
@@ Coverage Diff @@
## master #581 +/- ##
==========================================
+ Coverage 59.70% 59.74% +0.03%
==========================================
Files 45 45
Lines 5212 5212
==========================================
+ Hits 3112 3114 +2
+ Misses 1874 1873 -1
+ Partials 226 225 -1
|
This goes into great detail on both how Tendermint and the Cosmos SDK handle events, as well as how we work with them in
x/wasm
and when interfacing with smart contracts.This documents a spec on the desired format for implementing #440
Closes #448 and remove all filtering of
message
events.Document a solution to #552 which is a small adjustment from the current behaviour.
Documents a format for #574
We may want to raise new issues for any other changes defined here if they don't fit in the above 3 issues.