Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ICS3: Add Connection Upgrade Spec #621

Merged
merged 29 commits into from
Mar 22, 2022
Merged
Changes from 4 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
e0fa2e1
connection upgrade progress
AdityaSripal Nov 30, 2021
cb0b5c5
initial writeup
AdityaSripal Dec 1, 2021
067956e
add notes on init and try access control
AdityaSripal Dec 1, 2021
dc00b01
address colin suggestions
AdityaSripal Dec 3, 2021
82f7286
Apply suggestions from code review
AdityaSripal Dec 6, 2021
26169bd
address chris initial review
AdityaSripal Dec 6, 2021
b7ab84d
Merge branch 'aditya/path-upgrade' of github.com:cosmos/ibc into adit…
AdityaSripal Dec 6, 2021
d71f150
add timeout logic
AdityaSripal Feb 10, 2022
e398dbb
crossing hellos logic
AdityaSripal Feb 11, 2022
b92cced
migrations and crossing hello cleanup
AdityaSripal Feb 11, 2022
e7ff7bf
Apply suggestions from code review
AdityaSripal Feb 22, 2022
bd795ae
continue addressing @mpoke suggestions
AdityaSripal Feb 28, 2022
da255ad
clarify handshake pseudocode
AdityaSripal Mar 1, 2022
d5588c8
remove unnecessary structs and simplify protocol
AdityaSripal Mar 2, 2022
3d30b28
clarify TRY actor reasoning
AdityaSripal Mar 2, 2022
37916cd
TRY timeout clarification
AdityaSripal Mar 2, 2022
f483d1f
cleanup pseudocode
AdityaSripal Mar 2, 2022
7239327
fix mistakes after readthrough
AdityaSripal Mar 7, 2022
6f7f572
chan->conn
AdityaSripal Mar 7, 2022
758e5ab
Apply suggestions from code review
AdityaSripal Mar 9, 2022
67f2a03
complete fixing minor issues
AdityaSripal Mar 9, 2022
c40ab29
Merge branch 'aditya/path-upgrade' of github.com:cosmos/ibc into adit…
AdityaSripal Mar 9, 2022
a152627
reorder utility function and fix timeout conditional bug
AdityaSripal Mar 9, 2022
6a59321
fix restore connection logic
AdityaSripal Mar 14, 2022
a4c9fdc
use 02-client generic verify methods
AdityaSripal Mar 15, 2022
7359894
address colin comments
AdityaSripal Mar 15, 2022
849059a
Apply suggestions from code review
AdityaSripal Mar 22, 2022
c261dd3
address rest of reviews
AdityaSripal Mar 22, 2022
1948a82
use connection method
AdityaSripal Mar 22, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
365 changes: 365 additions & 0 deletions spec/core/ics-003-connection-semantics/UPGRADES.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,365 @@
# Upgrading Connections

### Synopsis

This standard document specifies the interfaces and state machine logic that IBC implementations must implement in order to enable existing connections to upgrade after initial connection handshake.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

### Motivation

As new features get added to IBC, chains may wish the take advantage of new connection features without abandoning the accumulated state and network effect(s) of an already existing connection. The upgrade protocol proposed would allow chains to renegotiate an existing connection to take advantage of new features without having to create a new connection.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

### Desired Properties

- Both chains must agree to the renegotiated connection parameters
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- Connection state and logic on both chains should either be using the old parameters or the new parameters, but should not be in an in-between state. i.e. It should not be possible for a chain to write state to an old proof path, while the counterparty expects a new proof path.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- If the upgrade handshake is unsuccessful, the connection must fall-back to the original connection parameters
- If the upgrade handshake is successful, then both connection ends have adopted the new connection parameters and process IBC data appropriately.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- The connection upgrade protocol should have the ability to change all connection-related parameters; however the connection upgrade protocol MUST NOT be able to change the underlying `ClientState`.
- The connection upgrade protocol may not modify the connection identifiers.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

## Technical Specification

### Data Structures

```typescript
enum ConnectionState {
INIT,
TRYOPEN,
OPEN,
UPGRADE_INIT,
UPGRADE_TRY,
UPGRADE_ERR,
}
```

- The chain that is proposing the upgrade should set the connection state from `OPEN` to `UPGRADE_INIT`
- The counterparty chain that accepts the upgrade should set the connection state from `OPEN` to `UPGRADE_TRY`

