From 19ae2273074f64efd68f99699636c61b2f83966e Mon Sep 17 00:00:00 2001 From: Aditya <14364734+AdityaSripal@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:57:18 +0100 Subject: [PATCH] ICS4: Event Emission Specification (NO PSEUDOCODE) (#1172) * event specification * specify events for channel creation * add client id to register counterparty events * rename emitLogEntry to emitEvents * address reviews * fix typo * remove explicit event implementation and include event writeup on what should be included * continue changes --- .../README.md | 243 +++++++----------- 1 file changed, 86 insertions(+), 157 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..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 @@ -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,38 +296,31 @@ 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)) - - // 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 - emitLogEntry("createChannel", { - channelId: channelId, - channel: channel, - creatorAddress: msg.signer(), - }) + // 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 + } + + // Local stores + // Store channel info + storedChannels[channelId]=channel + // Store creator address info + channelCreator[channelId]=msg.signer() + // Initialise the nextSequenceSend + nextSequenceSend[channelId]=1 return channelId } @@ -374,14 +367,6 @@ function registerCounterparty( // Local Store storedChannels[channelId]=channel - - // log that a packet can be safely sent - // Event Emission - emitLogEntry("registerCounterparty", { - channelId: channelId, - channel: channel, - creatorAddress: msg.signer(), - }) } ``` @@ -513,7 +498,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 +549,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 +566,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) @@ -596,19 +580,15 @@ 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", { - sourceId: sourceChannelId, - destId: channel.counterpartyChannelId, - sequence: sequence, - packet: packet, - timeoutTimestamp: timeoutTimestamp, - }) - 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 @@ -634,9 +614,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 @@ -653,7 +633,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) @@ -666,13 +646,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 @@ -686,51 +666,32 @@ function recvPacket( merklePath, commit)) - // 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.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. - emitLogEntry("writeAcknowledgement", { - sequence: packet.sequence, - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - 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 + writeAcknowledgement(packet.destChannel,packet.sequence,ack) } + // 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 ) - - // 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 - }) - } ``` +###### 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". @@ -754,9 +715,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 @@ -776,28 +737,16 @@ 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){ - emitLogEntry("writeAcknowledgement", { - sequence: packet.sequence, - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement - }) - // 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 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. + ##### 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. @@ -814,9 +763,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 @@ -834,7 +783,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) @@ -843,10 +792,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 @@ -860,21 +809,11 @@ 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)) - - // Event Emission // Check fields - emitLogEntry("acknowledgePacket", { - sequence: packet.sequence, - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement - }) + channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence)) } ``` @@ -929,9 +868,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 @@ -947,7 +886,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] @@ -957,7 +896,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 @@ -968,7 +907,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, @@ -979,20 +918,10 @@ 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)) - - // Event Emission // See fields - emitLogEntry("timeoutPacket", { - sequence: packet.sequence, - sourceId: packet.channelSourceId, - destId: packet.channelDestId, - timeoutTimestamp: packet.timeoutTimestamp, - data: packet.data, - acknowledgement - }) + channelStore.delete(packetCommitmentPath(packet.sourceChannel, packet.sequence)) } ```