Skip to content
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

x/ibc: implement ADR 032 typed events #7762

Closed
wants to merge 43 commits into from

Conversation

akhilkumarpilli
Copy link
Contributor

Description

ref: #7563


Before we can merge this PR, please make sure that all the following items have been
checked off. If any of the checklist items are not applicable, please leave them but
write a little note why.

  • Targeted PR against correct branch (see CONTRIBUTING.md)
  • Linked to Github issue with discussion and accepted design OR link to spec that describes this work.
  • Code follows the module structure standards.
  • Wrote unit and integration tests
  • Updated relevant documentation (docs/) or specification (x/<module>/spec/)
  • Added relevant godoc comments.
  • Added a relevant changelog entry to the Unreleased section in CHANGELOG.md
  • Re-reviewed Files changed in the Github PR explorer
  • Review Codecov Report in the comment section below once CI passes

@akhilkumarpilli
Copy link
Contributor Author

@jackzampolin ParseTypedEvent is failing with error: json: cannot unmarshal number into Go value of type string. Tests for this are present here

}

// EventOnTimeoutPacket is a typed event emitted on packet timeout
message EventOnTimeoutPacket {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should be in channel along with all the events above

Copy link
Contributor

@colin-axner colin-axner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Height type shouldn't be changed to pointer (this is would also make this pr a breaking change). Is there a reason this was done? The Height interface is only used to avoid circular dependencies but we intentionally constructed the code such that the concrete Height type is the only one used. We should definitely not be treating the Height type as an Any.

proto/ibc/applications/transfer/v1/tx.proto Outdated Show resolved Hide resolved
proto/ibc/core/channel/v1/event.proto Outdated Show resolved Hide resolved
proto/ibc/core/client/v1/event.proto Outdated Show resolved Hide resolved
@amaury1093
Copy link
Contributor

re #7762 (comment), I explored the issue with @akhilkumarpilli a little bit.

In old events, when we have an event with {attributeKey}={attributeValue}, only string and []byte were allowed for the attributeValue. strings were encoded as-is, without "" around them.

In new typed events, it seems that we want to put any type of value (strings, numbers, also arrays and structs??) inside attributeValue. What's the encoding we use here then? Akhil's error #7762 (comment) is just a wrong encoding used.

I think attributeValue as json.RawMessage would be ideal. However, strings will have "" around them, and I'm proposing to make search events work with "".

Copy link
Contributor

@colin-axner colin-axner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Diffs look a lot better. New way of emitting events looks great. Do you think you could update or event spec docs as well? It's be under x/ibc/applications/transfer/spec and x/ibc/core/spec

proto/ibc/core/channel/v1/event.proto Outdated Show resolved Hide resolved
proto/ibc/core/channel/v1/event.proto Outdated Show resolved Hide resolved
proto/ibc/core/connection/v1/event.proto Outdated Show resolved Hide resolved
x/ibc/applications/transfer/keeper/msg_server.go Outdated Show resolved Hide resolved
x/ibc/applications/transfer/keeper/keeper.go Outdated Show resolved Hide resolved
x/ibc/applications/transfer/module.go Outdated Show resolved Hide resolved
x/ibc/core/04-channel/handler.go Outdated Show resolved Hide resolved
@@ -0,0 +1,23 @@
syntax = "proto3";
package ibc.applications.transfer.v1;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

super nit, but can we rename these proto files to events.proto?

Comment on lines 17 to 18
bytes trace_hash = 1 [
(gogoproto.casttype) = "github.com/tendermint/tendermint/libs/bytes.HexBytes",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit, I'd just use string here

Comment on lines +19 to +20
txEvents = "tm.event='Tx'"
blEvents = "tm.event='NewBlock'"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure there are constants for this on Tendermint?

Comment on lines +84 to +85
// Replace "." in event type with "-" to fix tm event query issue
evtType := strings.ReplaceAll(proto.MessageName(tev), ".", "-")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this from tendermint? is there an issue that we can track there?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the actual issue we have: #7762 (comment)

Comment on lines +172 to +180
var txResult abci.TxResult
txResBytes, err := json.Marshal(rev.Data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(txResBytes, &txResult); err != nil {
return nil, fmt.Errorf("failed to unmarshall into abci.TxResult: %s", string(txResBytes))
}
return txResult.Result.Events, nil
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we use a private function for each of the cases? just for ease of readability

x/ibc/applications/transfer/module.go Outdated Show resolved Hide resolved
Copy link
Member

@AdityaSripal AdityaSripal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like this feature will help a lot!

Though there does seem to be a lot of marshalling into JSON and then immediately unmarshalling back into some struct. I wonder how much of this is strictly necessary and how much can be simplified and done without any marshalling.

It seems like at least some of this code will be called for each typed event on each full node. So it is crucial to limit the amount of serialization/deserialization that we are forcing every node to do.

Comment on lines 86 to 92
evtJSON, err := codec.ProtoMarshalJSON(tev, nil)
if err != nil {
return Event{}, err
}

var attrMap map[string]json.RawMessage
var attrMap map[string]interface{}
err = json.Unmarshal(evtJSON, &attrMap)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there something simpler we could do here rather than marshaling and then unmarshalling back again?

Comment on lines +101 to +102
case string:
valueBz = []byte(v)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this special case necessary? What's the harm in JSON marshalling everything and then JSON unmarshalling?

Comment on lines +146 to +149
var value interface{}
err := json.Unmarshal(attr.Value, &value)
if err != nil {
value = string(attr.Value)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note it seems possible that a module could emit an event string and have it get unmarshalled in JSON.

Imagine that an end user had control over an event attribute. They could construct the string such that it is valid JSON. This function will then successfully unmarshal into interface whatever the user wanted to create and store it into the attribute value.
I'm not sure there's an obviously exploitable issue here, but it depends on the application. So we should make sure to prevent this.
I recommend always JSON marshalling the attribute value in TypedEventToEvent and always unmarshalling here. If the JSON unmarshal fails then we simply return the error.

@@ -137,6 +165,37 @@ func ParseTypedEvent(event abci.Event) (proto.Message, error) {
return protoMsg, nil
}

// ResultEventToABCIEvent takes the ctypes.ResultEvent and casts it to abci.TxResult, extracting the []abci.Event
func ResultEventToABCIEvent(rev ctypes.ResultEvent) ([]abci.Event, error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't this also return some sort of boolean flag indicating whether the returned events are TxEvents or BlockEvents?

Comment on lines +173 to +177
txResBytes, err := json.Marshal(rev.Data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(txResBytes, &txResult); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we doing this marshalling and unmarshalling?

Can't we just cast rev.Data to tmtypes.EventDataTx?

And then we can get the abci.TxResult inside?

https://github.com/tendermint/tendermint/blob/master/rpc/core/types/responses.go#L233
https://github.com/tendermint/tendermint/blob/e13b4386ff1a46a5e8879e11bd653b62d4ca0992/types/events.go#L86

Comment on lines +183 to +187
bl, err := json.Marshal(rev.Data)
if err != nil {
return nil, err
}
if err := json.Unmarshal(bl, &blResult); err != nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

)
channel, _ := am.keeper.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel())

if err := ctx.EventManager().EmitTypedEvent(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto @colin-axner 's comment above

channel, _ := am.keeper.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel())

if err := ctx.EventManager().EmitTypedEvent(
&channeltypes.EventChannelTimeoutPacket{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto @colin-axner's comment above

@@ -12,12 +12,19 @@ message EventTransfer {
string receiver = 2;
}

// EventAcknowledgementSuccess is a typed event emitted on packet acknowledgement success
message EventAcknowledgementSuccess {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these can go in channel. We have a acknowledgement success/error type defined in channel so other applications may want to use this event. It's usage would make it easier on relayers as well

),
})
if err := ctx.EventManager().EmitTypedEvent(
&types.EventTransfer{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we be emitting the token denom and amount here too? This information is redundant since the packet data will always be emitted, but maybe it is useful for exchanges to be notified that a certain transfer occurred?

cc @fedekunze @AdityaSripal

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might be useful yes, don't see a reason why it shouldn't be emitted

)
if err := ctx.EventManager().EmitTypedEvent(
&types.EventDenominationTrace{
TraceHash: traceHash.String(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should emit the amount and receiver here as well

ctx.EventManager().EmitEvent(
sdk.NewEvent(
types.EventTypePacket,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still want to emit this information (It isn't 04-channel logic). Ideally we want to bundle this information with whether the ack was a success or failure. Is it possible to embed a event type into another event easily.

I'm thinking we have the ack success/fail event in channel which also get added an event type applications (such as transfer) can embed their own custom event

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to create separate events. We can't embed one event into other.

sdk.NewEvent(
types.EventTypeTimeout,
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
sdk.NewAttribute(types.AttributeKeyRefundReceiver, data.Sender),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto, we still need this

@anilcse
Copy link
Collaborator

anilcse commented Dec 14, 2020

re #7762 (comment), I explored the issue with @akhilkumarpilli a little bit.

In old events, when we have an event with {attributeKey}={attributeValue}, only string and []byte were allowed for the attributeValue. strings were encoded as-is, without "" around them.

In new typed events, it seems that we want to put any type of value (strings, numbers, also arrays and structs??) inside attributeValue. What's the encoding we use here then? Akhil's error #7762 (comment) is just a wrong encoding used.

I think attributeValue as json.RawMessage would be ideal. However, strings will have "" around them, and I'm proposing to make search events work with "".

I also in favour of adding support to search by " for strings from tendermint. Wdyt @marbar3778 @sahith-narahari @alessio ? more info here

@colin-axner
Copy link
Contributor

colin-axner commented Jan 25, 2021

what's the status of this pr?

@anilcse
Copy link
Collaborator

anilcse commented Jan 26, 2021

what's the status of this pr?

Hello @colin-axner , we stuck at querying typed events. Because it's storing extra quotes " for strings and we are not able to use quotes for searching. Best fix we could think of is allowing search with " from tendermint side. Or making some hack around TypedEventToEvent to avoid/remove extra double-quotes (") for strings after marshaling. We tried a few workarounds, nothing seemed to be working as expected.

@anilcse
Copy link
Collaborator

anilcse commented Jan 26, 2021

re #7762 (comment), I explored the issue with @akhilkumarpilli a little bit.
In old events, when we have an event with {attributeKey}={attributeValue}, only string and []byte were allowed for the attributeValue. strings were encoded as-is, without "" around them.
In new typed events, it seems that we want to put any type of value (strings, numbers, also arrays and structs??) inside attributeValue. What's the encoding we use here then? Akhil's error #7762 (comment) is just a wrong encoding used.
I think attributeValue as json.RawMessage would be ideal. However, strings will have "" around them, and I'm proposing to make search events work with "".

I also in favour of adding support to search by " for strings from tendermint. Wdyt @marbar3778 @sahith-narahari @alessio ? more info here

@marbar3778 did you/anyone from tendermint team got a chance to look into this?

@tac0turtle
Copy link
Member

We have not. I don't think there is an issue related to this in tendermint. Would you want to open one?

@anilcse
Copy link
Collaborator

anilcse commented Jan 26, 2021

We have not. I don't think there is an issue related to this in tendermint. Would you want to open one?

thanks, created an issue tendermint/tendermint#5978

@colin-axner
Copy link
Contributor

IBC is no longer in the SDK. It seems to me the path forward with this pr is to:

  1. resolve types/events.go changes necessary in a separate pr. This may require waiting for tendermint changes or figuring out another workaround. Implement ADR 032: Typed Events #7563 can track this work
  2. once the above is resolved, open a pr on the ibc-go repo with the IBC changes

Closing this pr as it is stale and likely easier to open a fresh pr to address the concerns of 1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants