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/8] 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/8] 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/8] 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/8] 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/8] 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/8] 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
From afb24f6c19e5726e3663035362b12c67316a6443 Mon Sep 17 00:00:00 2001
From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com>
Date: Mon, 2 Dec 2024 20:12:10 +0100
Subject: [PATCH 7/8] remove explicit event implementation and include event
writeup on what should be included
---
.../README.md | 135 +++---------------
1 file changed, 21 insertions(+), 114 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 8ab7fedaa..70d1054f9 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
@@ -321,13 +321,6 @@ function createChannel(
channelCreator[channelId]=msg.signer()
// Initialise the nextSequenceSend
nextSequenceSend[channelId]=1
-
- // Event Emission
- emitEvents("createChannel", {
- channelId: channelId,
- clientId: clientId,
- creatorAddress: msg.signer(),
- })
return channelId
}
@@ -374,14 +367,6 @@ function registerCounterparty(
// Local Store
storedChannels[channelId]=channel
-
- // log that a packet can be safely sent
- // Event Emission
- emitEvents("registerCounterparty", {
- channelId: channelId,
- clientId: channel.clientId
- counterpartyChannelid: counterpartyChannelId,
- })
}
```
@@ -595,37 +580,15 @@ function sendPacket(
// increment the sequence. Thus there are monotonically increasing sequences for packet flow for a given clientId
nextSequenceSend[sourceChannelId]=sequence+1
- // Event Emission for send packet
- emitEvents("send_packet", {
- 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
- // these will include the packet identifier so they can be indexed and
- // reconstructed by relayers
- for i, payload in payloads {
- emitEvents("send_payload", {
- sourceChannel: sourceChannelId,
- destChannel: 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
}
```
+
+###### Send Packet Events
+
+The SendPacket handler **must** emit events that include the entire packet. Thus every packet field must be emitted in events, either in individual key/value pairs or the packet can be encoded and emitted as a single event. Since the protocol only stores the packet commitment hash in state, the entire preimage (ie the packet) must be emitted in events so it can be reconstructed by the relayer. The event **should** also emit the `sourceChannel` and `sequence` separately in order to allow for easy event filtering by relayers that want to focus on relaying for a single channel.
+
+In the case, an implementor does not have access to an event system; the implementor must then store the entire packet in state so it can be retreived by a relayer.
##### Receiving packets
@@ -711,20 +674,9 @@ function recvPacket(
if ack != nil {
// NOTE: Synchronous ack.
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
+ } 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.destChannel,packet.sequence]=packet
}
// Provable Stores
@@ -734,38 +686,15 @@ function recvPacket(
packetReceiptPath(packet.destChannel, packet.sequence),
SUCCESSFUL_RECEIPT
)
-
- // Event Emission for receive packet
- emitEvents("recv_packet", {
- 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
- // these will include the packet identifier so they can be indexed and
- // reconstructed by relayers
- for i, payload in payloads {
- emitEvents("recv_payload", {
- sourceChannel: sourceChannelId,
- destChannel: channel.counterpartyChannelId,
- sequence: sequence, // value is string in decimal 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
- })
- }
-
}
```
+###### Receive Packet Events
+
+The ReceivePacket handler **must** emit events that include the entire packet and the entire acknowledgement. Thus every packet field must be emitted in events, either in individual key/value pairs or the packet can be encoded and emitted as a single event. Furthermore, the acknowledgment must be encoded and emitted as an event. Since the protocol only stores the hash of the packet and acknowledgment in state, the entire preimage (ie the packet and acknowledgement) must be emitted in events so it can be reconstructed by the relayer. The event **should** also emit the `destinationChannel` and `sequence` separately in order to allow for easy event filtering by relayers that want to focus on relaying for a single channel.
+
+In the case, an implementor does not have access to an event system; the implementor must then store the entire packet and acknowledgment in state so it can be retreived by a relayer.
+
##### Writing acknowledgements
> **Note:** The system handles synchronous and asynchronous acknowledgement logic. Writing acknowledgements ensures that application modules callabacks have been triggered and have returned their specific acknowledgment in order to write data which resulted from processing an IBC packet that the sending chain can then verify. Writing acknowledgement serves as a sort of "execution receipt" or "RPC call response".
@@ -829,34 +758,6 @@ function writeAcknowledgement(
acknowledgement: toHex(ack),
})
}
-
- // Event Emission for receive packet. emit again so relayer can reconstruct the packet
- emitEvents("recv_packet", {
- 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
- // these will include the packet identifier so they can be indexed and
- // reconstructed by relayers
- for i, payload in payloads {
- emitEvents("recv_payload", {
- sourceChannel: sourceChannelId,
- destChannel: 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
@@ -864,6 +765,12 @@ function writeAcknowledgement(
}
```
+###### WriteAcknowledgement Events
+
+The WriteAcknowledgement handler must emit the original received packet associated with the acknowledgement and the acknowledgement in events itself. Since the protocol only stores the hash of the packet and acknowledgment in state, the entire preimage (ie the packet and acknowledgement) must be emitted in events so it can be reconstructed by the relayer. Note: In the case of asynchronous acknowledgements; the original received packet must be stored temporarily so that it can be emitted on WriteAcknowledgement events.
+
+In the case, an implementor does not have access to an event system; the implementor must then store the entire packet and acknowledgment in state so it can be retreived by a relayer.
+
##### Processing acknowledgements
The `acknowledgePacket` function is called by the IBC handler to process the acknowledgement of a packet previously sent by the sender chain that has been received on the receiver chain. The `acknowledgePacket` also cleans up the packet commitment, which is no longer necessary since the packet has been received and acted upon.
From f411a58b843ff5376869bcbb4f66b9b3e3703180 Mon Sep 17 00:00:00 2001
From: Aditya Sripal <14364734+AdityaSripal@users.noreply.github.com>
Date: Mon, 2 Dec 2024 20:22:51 +0100
Subject: [PATCH 8/8] continue changes
---
.../README.md | 49 ++-----------------
1 file changed, 3 insertions(+), 46 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 70d1054f9..5db8c5a10 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
@@ -674,11 +674,8 @@ function recvPacket(
if ack != nil {
// NOTE: Synchronous ack.
writeAcknowledgement(packet.destChannel,packet.sequence,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.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}
@@ -740,34 +737,13 @@ function writeAcknowledgement(
// create the acknowledgement coomit using the function defined in [packet specification](https://github.com/cosmos/ibc/blob/c7b2e6d5184b5310843719b428923e0c5ee5a026/spec/core/v2/ics-004-packet-semantics/PACKET.md)
commit=commitV2Acknowledgment(acknowledgement)
- provableStore.set(
- packetAcknowledgementPath(destChannelId, sequence),commit)
-
- // log that a packet has been acknowledged
- // Event Emission
- // 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){
- // emit an acknowledgement event for each app acknowledgement in the acknowledgement
- for i, ack in acknowledgment {
- 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),
- })
- }
-
- // delete the packet from state
- storedPacket[destChannelId,sequence]=nil
- }
+ provableStore.set(packetAcknowledgementPath(destChannelId, sequence),commit)
}
```
###### WriteAcknowledgement Events
-The WriteAcknowledgement handler must emit the original received packet associated with the acknowledgement and the acknowledgement in events itself. Since the protocol only stores the hash of the packet and acknowledgment in state, the entire preimage (ie the packet and acknowledgement) must be emitted in events so it can be reconstructed by the relayer. Note: In the case of asynchronous acknowledgements; the original received packet must be stored temporarily so that it can be emitted on WriteAcknowledgement events.
+The WriteAcknowledgement handler must emit the original received packet associated with the acknowledgement and the acknowledgement in events itself. Since the protocol only stores the hash of the packet and acknowledgment in state, the entire preimage (ie the packet and acknowledgement) must be emitted in events so it can be reconstructed by the relayer. Note: In the case of asynchronous acknowledgements; the original received packet must be stored temporarily so that it can be emitted on WriteAcknowledgement events. The event **should** also emit the `destinationChannel` and `sequence` separately in order to allow for easy event filtering by relayers that want to focus on relaying for a single channel.
In the case, an implementor does not have access to an event system; the implementor must then store the entire packet and acknowledgment in state so it can be retreived by a relayer.
@@ -838,18 +814,6 @@ function acknowledgePacket(
}
channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence))
-
- // emit an acknowledgement event for each app acknowledgement in the acknowledgement
- for i, ack in acknowledgment {
- 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),
- })
- }
-
}
```
@@ -958,13 +922,6 @@ function timeoutPacket(
abortUnless(success)
channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence))
-
- // Event Emission for timeout packet
- emitEvents("timeoutPacket", {
- sequence: packet.sequence, // value is string in decimal format
- sourceChannel: packet.sourceChannel,
- destChannel: packet.destChannel,
- })
}
```