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

ICS4: Event emission Specification #1165

Open
wants to merge 7 commits into
base: feat/v2-spec
Choose a base branch
from
Open

Conversation

AdityaSripal
Copy link
Member

Emit events for relayers to construct the packet messages

  • Simple in single payload case
  • Support for multipayload

@DimitrisJim
Copy link
Contributor

if you could also give an ack on current events spec'ed for CreateChannel/RegisterCounterparty it would be great (e.g I see for RegisterCounterparty we emit the creator which should have been deleted from state after that tx runs, so may not make sense to emit https://github.com/cosmos/ibc/pull/1143/files#diff-f32300fb26667f1d0dc384ad4d8fd45665bd5a7edd6b4e6cb648ae89721d7f13R383)

@AdityaSripal AdityaSripal changed the base branch from main to feat/v2-spec November 12, 2024 10:51
@AdityaSripal
Copy link
Member Author

Done! @DimitrisJim

sequence: sequence,
packet: packet,
timeoutTimestamp: timeoutTimestamp,
destId: channel.counterpartyChannelId,
Copy link
Contributor

Choose a reason for hiding this comment

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

I see these are defined as bytes in spec atm (for eth side of things where these are a contract address I assume?). Should they be hex encoded too in spec?

Copy link
Member Author

Choose a reason for hiding this comment

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

Mmmm this is a good point. In ibc-go this is an alphanumeric string. It feels wasteful to convert that to a hex string only to convert it back. Tho it is possible that other implementations use bytes that do not decode to ASCII characters.

What do you think @gjermundgaraba ?

Choose a reason for hiding this comment

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

It is a string in Solidity (which is technically dynamic bytes array), but I don't think we suffer too much on this. Unless it was a fixed-length byte array I don't think we would save much on Solidity.

Copy link

@gjermundgaraba gjermundgaraba left a comment

Choose a reason for hiding this comment

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

This looks reasonable to me. Is it OK for events to emit extra information, if there are implementation-specific things that are needed?

// Event Emission
emitLogEntry("sendPacket", {
// Event Emission for send packet
emitEvents("send_packet", {
sourceId: sourceChannelId,

Choose a reason for hiding this comment

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

Is there any particular reason why we use sourceId here rather than sourceChannelId? I don't care too much either way, but why not use the same names as the packet structure?

sequence: sequence, // value is string in decimal format
timeoutTimestamp: timeoutTimestamp, // value is string in decimal format
payloadLength: len(payloads), // value is string in decimal format
// include first payload data in events if there is only one payload

Choose a reason for hiding this comment

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

Does that mean that if this is a multi-payload packet, these need to be empty strings?

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we can still fill these in.

Choose a reason for hiding this comment

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

Right, yes because you would check the length to find out if there should be more to look for.

// reconstructed by relayers
for i, payload in payloads {
emitLongEntry("send_payload", {
sourceId: sourceChannelId,

Choose a reason for hiding this comment

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

Same question as above regarding naming differences

emitLogEntry("writeAcknowledgement", {
sequence: packet.sequence,
emitEvents("write_acknowledgement", {
sequence: packet.sequence, // value is string in decimal format

Choose a reason for hiding this comment

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

nit/question: Curious about the use of the word "decimal" here. I immediately think of a number with some kind of precision. Would it be simpler to say integer?

Also, what is the reason for using string-formatted numbers here?

Copy link
Member Author

Choose a reason for hiding this comment

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

I mean that the string is base10 as opposed to hexadecimal or something else.

This is assuming the event system is a <string, string> attribute system.

Choose a reason for hiding this comment

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

Ah, I see. That makes sense.

@@ -784,14 +825,49 @@ function writeAcknowledgement(
// Note that the event should be emitted by this function only in the asynchrounous ack case. Otherwise the event is emitted during the onReceive
packet=getPacket(destChannelId,sequence)
if(packet!=nil){
emitLogEntry("writeAcknowledgement", {
sequence: packet.sequence,
// construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter

Choose a reason for hiding this comment

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

Since we emit separate events for multiple payloads, could we not do the same here? Is it because it would be simpler for an event handler to always have to deal with a single writeAcknowledgement event per packet?

Copy link
Member Author

Choose a reason for hiding this comment

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

We could do this yes. Think I just did this before thinking about the payload case

@srdtrk
Copy link
Member

srdtrk commented Nov 20, 2024

I think this is mostly written under the assumptions that all events must look like key-value pairs where both key and value must be string. Also assumes that there must be a key identifying the event. In solidity it is not necessarily like this, and serializing the packet this way would likely cost a lot of gas. Instead we'd be better off just emitting the full packet (abi encoded) each time rather than emitting each individual field. For example:

emit SendPacket(packet)

I don't see any issue with this unless we have to implement the events this way in every implementation.

@AdityaSripal
Copy link
Member Author

Yes its a bit of a tough needle to thread which is why we faced this problem in the v1 spec. Note the exact view of the events is not strictly necessary to be followed in order to be a compliant implemention (only provable key/value logic is absolutely necessary). If different implementations emit events the same way, then the work on the relayer is simpler since they will use the same parsing and reconstruction logic. We could also just tell different implementations what they have to emit without specifying how, then relayers must build custom integrators for each implementation. This has been a consistent complaint and request from relayer teams to standardize and specify the events for the v1 spec. Open to doing things differently but should ensure its ok with potential relayer implementations

// Event Emission for receive packet
emitEvents("recv_packet", {
sourceChannel: sourceChannelId,
destChannel: channel.counterpartyChannelId,
Copy link
Contributor

Choose a reason for hiding this comment

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

meant to drop comment here, counterparty channel id on recv will be equal to source channel no? Should be packet.DestChannel?

@gjermundgaraba
Copy link

@srdtrk @AdityaSripal one other thing we have not looked too closely at is how different way of structuring the events affect gas cost on Ethereum. I would need to dive a bit deeper into it, but the general way it works is 375 + 375 * numberOfIndexedParameters + numberOfUnindexedBits

Currently, I don't believe we haven't added any extra indexed parameters, so we are mostly concerned with size. So where we can keep size smaller, it will be advantageous. Obviously any marshaling/encoding we have to do first is also very much relevant.

Yes its a bit of a tough needle to thread

Would at least being able to use the local "type" for different variables such as timestamp and so on be OK in this context (rather than having to encode it to string)?

})
}

// Event Emission for receive packet. emit again so relayer can reconstruct the packet
Copy link
Contributor

Choose a reason for hiding this comment

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

Note that re-emission may be expensive. Can't relayers store somewhere these events instead?

@sangier
Copy link
Contributor

sangier commented Nov 26, 2024

working on the solidity events, I can confirm that if we don't emit events like serdar suggested emit SendPacket(packet) it increases the cost and we end up in a stack too deep issue. I guess that's fine to emit event like suggested as long as all the relevant fields are emitted. The relayer reconstruction should then be custom for the eth side.

// for multi payload cases, we will emit each payload as a separate event
// these will include the packet identifier so they can be indexed and
// reconstructed by relayers
for i, payload in payloads {
Copy link
Contributor

Choose a reason for hiding this comment

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

In the single payload case, a send_payload event would be emitted anyway. Since we emit an event with the first payload related data in the send_packet event, this results in a duplicated field emission.
Do we want to emit the send_payload event even in the single payload case?
If not, shall we discard the first element of the payload array here? Alternatively, shall we remove version,encoding,data from the send_packet event?

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

Successfully merging this pull request may close these issues.

5 participants