```typescript
interface ConnectionEnd {
mpoke marked this conversation as resolved.
Show resolved Hide resolved
state: ConnectionState
counterpartyConnectionIdentifier: Identifier
counterpartyPrefix: CommitmentPrefix
clientIdentifier: Identifier
counterpartyClientIdentifier: Identifier
version: string | []string
delayPeriodTime: uint64
delayPeriodBlocks: uint64
}
```

The desired property that the connection upgrade protocol may not modify the underlying clients or connection identifiers, means that only some fields are upgradable by the upgrade protocol.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

- `state`: The state is specified by the handshake steps of the upgrade protocol.

CAN BE MODIFIED:
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- `counterpartyPrefix`: The prefix MAY be modified in the upgrade protocol. The counterparty must accept the new proposed prefix value, or it must return an error during the upgrade handshake.
- `version`: The version MAY be modified by the upgrade protocol. The same version negotiation that happens in the initial connection handshake can be employed for the upgrade handshake.
- `delayPeriodTime`: The delay period MAY be modified by the upgrade protocol. The counterparty MUST accept the new proposed value or return an error during the upgrade handshake.
- `delayPeriodBlocks`: The delay period MAY be modified by the upgrade protocol. The counterparty MUST accept the new proposed value or return an error during the upgrade handshake.

CAN NOT BE MODIFIED:
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- `counterpartyConnectionIdentifier`: The counterparty connection identifier CAN NOT be modified by the upgrade protocol.
- `clientIdentifier`: The client identifier CAN NOT be modified by the upgrade protocol
- `counterpartyClientIdentifier`: The counterparty client identifier CAN NOT be modified by the upgrade protocol

```typescript
interface UpgradeStatus {
state: ConnectionState
timeoutHeight: Height
timeoutTimestamp: uint64
}
```

- UpgradeStatus contains the state of the upgrade. If upgrade is successful it will contain the `ConnectionState` of the upgrading connection on the executing chain. If the executing chain wants to abort the upgrade, it will restore its previous connection under its connection path with state `OPEN` and write an `UpgradeStatus` with state `UPGRADE_ERR`.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- `timeoutHeight`: Timeout height indicates the height at which the counterparty must no longer proceed with the upgrade handshake. The chains will then preserve their original connection and the upgrade handshake is aborted.
- `timeoutTimestamp`: Timeout timestamp indicates the time on the counterparty at which the counterparty must no longer proceed with the upgrade handshake. The chains will then preserve their original connection and the upgrade handshake is aborted.

```typescript
interface UpgradeConnectionState {
connection: ConnectionEnd
timeoutHeight: Height
timeoutTimestamp: uint64
mpoke marked this conversation as resolved.
Show resolved Hide resolved
}
```

- `proposedConnectionState`: Proposed `ConnectionState` to replace the current `ConnectionState`, it MUST ONLY modify the fields that are permissable to
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
- `timeoutHeight`: Timeout height indicates the height at which the counterparty must no longer proceed with the upgrade handshake. The chains will then preserve their original connection and the upgrade handshake is aborted.
- `timeoutTimestamp`: Timeout timestamp indicates the time on the counterparty at which the counterparty must no longer proceed with the upgrade handshake. The chains will then preserve their original connection and the upgrade handshake is aborted.

NOTE: One of the timeout height or timeout timestamp must be non-zero.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

### Store Paths

##### Restore Connection Path
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

The chain must store the previous connection end so that it may restore it if the upgrade handshake fails. This may be stored in the private store.

```typescript
function restorePath(id: Identifier): Path {
return "connections/{id}/restore"
}
```

##### UpgradeStatus Path
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

The upgrade status path is a public path that can signal the status of the upgrade to the counterparty. It does not store anything in the successful case, but it will store a sentinel abort value in the case that a chain does not accept the proposed upgrade.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

```typescript
function statusPath(id: Identifier): Path {
return "connections/{id}/upgradeStatus"

}
```

### Upgrade Handshake

The upgrade handshake defines four datagrams: *ConnUpgradeInit*, *ConnUpgradeTry*, *ConnUpgradeAck*, and *ConnUpgradeConfirm*

A successful protocol execution flows as follows (note that all calls are made through modules per ICS 25):

| Initiator | Datagram | Chain acted upon | Prior state (A, B) | Posterior state (A, B) |
| --------- | -------------------- | ---------------- | --------------------------- | --------------------------- |
| Actor | `ConnUpgradeInit` | A | (OPEN, OPEN) | (UPGRADE_INIT, OPEN) |
| Actor | `ConnUpgradeTry` | B | (UPGRADE_INIT, OPEN) | (UPGRADE_INIT, UPGRADE_TRY) |
mpoke marked this conversation as resolved.
Show resolved Hide resolved
| Relayer | `ConnUpgradeAck` | A | (UPGRADE_INIT, UPGRADE_TRY) | (OPEN, UPGRADE_TRY) |
| Relayer | `ConnUpgradeConfirm` | B | (OPEN, UPGRADE_TRY) | (OPEN, OPEN) |

