From 89b2f8453c95f9c40756f5081d8f09734179d2e5 Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Mon, 11 Nov 2024 23:31:10 +0100 Subject: [PATCH 1/6] event specification --- .../README.md | 152 +++++++++++++----- 1 file changed, 116 insertions(+), 36 deletions(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index 4d8d80430..935675338 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -596,15 +596,33 @@ function sendPacket( // increment the sequence. Thus there are monotonically increasing sequences for packet flow for a given clientId nextSequenceSend[sourceChannelId]=sequence+1 - // log that a packet can be safely sent - // Event Emission - emitLogEntry("sendPacket", { + // Event Emission for send packet + emitLogEntry("send_packet", { sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, - sequence: sequence, - packet: packet, - timeoutTimestamp: timeoutTimestamp, + destId: channel.counterpartyChannelId, + 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 + version: payload[0].version, + encoding: payload[0].encoding, + data: toHex(payload[0].appData) // emit app bytes as string in hex format }) + + // 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 { + emitLongEntry("send_payload", { + sourceId: sourceChannelId, + destId: channel.counterpartyChannelId, + sequence: sequence, // value is string in decimal format + payloadSequence: i, // value is string in payload format + version: payload.version, + encoding: payload.encoding, + data: toHex(payload.appData) // emit app bytes as string in hex format + }) + } return sequence } @@ -690,19 +708,25 @@ function recvPacket( // Executes Application logic ∀ Payload payload=packet.data[0] cbs = router.callbacks[payload.destPort] - ack,success = cbs.onReceivePacket(packet.channelDestId,packet.channelSourceId,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback + acknowledgement,success = cbs.onReceivePacket(packet.channelDestId,packet.channelSourceId,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback + // construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter + ackString = "" + for i, ack in acknowledgment { + ackString = ackString + toHex(ack) + if i !== len(acknowledgement) - 1 { + ackString = ackString + "/" + } + } abortTransactionUnless(success) if ack != nil { // NOTE: Synchronous ack. writeAcknowledgement(packet.channelDestId,packet.sequence,ack) // In case of Synchronous ack we emit the event here as we have all the necessary information, while writeAcknowledgement can only retrieve this in case of asynchronous ack. - emitLogEntry("writeAcknowledgement", { - sequence: packet.sequence, + emitLogEntry("write_acknowledgement", { + sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - ack + acknowledgement: ackString, }) }else { // NOTE No ack || Asynchronous ack. @@ -717,16 +741,33 @@ function recvPacket( SUCCESSFUL_RECEIPT ) - // log that a packet has been received - // Event Emission - emitLogEntry("recvPacket", { - data: packet.data - timeoutTimestamp: packet.timeoutTimestamp, - sequence: packet.sequence, - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - relayer: relayer + // Event Emission for receive packet + emitLogEntry("recv_packet", { + sourceId: sourceChannelId, + destId: channel.counterpartyChannelId, + 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 + version: payload[0].version, + encoding: payload[0].encoding, + data: toHex(payload[0].appData) // emit app bytes as string in hex format }) + + // 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 { + emitLongEntry("recv_payload", { + sourceId: sourceChannelId, + destId: channel.counterpartyChannelId, + sequence: sequence, // value is string in decimal format + payloadSequence: i, // value is string in payload format + version: payload.version, + encoding: payload.encoding, + data: toHex(payload.appData) // emit app bytes as string in hex format + }) + } } ``` @@ -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 + ackString = "" + for i, ack in acknowledgment { + ackString = ackString + toHex(ack) + if i !== len(acknowledgement) - 1 { + ackString = ackString + "/" + } + } + emitLogEntry("write_acknowledgement", { + sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement + acknowledgement: ackString, + }) + + // Event Emission for receive packet. emit again so relayer can reconstruct the packet + emitLogEntry("recv_packet", { + sourceId: sourceChannelId, + destId: channel.counterpartyChannelId, + 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 + version: payload[0].version, + encoding: payload[0].encoding, + data: toHex(payload[0].appData) // emit app bytes as string in hex format }) + + // 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 { + emitLongEntry("recv_payload", { + sourceId: sourceChannelId, + destId: channel.counterpartyChannelId, + sequence: sequence, // value is string in decimal format + payloadSequence: i, // value is string in payload format + version: payload.version, + encoding: payload.encoding, + data: toHex(payload.appData) // emit app bytes as string in hex format + }) + } + // delete the packet from state storedPacket[destChannelId,sequence]=nil } @@ -865,15 +941,22 @@ function acknowledgePacket( } channelStore.delete(packetCommitmentPath(packet.channelSourceId, packet.sequence)) + + // construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter + ackString = "" + for i, ack in acknowledgment { + ackString = ackString + toHex(ack) + if i !== len(acknowledgement) - 1 { + ackString = ackString + "/" + } + } // Event Emission // Check fields emitLogEntry("acknowledgePacket", { - sequence: packet.sequence, + sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement + acknowledgement: ackString, }) } ``` @@ -984,14 +1067,11 @@ function timeoutPacket( channelStore.delete(packetCommitmentPath(packet.channelSourceId, packet.sequence)) - // Event Emission // See fields + // Event Emission for timeout packet emitLogEntry("timeoutPacket", { - sequence: packet.sequence, + sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement }) } ``` From c6de304ba6fa01fc73fe6cdc6314a593eba87af8 Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:53:36 +0100 Subject: [PATCH 2/6] specify events for channel creation --- spec/core/v2/ics-004-channel-and-packet-semantics/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index 935675338..7b3574456 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -325,7 +325,7 @@ function createChannel( // Event Emission emitLogEntry("createChannel", { channelId: channelId, - channel: channel, + clientId: clientId, creatorAddress: msg.signer(), }) @@ -379,8 +379,7 @@ function registerCounterparty( // Event Emission emitLogEntry("registerCounterparty", { channelId: channelId, - channel: channel, - creatorAddress: msg.signer(), + counterpartyChannelid: counterpartyChannelId, }) } ``` From a15962bbf8bd1b8bf47968b37d946106597a6b91 Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 12 Nov 2024 14:55:36 +0100 Subject: [PATCH 3/6] add client id to register counterparty events --- spec/core/v2/ics-004-channel-and-packet-semantics/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index 7b3574456..57c8842e3 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -378,7 +378,8 @@ function registerCounterparty( // log that a packet can be safely sent // Event Emission emitLogEntry("registerCounterparty", { - channelId: channelId, + channelId: channelId, + clientId: channel.clientId counterpartyChannelid: counterpartyChannelId, }) } From 835c47736bb5a94f7672daebb87a18d9cd9b372f Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 12 Nov 2024 15:29:58 +0100 Subject: [PATCH 4/6] rename emitLogEntry to emitEvents --- .../README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index 57c8842e3..4eb89ec5d 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -323,7 +323,7 @@ function createChannel( nextSequenceSend[channelId]=1 // Event Emission - emitLogEntry("createChannel", { + emitEvents("createChannel", { channelId: channelId, clientId: clientId, creatorAddress: msg.signer(), @@ -377,7 +377,7 @@ function registerCounterparty( // log that a packet can be safely sent // Event Emission - emitLogEntry("registerCounterparty", { + emitEvents("registerCounterparty", { channelId: channelId, clientId: channel.clientId counterpartyChannelid: counterpartyChannelId, @@ -597,7 +597,7 @@ function sendPacket( nextSequenceSend[sourceChannelId]=sequence+1 // Event Emission for send packet - emitLogEntry("send_packet", { + emitEvents("send_packet", { sourceId: sourceChannelId, destId: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format @@ -722,7 +722,7 @@ function recvPacket( // NOTE: Synchronous ack. writeAcknowledgement(packet.channelDestId,packet.sequence,ack) // In case of Synchronous ack we emit the event here as we have all the necessary information, while writeAcknowledgement can only retrieve this in case of asynchronous ack. - emitLogEntry("write_acknowledgement", { + emitEvents("write_acknowledgement", { sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, @@ -742,7 +742,7 @@ function recvPacket( ) // Event Emission for receive packet - emitLogEntry("recv_packet", { + emitEvents("recv_packet", { sourceId: sourceChannelId, destId: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format @@ -833,7 +833,7 @@ function writeAcknowledgement( ackString = ackString + "/" } } - emitLogEntry("write_acknowledgement", { + emitEvents("write_acknowledgement", { sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, @@ -841,7 +841,7 @@ function writeAcknowledgement( }) // Event Emission for receive packet. emit again so relayer can reconstruct the packet - emitLogEntry("recv_packet", { + emitEvents("recv_packet", { sourceId: sourceChannelId, destId: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format @@ -952,7 +952,7 @@ function acknowledgePacket( } // Event Emission // Check fields - emitLogEntry("acknowledgePacket", { + emitEvents("acknowledgePacket", { sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, @@ -1068,7 +1068,7 @@ function timeoutPacket( channelStore.delete(packetCommitmentPath(packet.channelSourceId, packet.sequence)) // Event Emission for timeout packet - emitLogEntry("timeoutPacket", { + emitEvents("timeoutPacket", { sequence: packet.sequence, // value is string in decimal format sourceId: packet.channelSourceId, destId: packet.channelDestId, From a9197dee01cfbf3c99efca8e54c14013cee4117d Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:30:08 +0100 Subject: [PATCH 5/6] address reviews --- .../README.md | 247 ++++++++---------- 1 file changed, 116 insertions(+), 131 deletions(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index 4eb89ec5d..d44207aab 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -162,8 +162,8 @@ The ICS-04 use the protocol paths, defined in [ICS-24](../ics-024-host-requireme Thus, constant-size commitments to packet data fields are stored under the packet sequence number: ```typescript -function packetCommitmentPath(channelSourceId: bytes, sequence: BigEndianUint64): Path { - return "{channelSourceId}|0x1|{bigEndianUint64Sequence}" +function packetCommitmentPath(sourceChannel: bytes, sequence: BigEndianUint64): Path { + return "{sourceChannel}|0x1|{bigEndianUint64Sequence}" } ``` @@ -172,16 +172,16 @@ Absence of the path in the store is equivalent to a zero-bit. Packet receipt data are stored under the `packetReceiptPath`. In the case of a successful receive, the destination chain writes a sentinel success value of `SUCCESSFUL_RECEIPT`. ```typescript -function packetReceiptPath(channelDestId: bytes, sequence: BigEndianUint64): Path { - return "{channelDestId}|0x2|{bigEndianUint64Sequence}" +function packetReceiptPath(destChannel: bytes, sequence: BigEndianUint64): Path { + return "{destChannel}|0x2|{bigEndianUint64Sequence}" } ``` Packet acknowledgement data are stored under the `packetAcknowledgementPath`: ```typescript -function packetAcknowledgementPath(channelSourceId: bytes, sequence: BigEndianUint64): Path { - return "{channelSourceId}|0x3|{bigEndianUint64Sequence}" +function packetAcknowledgementPath(sourceChannel: bytes, sequence: BigEndianUint64): Path { + return "{sourceChannel}|0x3|{bigEndianUint64Sequence}" } ``` @@ -296,33 +296,33 @@ function createChannel( clientId: bytes, counterpartyKeyPrefix: CommitmentPrefix): bytes { - // Implementation-Specific Input Validation - // All implementations MUST ensure the inputs value are properly validated and compliant with this specification - client=getClient(clientId) - assert(client!==null) - assert(isFormatOk(counterpartyKeyPrefix)) + // Implementation-Specific Input Validation + // All implementations MUST ensure the inputs value are properly validated and compliant with this specification + client=getClient(clientId) + assert(client!==null) + assert(isFormatOk(counterpartyKeyPrefix)) - // Channel Checks - channelId = generateIdentifier() - abortTransactionUnless(validateIdentifier(channelId)) - abortTransactionUnless(getChannel(channelId)) === null) - - // Channel manipulation - channel = Channel{ - clientId: clientId, - counterpartyChannelId: "", // This field it must be a blank field during the creation as it may be not known at the creation time. - keyPrefix: counterpartyKeyPrefix - } + // Channel Checks + channelId = generateIdentifier() + abortTransactionUnless(validateIdentifier(channelId)) + abortTransactionUnless(getChannel(channelId)) === null) + + // Channel manipulation + channel = Channel{ + clientId: clientId, + counterpartyChannelId: "", // This field it must be a blank field during the creation as it may be not known at the creation time. + keyPrefix: counterpartyKeyPrefix + } - // Local stores - // Store channel info - storedChannels[channelId]=channel - // Store creator address info - channelCreator[channelId]=msg.signer() - // Initialise the nextSequenceSend - nextSequenceSend[channelId]=1 - - // Event Emission + // Local stores + // Store channel info + storedChannels[channelId]=channel + // Store creator address info + channelCreator[channelId]=msg.signer() + // Initialise the nextSequenceSend + nextSequenceSend[channelId]=1 + + // Event Emission emitEvents("createChannel", { channelId: channelId, clientId: clientId, @@ -513,7 +513,7 @@ sequenceDiagram ##### Sending packets -The `sendPacket` function is called by the IBC handler when an IBC packet is submitted to the newtwork in order to send *data* in the form of an IBC packet. The `sendPacket` function executes the IBC core logic and atomically triggers the application logic execution via the activation of the `onSendPacket` callback. Indeed ∀ `Payload` included in the `packet.data`, which refers to a specific application, the callbacks are retrieved from the IBC router and the `onSendPacket` is the then triggered on the application specified in the `payload` content. Once all payloads contained in the `packet.data` have been processed, the packet commitment is generated and the sequence number bound to the `channelSourceId` is incremented. +The `sendPacket` function is called by the IBC handler when an IBC packet is submitted to the newtwork in order to send *data* in the form of an IBC packet. The `sendPacket` function executes the IBC core logic and atomically triggers the application logic execution via the activation of the `onSendPacket` callback. Indeed ∀ `Payload` included in the `packet.data`, which refers to a specific application, the callbacks are retrieved from the IBC router and the `onSendPacket` is the then triggered on the application specified in the `payload` content. Once all payloads contained in the `packet.data` have been processed, the packet commitment is generated and the sequence number bound to the `sourceChannel` is incremented. The `sendPacket` core function MUST execute the applications logic atomically triggering the `onSendPacket` callback ∀ application contained in the `packet.data` payload. @@ -564,7 +564,6 @@ function sendPacket( // disallow packet with timeoutTimestamp less than currentTimestamp and timeoutTimestamp value bigger than currentTimestamp + MaxTimeoutDelta assert(currentTimestamp() < timeoutTimestamp < currentTimestamp() + MAX_TIMEOUT_DELTA) - // retrieve sequence sequence = nextSequenceSend[sourecChannelId] // Check that the Sequence has been correctly initialized before hand. @@ -582,12 +581,12 @@ function sendPacket( // Construct the packet packet = Packet { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, - sequence: sequence, - timeoutTimestamp: timeoutTimestamp, - payloads: payloads - } + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, + sequence: sequence, + timeoutTimestamp: timeoutTimestamp, + payloads: payloads + } // store packet commitment using commit function defined in [packet specification](https://github.com/cosmos/ibc/blob/c7b2e6d5184b5310843719b428923e0c5ee5a026/spec/core/v2/ics-004-packet-semantics/PACKET.md) commitment=commitV2Packet(packet) @@ -598,8 +597,8 @@ function sendPacket( // Event Emission for send packet emitEvents("send_packet", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, 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 @@ -614,8 +613,8 @@ function sendPacket( // reconstructed by relayers for i, payload in payloads { emitLongEntry("send_payload", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format payloadSequence: i, // value is string in payload format version: payload.version, @@ -652,9 +651,9 @@ Pre-conditions: | **Condition Type** | **Description** | **Code Checks** | |-------------------------------|-----------------------------------------------|-----------------------------------------------| -| **Error-Conditions** | 1. invalid `packetCommitment`, 2.`packetReceipt` already exists
3. Invalid timeoutTimestamp
4. Unsuccessful payload execution.
5. Unexpected counterparty channel id | 1.1 `verifyMembership(packetCommitment)==false`
1.2 `provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence))!=null`
3. `timeoutTimestamp === 0`
3.1 `currentTimestamp() > packet.timeoutTimestamp`
4. `onReceivePacket(..)==False`
5. `packet.sourceChannelId != channel.counterpartyChannelId` | -| **Post-Conditions (Success)** | 1. `onReceivePacket` is executed and the application state is modified
2. The `packetReceipt` is written
3. Event is Emitted
| 1. `onReceivePacket(..)==True; app.State(beforeReceivePacket)!=app.State(afterReceivePacket)`
2. `provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence))!=null`
3. Check Event Emission
| -| **Post-Conditions (Error)** | 1. if `onReceivePacket` fails the application state is unchanged
2. `packetReceipt is not written`

3. No Event Emission
| 1. `app.State(beforeReceivePacket)==app.State(afterReceivePacket)`
2. `provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence))==null`
3. Check No Event is Emitted
| +| **Error-Conditions** | 1. invalid `packetCommitment`, 2.`packetReceipt` already exists
3. Invalid timeoutTimestamp
4. Unsuccessful payload execution.
5. Unexpected counterparty channel id | 1.1 `verifyMembership(packetCommitment)==false`
1.2 `provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence))!=null`
3. `timeoutTimestamp === 0`
3.1 `currentTimestamp() > packet.timeoutTimestamp`
4. `onReceivePacket(..)==False`
5. `packet.sourceChannelId != channel.counterpartyChannelId` | +| **Post-Conditions (Success)** | 1. `onReceivePacket` is executed and the application state is modified
2. The `packetReceipt` is written
3. Event is Emitted
| 1. `onReceivePacket(..)==True; app.State(beforeReceivePacket)!=app.State(afterReceivePacket)`
2. `provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence))!=null`
3. Check Event Emission
| +| **Post-Conditions (Error)** | 1. if `onReceivePacket` fails the application state is unchanged
2. `packetReceipt is not written`

3. No Event Emission
| 1. `app.State(beforeReceivePacket)==app.State(afterReceivePacket)`
2. `provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence))==null`
3. Check No Event is Emitted
| ###### Pseudo-Code @@ -671,7 +670,7 @@ function recvPacket( ) { // Channel and Client Checks - channel = getChannel(packet.channelDestId) + channel = getChannel(packet.destChannel) assert(channel !== null) client = router.clients[channel.clientId] assert(client !== null) @@ -684,13 +683,13 @@ function recvPacket( assert(currentTimestamp() < packet.timeoutTimestamp) // verify the packet receipt for this packet does not exist already - packetReceipt = provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence)) + packetReceipt = provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence)) abortTransactionUnless(packetReceipt === null) //////// verify commitment // 1. retrieve keys - packetPath = packetCommitmentPath(packet.channelDestId, packet.sequence) + packetPath = packetCommitmentPath(packet.destChannel, packet.sequence) merklePath = applyPrefix(channel.keyPrefix, packetPath) // 2. reconstruct commit value based on the passed-in packet @@ -704,47 +703,42 @@ function recvPacket( merklePath, commit)) - // Executes Application logic ∀ Payload payload=packet.data[0] cbs = router.callbacks[payload.destPort] - acknowledgement,success = cbs.onReceivePacket(packet.channelDestId,packet.channelSourceId,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback - // construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter - ackString = "" - for i, ack in acknowledgment { - ackString = ackString + toHex(ack) - if i !== len(acknowledgement) - 1 { - ackString = ackString + "/" - } - } + acknowledgement,success = cbs.onReceivePacket(packet.destChannel,packet.sourceChannel,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback abortTransactionUnless(success) if ack != nil { // NOTE: Synchronous ack. - writeAcknowledgement(packet.channelDestId,packet.sequence,ack) - // In case of Synchronous ack we emit the event here as we have all the necessary information, while writeAcknowledgement can only retrieve this in case of asynchronous ack. - emitEvents("write_acknowledgement", { - sequence: packet.sequence, // value is string in decimal format - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - acknowledgement: ackString, - }) + writeAcknowledgement(packet.destChannel,packet.sequence,ack) + // emit an acknowledgement event for each app acknowledgement in the acknowledgement + for i, ack in acknowledgment { + // In case of Synchronous ack we emit the event here as we have all the necessary information, while writeAcknowledgement can only retrieve this in case of asynchronous ack. + emitEvents("write_acknowledgement", { + sourceChannel: packet.sourceChannel, + destChannel: packet.destChannel, + sequence: packet.sequence, // value is string in decimal format + payloadSequence: i, // value is string in decimal format + acknowledgement: toHex(ack), + }) + } }else { // NOTE No ack || Asynchronous ack. // ack is nil and will be written asynchronously, so we store the full packet in the private store - storedPacket[packet.channelDestId,packet.sequence]=packet + storedPacket[packet.destChannel,packet.sequence]=packet } // Provable Stores // we must set the receipt so it can be verified on the other side // it's the sentinel success receipt: []byte{0x01} provableStore.set( - packetReceiptPath(packet.channelDestId, packet.sequence), + packetReceiptPath(packet.destChannel, packet.sequence), SUCCESSFUL_RECEIPT ) // Event Emission for receive packet emitEvents("recv_packet", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, 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 @@ -759,10 +753,10 @@ function recvPacket( // reconstructed by relayers for i, payload in payloads { emitLongEntry("recv_payload", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format - payloadSequence: i, // value is string in payload format + payloadSequence: i, // value is string in decimal format version: payload.version, encoding: payload.encoding, data: toHex(payload.appData) // emit app bytes as string in hex format @@ -795,9 +789,9 @@ Pre-conditions: | **Condition Type** | **Description** | **Code Checks** | |-------------------------------|------------|------------| -| **Error-Conditions** | 1. acknowledgement is empty
2. The `packetAcknowledgementPath` stores already a value. | 1. `len(acknowledgement) === 0`
2. `provableStore.get(packetAcknowledgementPath(packet.channelDestId, packet.sequence) !== null` | -| **Post-Conditions (Success)** | 1. opaque acknowledgement has been written at `packetAcknowledgementPath`
2. Event is Emitted
| 1. `provableStore.get(packetAcknowledgementPath(packet.channelDestId, packet.sequence) !== null`
2. Check Event Emission
| -| **Post-Conditions (Error)** | 1. No value is stored at the `packetAcknowledgementPath`.
2. No Event is Emitted
| 1. `provableStore.get(packetAcknowledgementPath(packet.channelDestId, packet.sequence) === null`
2. Check No Event is Emitted
| +| **Error-Conditions** | 1. acknowledgement is empty
2. The `packetAcknowledgementPath` stores already a value. | 1. `len(acknowledgement) === 0`
2. `provableStore.get(packetAcknowledgementPath(packet.destChannel, packet.sequence) !== null` | +| **Post-Conditions (Success)** | 1. opaque acknowledgement has been written at `packetAcknowledgementPath`
2. Event is Emitted
| 1. `provableStore.get(packetAcknowledgementPath(packet.destChannel, packet.sequence) !== null`
2. Check Event Emission
| +| **Post-Conditions (Error)** | 1. No value is stored at the `packetAcknowledgementPath`.
2. No Event is Emitted
| 1. `provableStore.get(packetAcknowledgementPath(packet.destChannel, packet.sequence) === null`
2. Check No Event is Emitted
| ###### Pseudo-Code @@ -825,32 +819,28 @@ 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){ - // construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter - ackString = "" + // emit an acknowledgement event for each app acknowledgement in the acknowledgement for i, ack in acknowledgment { - ackString = ackString + toHex(ack) - if i !== len(acknowledgement) - 1 { - ackString = ackString + "/" - } + emitEvents("write_acknowledgement", { + sourceChannel: packet.sourceChannel, + destChannel: packet.destChannel, + sequence: packet.sequence, // value is string in decimal format + payloadSequence: i, // value is string in decimal format + acknowledgement: toHex(ack), + }) } - emitEvents("write_acknowledgement", { - sequence: packet.sequence, // value is string in decimal format - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - acknowledgement: ackString, - }) // Event Emission for receive packet. emit again so relayer can reconstruct the packet emitEvents("recv_packet", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, - 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 - version: payload[0].version, - encoding: payload[0].encoding, - data: toHex(payload[0].appData) // emit app bytes as string in hex format + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, + 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 + version: payload[0].version, + encoding: payload[0].encoding, + data: toHex(payload[0].appData) // emit app bytes as string in hex format }) // for multi payload cases, we will emit each payload as a separate event @@ -858,8 +848,8 @@ function writeAcknowledgement( // reconstructed by relayers for i, payload in payloads { emitLongEntry("recv_payload", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, + sourceChannel: sourceChannelId, + destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format payloadSequence: i, // value is string in payload format version: payload.version, @@ -890,9 +880,9 @@ Pre-conditions: | **Condition Type** | **Description** | **Code Checks** | |-------------------------------|---------------------------------|---------------------------------| -| **Error-Conditions** | 1. `packetCommitment` already cleared out
2. Unset Acknowledgment
3. Unsuccessful payload execution.
4. Unexpected counterparty channel id | 1. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === null`
2. `verifyMembership(packetacknowledgementPath,...,) == False`
3. `onAcknowledgePacket(packet.channelSourceId,payload, acknowledgement) == False`
4. `packet.sourceChannelId != channel.counterpartyChannelId` | -| **Post-Conditions (Success)** | 1. `onAcknowledgePacket` is executed and the application state is modified
2. `packetCommitment` has been cleared out
4. Event is Emission
| 1. `onAcknowledgePacket(..)==True; app.State(beforeAcknowledgePacket)!=app.State(afterAcknowledgePacket)`
2. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === null`,
4. Check Event is Emitted
| -| **Post-Conditions (Error)** | 1. If `onAcknowledgePacket` fails the application state is unchanged
2. `packetCommitment` has not been cleared out
3. acknowledgement is stil in store
4. No Event Emission
| 1. `onAcknowledgePacket(..)==False; app.State(beforeAcknowledgePacket)==app.State(afterAcknowledgePacket)`
2. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === commitV2Packet(packet)` 3. `verifyMembership(packetAcknowledgementPath,...,) == True`
4. Check No Event is Emitted
| +| **Error-Conditions** | 1. `packetCommitment` already cleared out
2. Unset Acknowledgment
3. Unsuccessful payload execution.
4. Unexpected counterparty channel id | 1. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === null`
2. `verifyMembership(packetacknowledgementPath,...,) == False`
3. `onAcknowledgePacket(packet.sourceChannel,payload, acknowledgement) == False`
4. `packet.sourceChannelId != channel.counterpartyChannelId` | +| **Post-Conditions (Success)** | 1. `onAcknowledgePacket` is executed and the application state is modified
2. `packetCommitment` has been cleared out
4. Event is Emission
| 1. `onAcknowledgePacket(..)==True; app.State(beforeAcknowledgePacket)!=app.State(afterAcknowledgePacket)`
2. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === null`,
4. Check Event is Emitted
| +| **Post-Conditions (Error)** | 1. If `onAcknowledgePacket` fails the application state is unchanged
2. `packetCommitment` has not been cleared out
3. acknowledgement is stil in store
4. No Event Emission
| 1. `onAcknowledgePacket(..)==False; app.State(beforeAcknowledgePacket)==app.State(afterAcknowledgePacket)`
2. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === commitV2Packet(packet)` 3. `verifyMembership(packetAcknowledgementPath,...,) == True`
4. Check No Event is Emitted
| ###### Pseudo-Code @@ -910,7 +900,7 @@ function acknowledgePacket( ) { // Channel and Client Checks - channel = getChannel(packet.channelSourceId) + channel = getChannel(packet.sourceChannel) assert(channel !== null) client = router.clients[channel.clientId] assert(client !== null) @@ -919,10 +909,10 @@ function acknowledgePacket( assert(packet.sourceChannelId == channel.counterpartyChannelId) // verify we sent the packet and haven't cleared it out yet - assert(provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === commitV2Packet(packet)) + assert(provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === commitV2Packet(packet)) // verify that the acknowledgement exist at the desired path - ackPath = packetAcknowledgementPath(packet.channelDestId, packet.sequence) + ackPath = packetAcknowledgementPath(packet.destChannel, packet.sequence) merklePath = applyPrefix(channel.keyPrefix, ackPath) assert(client.verifyMembership( client.clientState @@ -936,28 +926,23 @@ function acknowledgePacket( // Executes Application logic ∀ Payload payload=packet.data[0] cbs = router.callbacks[payload.sourcePort] - success= cbs.OnAcknowledgePacket(packet.channelSourceId,packet.channelDestId,packet.sequence,payload,acknowledgement, relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback + success= cbs.OnAcknowledgePacket(packet.sourceChannel,packet.destChannel,packet.sequence,payload,acknowledgement, relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback abortUnless(success) } - channelStore.delete(packetCommitmentPath(packet.channelSourceId, packet.sequence)) + channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence)) - // construct acknowlegement event by concatenating each app acknowledgment together with a "/" delimiter - ackString = "" + // emit an acknowledgement event for each app acknowledgement in the acknowledgement for i, ack in acknowledgment { - ackString = ackString + toHex(ack) - if i !== len(acknowledgement) - 1 { - ackString = ackString + "/" - } + emitEvents("acknowledgePacket", { + sourceChannel: packet.sourceChannel, + destChannel: packet.destChannel, + sequence: packet.sequence, // value is string in decimal format + payloadSequence: i // value is string in decimal format + acknowledgement: toHex(ack), + }) } - // Event Emission // Check fields - emitEvents("acknowledgePacket", { - sequence: packet.sequence, // value is string in decimal format - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - acknowledgement: ackString, - }) } ``` @@ -1012,9 +997,9 @@ Pre-conditions: | **Condition Type** | **Description**| **Code Checks**| |-------------------------------|--------------------|--------------------| -| **Error-Conditions** | 1. `packetCommitment` already cleared out
2. `packetReceipt` is not empty
3. Unsuccessful payload execution
4. `timeoutTimestamp` not elapsed on the receiving chain
5. Unexpected counterparty channel id| 1. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === null`
2. `provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence))!=null`
3. `onTimeoutPacket(packet.channelSourceId,payload) == False`
4.1 `packet.timeoutTimestamp > 0`
4.2 `proofTimestamp = client.getTimestampAtHeight(proofHeight); proofTimestamp >= packet.timeoutTimestamp`
5. `packet.sourceChannelId != channel.counterpartyChannelId` | -| **Post-Conditions (Success)** | 1. `onTimeoutPacket` is executed and the application state is modified
2. `packetCommitment` has been cleared out
3. `packetReceipt` is empty
4. Event is Emitted
| 1. `onTimeoutPacket(..)==True; app.State(beforeTimeoutPacket)!=app.State(afterTimeoutPacket)`
2. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === null`
3. `provableStore.get(packetReceiptPath(packet.channelDestId, packet.sequence))==null`
4. Check Event is Emitted
| -| **Post-Conditions (Error)** | 1. If `onTimeoutPacket` fails and the application state is unchanged
2. `packetCommitment` is not cleared out
3. No Event Emission
| 1. `onTimeoutPacket(..)==False; app.State(beforeTimeoutPacket)==app.State(afterTimeoutPacket)`
2. `provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) === null`
3. Check No Event is Emitted
| +| **Error-Conditions** | 1. `packetCommitment` already cleared out
2. `packetReceipt` is not empty
3. Unsuccessful payload execution
4. `timeoutTimestamp` not elapsed on the receiving chain
5. Unexpected counterparty channel id| 1. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === null`
2. `provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence))!=null`
3. `onTimeoutPacket(packet.sourceChannel,payload) == False`
4.1 `packet.timeoutTimestamp > 0`
4.2 `proofTimestamp = client.getTimestampAtHeight(proofHeight); proofTimestamp >= packet.timeoutTimestamp`
5. `packet.sourceChannelId != channel.counterpartyChannelId` | +| **Post-Conditions (Success)** | 1. `onTimeoutPacket` is executed and the application state is modified
2. `packetCommitment` has been cleared out
3. `packetReceipt` is empty
4. Event is Emitted
| 1. `onTimeoutPacket(..)==True; app.State(beforeTimeoutPacket)!=app.State(afterTimeoutPacket)`
2. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === null`
3. `provableStore.get(packetReceiptPath(packet.destChannel, packet.sequence))==null`
4. Check Event is Emitted
| +| **Post-Conditions (Error)** | 1. If `onTimeoutPacket` fails and the application state is unchanged
2. `packetCommitment` is not cleared out
3. No Event Emission
| 1. `onTimeoutPacket(..)==False; app.State(beforeTimeoutPacket)==app.State(afterTimeoutPacket)`
2. `provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === null`
3. Check No Event is Emitted
| ###### Pseudo-Code @@ -1030,7 +1015,7 @@ function timeoutPacket( relayer: string ) { // Channel and Client Checks - channel = getChannel(packet.channelSourceId) + channel = getChannel(packet.sourceChannel) assert(client !== null) client = router.clients[channel.clientId] @@ -1040,7 +1025,7 @@ function timeoutPacket( assert(packet.sourceChannelId == channel.counterpartyChannelId) // verify we sent the packet and haven't cleared it out yet - assert(provableStore.get(packetCommitmentPath(packet.channelSourceId, packet.sequence)) + assert(provableStore.get(packetCommitmentPath(packet.sourceChannel, packet.sequence)) === commitV2Packet(packet)) // get the timestamp from the final consensus state in the channel path @@ -1051,7 +1036,7 @@ function timeoutPacket( assert(packet.timeoutTimestamp > 0 && proofTimestamp >= packet.timeoutTimestamp) // verify there is no packet receipt --> receivePacket has not been called - receiptPath = packetReceiptPath(packet.channelDestId, packet.sequence) + receiptPath = packetReceiptPath(packet.destChannel, packet.sequence) merklePath = applyPrefix(channel.keyPrefix, receiptPath) assert(client.verifyNonMembership( client.clientState, @@ -1062,16 +1047,16 @@ function timeoutPacket( payload=packet.data[0] cbs = router.callbacks[payload.sourcePort] - success=cbs.OnTimeoutPacket(packet.channelSourceId,packet.channelDestId,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback + success=cbs.OnTimeoutPacket(packet.sourceChannel,packet.destChannel,packet.sequence,payload,relayer) // Note that payload includes the version. The application is required to inspect the version to route the data to the proper callback abortUnless(success) - channelStore.delete(packetCommitmentPath(packet.channelSourceId, packet.sequence)) + channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence)) // Event Emission for timeout packet emitEvents("timeoutPacket", { sequence: packet.sequence, // value is string in decimal format - sourceId: packet.channelSourceId, - destId: packet.channelDestId, + sourceChannel: packet.sourceChannel, + destChannel: packet.destChannel, }) } ``` From 90a1dd52112f0c159cdf2e9d23151c7dca447ca1 Mon Sep 17 00:00:00 2001 From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 19 Nov 2024 13:33:43 +0100 Subject: [PATCH 6/6] fix typo --- spec/core/v2/ics-004-channel-and-packet-semantics/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md index d44207aab..8ab7fedaa 100644 --- a/spec/core/v2/ics-004-channel-and-packet-semantics/README.md +++ b/spec/core/v2/ics-004-channel-and-packet-semantics/README.md @@ -612,7 +612,7 @@ function sendPacket( // these will include the packet identifier so they can be indexed and // reconstructed by relayers for i, payload in payloads { - emitLongEntry("send_payload", { + emitEvents("send_payload", { sourceChannel: sourceChannelId, destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format @@ -752,7 +752,7 @@ function recvPacket( // these will include the packet identifier so they can be indexed and // reconstructed by relayers for i, payload in payloads { - emitLongEntry("recv_payload", { + emitEvents("recv_payload", { sourceChannel: sourceChannelId, destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format @@ -847,7 +847,7 @@ function writeAcknowledgement( // these will include the packet identifier so they can be indexed and // reconstructed by relayers for i, payload in payloads { - emitLongEntry("recv_payload", { + emitEvents("recv_payload", { sourceChannel: sourceChannelId, destChannel: channel.counterpartyChannelId, sequence: sequence, // value is string in decimal format