At the end of an opening handshake between two chains implementing the sub-protocol, the following properties hold:
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

- Each chain is running their new upgraded connection end and is processing upgraded logic and state according to the upgraded parameters.
- Each chain has knowledge of and has agreed to the counterparty's upgraded connection parameters.

If a chain does not agree to the proposed counterparty `UpgradeConnectionState`, it may abort the upgrade handshake by writing `UPGRADE_ERR` as the state in the `UpgradeStatus` and storing
it under the status path and restore the original connection.

`statusPath(id) => UpgradeStatus{UPGRADE_ERR}`

A relayer may then submit a `CancelConnectionUpgradeMsg` to the counterparty. Upon receiving this message a chain must verify that the counterparty wrote `UPGRADE_ERR` into its `UpgradeStatus` and if successful, it will restore its original connection as well thus cancelling the upgrade.

If an upgrade message arrives after the specified timeout, then the message MUST NOT execute successfully. Again a relayer may submit a proof of this in a `CancelConnectionUpgradeTimeoutMsg` so that counterparty cancels the upgrade and restores it original connection as well.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

```typescript
function connUpgradeInit(
identifier: Identifier,
proposedUpgrade: UpgradeConnectionState
) {
// current connection must be OPEN
currentConnection = provableStore.get(connectionPath(identifier))
abortTransactionUnless(connection.state == OPEN)

// abort transaction if an unmodifiable field is modified
// upgraded connection state must be in `UPGRADE_INIT`
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
abortTransactionUnless(
proposedUpgrade.connection.state == UPGRADE_INIT &&
proposedUpgrade.connection.counterpartyConnectionIdentifier == currentConnection.counterpartyConnectionIdentifier &&
proposedUpgrade.connection.clientIdentifier == currentConnection.clientIdentifier &&
proposedUpgrade.connection.counterpartyClientIdentifier == currentConnection.counterpartyClientIdentifier &&
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
)

// either timeout height or timestamp must be non-zero
abortTransactionUnless(proposedUpgrade.TimeoutHeight != 0 || proposedUpgrade.TimeoutTimestamp != 0)

upgradeStatus = UpgradeStatus{
state: UPGRADE_INIT,
timeoutHeight: proposedUpgrade.timeoutHeight,
timeoutTimestamp: proposedUpgrade.timeoutTimestamp,
}

provableStore.set(statusPath(identifier), upgradeStatus)
provableStore.set(connectionPath(identifier), proposedUpgrade.connection)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
privateStore.set(restorePath(identifier), currentConnection)
}
```

NOTE: It is up to individual implementations how they will provide access-control to the `ConnUpgradeInit` function. E.g. chain governance, permissioned actor, DAO, etc.
Access control on counterparty should inform choice of timeout values, i.e. timeout value should be large if counterparty's `UpgradeTry` is gated by chain governance.

```typescript
function connUpgradeTry(
identifier: Identifier,
proposedUpgrade: UpgradeConnectionState,
counterpartyConnection: ConnectionEnd,
counterpartyUpgradeStatus: UpgradeStatus,
proofConnection: CommitmentProof,
proofUpgradeStatus: CommitmentProof,
proofHeight: Height
) {
// current connection must be OPEN or UPGRADE_INIT (crossing hellos)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
currentConnection = provableStore.get(connectionPath(identifier))
abortTransactionUnless(connection.state == (OPEN || UPGRADE_INIT))

// abort transaction if an unmodifiable field is modified
// upgraded connection state must be in `UPGRADE_TRY`
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
abortTransactionUnless(
proposedUpgrade.connection.state == UPGRADE_TRY &&
proposedUpgrade.connection.counterpartyConnectionIdentifier == currentConnection.counterpartyConnectionIdentifier &&
proposedUpgrade.connection.clientIdentifier == currentConnection.clientIdentifier &&
proposedUpgrade.connection.counterpartyClientIdentifier == currentConnection.counterpartyClientIdentifier &&
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
)

// either timeout height or timestamp must be non-zero
abortTransactionUnless(proposedUpgrade.TimeoutHeight != 0 || proposedUpgrade.TimeoutTimestamp != 0)


// verify proofs of counterparty state
abortTransactionUnless(currentConnection.client.verifyConnectionState(proofHeight, proofConnection, counterpartyConnection))
abortTransactionUnless(currentConnection.client.verifyUpgradeStatus(proofHeight, proofUpgradeStatus, counterpartyUpgradeStatus))
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// verify that counterparty connection unmodifiable fields have not changed and counterparty state
// is UPGRADE_INIT
restoreConnectionUnless(
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
counterpartyConnection.state == UPGRADE_INIT &&
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
counterpartyConnection.counterpartyConnectionIdentifier == identifier &&
counterpartyConnection.clientIdentifier == currentConnection.counterpartyClientIdentifier &&
counterpartyConnection.counterpartyClientIdentifier == currentConnection.clientIdentifier
)
restoreConnectionUnless(counterpartyUpgradeStatus.state == UPGRADE_INIT)

// counterparty-specified timeout must not have exceeded
restoreConnectionUnless(
counterparty.UpgradeStatus.TimeoutHeight < currentHeight() &&
counterparty.UpgradeStatus.TimeoutTimestamp < currentTimestamp()
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
)

// verify chosen versions are compatible
versionsIntersection = intersection(counterpartyConnection.version, proposedUpgrade.Connection.version)
version = pickVersion(versionsIntersection) // throws if there is no intersection

// both connection ends must be mutually compatible.
restoreConnectionUnless(IsCompatible(counterpartyConnection, proposedUpgrade.Connection))
mpoke marked this conversation as resolved.
Show resolved Hide resolved

upgradeStatus = UpgradeStatus{
state: UPGRADE_TRY,
timeoutHeight: proposedUpgrade.timeoutHeight,
timeoutTimestamp: proposedUpgrade.timeoutTimestamp,
}

provableStore.set(statusPath(identifier), upgradeStatus)
provableStore.set(connectionPath(identifier), proposedUpgrade.connection)
Copy link
Contributor

Choose a reason for hiding this comment

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

Interesting, I'd think you'd want to leave the connection unchanged until the upgrade process successfully completes. Otherwise you could potentially disrupt packet flow if the connection is in UPGRADE_INIT instead of OPEN?

I'd expect you to store the proposed upgrade connection under a proposed upgrade connection path. Use that for proofs and then if successful update the connection on ack/confirm?

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't want the case where chainA has its connectionEnd OPEN with the old parameters, and chainB has its connectionEnd OPEN with the new parameters as that may cause unexpected consequences.

If a connection is OPEN on both ends it should be a valid connection always.

So either both ends are OPEN running the old parameters, or both ends are OPEN running the new parameters.

The only way to accomplish this is to temporarily close the connection on both sides (INIT and TRY), then reopen after the upgrade is complete on either end (ACK and CONFIRM).

This does mean packet flow is temporarily halted but i believe this is fine. Once the connection is back up, the relayers can either receive or timeout the pending packets

Copy link
Member Author

Choose a reason for hiding this comment

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

This is also why I specify a timeout, because I don't want the "temporary pause" to last arbitrarily long

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, this makes sense to me

privateStore.set(restorePath(identifier), currentConnection)
}
```

NOTE: It is up to individual implementations how they will provide access-control to the `ConnUpgradeTry` function. E.g. chain governance, permissioned actor, DAO, etc.


```typescript
function onChanUpgradeAck(
identifier: Identifier,
counterpartyConnection: ConnectionEnd,
counterpartyStatus: UpgradeStatus,
proofConnection: CommitmentProof,
proofUpgradeStatus: CommitmentProof,
proofHeight: Height
) {
// current connection is in UPGRADE_INIT
currentConnection = provableStore.get(connectionPath(identifier))
abortTransactionUnless(connection.state == UPGRADE_INIT)


// verify proofs of counterparty state
abortTransactionUnless(currentConnection.client.verifyConnectionState(proofHeight, proofConnection, counterpartyConnection))
abortTransactionUnless(currentConnection.client.verifyUpgradeStatus(proofHeight, proofUpgradeStatus, counterpartyUpgradeStatus))
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// counterparty must be in TRY state
restoreConnectionUnless(counterpartyStatus.state == UPGRADE_TRY)
restoreConnectionUnless(counterpartyConnection.State == UPGRADE_TRY)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// verify connections are mutually compatible
// this will also check counterparty chosen version is valid
restoreConnectionUnless(IsCompatible(counterpartyConnection, connection))

// counterparty-specified timeout must not have exceeded
restoreConnectionUnless(
counterparty.UpgradeStatus.TimeoutHeight < currentHeight() &&
counterparty.UpgradeStatus.TimeoutTimestamp < currentTimestamp()
)

// upgrade is complete
// set connection to OPEN and remove unnecessary state
currentConnection.state = OPEN
provableStore.set(connectionPath(identifier), currentConnection)
provableStore.delete(statusPath(identifier))
privateStore.delete(restorePath(identifier))
}
```

```typescript
function onChanUpgradeConfirm(
identifier: Identifier,
counterpartyConnection: ConnectionEnd,
proofConnection: CommitmentProof,
proofHeight: Height,
) {
// current connection is in UPGRADE_TRY
currentConnection = provableStore.get(connectionPath(identifier))
abortTransactionUnless(connection.state == UPGRADE_TRY)
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// counterparty must be in OPEN state
abortTransactionUnless(counterpartyConnection.State == OPEN)

// verify proofs of counterparty state
abortTransactionUnless(currentConnection.client.verifyConnectionState(proofHeight, proofConnection, counterpartyConnection))
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

Copy link
Contributor

Choose a reason for hiding this comment

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

Before changing the local connection state to OPEN, shouldn't we check again that the remote connection is compatible with the local one? During connUpgradeAck, the remote side could restore the connection, which means moving to a connection with state OPEN. Just verifying that the remote side is OPEN may not be enough.

connUpgradeConfirm should also contain a proof that UpgradeError was not set by the remote side.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ahh thank you, nice catch

// upgrade is complete
// set connection to OPEN and remove unnecessary state
currentConnection.state = OPEN
provableStore.set(connectionPath(identifier), currentConnection)
provableStore.delete(statusPath(identifier))
privateStore.delete(restorePath(identifier))
}
```

Note: In the `TRY` and `ACK` steps, the chain has the ability to abort the upgrade process if the upgrade parameters are not suitable or the timeout has exceeded. In this case, the chain is expected to write `UPGRADE_ERR` as the state in the `UPGRADE_STATUS`, and restore the original connection with state `OPEN`. The counterparty can then verify that the upgrade status is `UPGRADE_ERR` and restore its original connection to `OPEN` as well, thus cancelling the upgrade.
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

```typescript
function restoreConnectionUnless(condition: bool) {
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
if !condition {
// cancel upgrade
// set UpgradeStatus to `UPGRADE_ERR`
// and restore original conneciton
errStatus = UpgradeStatus{UPGRADE_ERR}
provableStore.set(statusPath(identifier), errStatus)
originalConnection = privateStore.get(restorePath(identifier))
mpoke marked this conversation as resolved.
Show resolved Hide resolved
provableStore.set(connectionPath(identifier), originalConnection)
privateStore.delete(restorePath(identifier))
// caller should return as well
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved
} else {
// caller should continue execution
}
}
```

### Cancel Upgrade Process

As discussed, during the upgrade handshake a chain may cancel the upgrade by writing `UPGRADE_ERR` into the `UpgradeStatus` and restoring the original connection to `OPEN`. The counterparty must then restore its connection to `OPEN` as well. A relayer can facilitate this by calling `CancelConnectionUpgrade`

```typescript
function cancelConnectionUpgrade(
identifier: Identifer,
counterpartyUpgradeStatus: UpgradeStatus,
proofUpgradeStatus: CommitmentProof,
proofHeight: Height,
) {
// current connection is in UPGRADE_INIT or UPGRADE_TRY
currentConnection = provableStore.get(connectionPath(identifier))
abortTransactionUnless(connection.state == (UPGRADE_INIT || UPGRADE_TRY))
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

abortTransactionUnless(counterpartyUpgradeStatus.state == UPGRADE_ERR)

abortTransactionUnless(currentConnection.client.verifyUpgradeStatus(proofHeight, proofUpgradeStatus, counterpartyUpgradeStatus))
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved

// cancel upgrade
// and restore original conneciton
// delete unnecessary state
originalConnection = privateStore.get(restorePath(identifier))
provableStore.set(connectionPath(identifier), originalConnection)
provableStore.delete(statusPath(identifier))
privateStore.delete(restorePath(identifier))
}
```

It is possible that there is an extraordinary delay in the upgrade handshake occurs because of liveness issues. In this case, we do not want to indefinitely stay in the upgrade process and we will revert to the original connection by calling `CancelConnectionUpgradeTimeout`.

// TODO
AdityaSripal marked this conversation as resolved.
Show resolved Hide resolved