Skip to content

Commit

Permalink
ICS27: add support for unordered channels/implement upgrade callbacks (
Browse files Browse the repository at this point in the history
…#1007)

* wip: adding support for unordered channels to ics27

* support for now only upgrades that do not change the connection hops

* better way to get channel version

* fix comment
  • Loading branch information
Carlos Rodriguez authored Aug 1, 2023
1 parent 8cadde5 commit b6e3ca5
Showing 1 changed file with 164 additions and 7 deletions.
171 changes: 164 additions & 7 deletions spec/app/ics-027-interchain-accounts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -383,14 +383,10 @@ function onChanOpenInit(
counterpartyPortIdentifier: Identifier,
counterpartyChannelIdentifier: Identifier,
version: string) => (version: string, err: Error) {
// only ordered channels allowed
abortTransactionUnless(order === ORDERED)
// validate port format
abortTransactionUnless(validateControllerPortParams(portIdentifier))
// only allow channels to be created on the "icahost" port on the counterparty chain
abortTransactionUnless(counterpartyPortIdentifier === "icahost")
// only open the channel if there is no active channel already set (with status OPEN)
abortTransactionUnless(activeChannel === nil)

if version != "" {
// validate metadata
Expand All @@ -416,6 +412,24 @@ function onChanOpenInit(
}
version = marshalJSON(metadata)
}

// only open the channel if:
// - there is no active channel already set (with status OPEN)
// OR
// - there is already an active channel (with status CLOSED) AND
// the metadata matches exactly the existing metadata in the
// version string of the active channel AND the ordering of the
// new channel matches the ordering of the active channel.
activeChannelId, activeChannelFound = GetActiveChannelID(portId, connectionId)
if activeChannelFound {
activeChannel = provableStore.get(channelPath(portId, activeChannelId))
abortTransactionUnless(activeChannel.state === CLOSED)
previousOrder = activeChannel.order
abortTransactionUnless(previousOrder === order)
previousMetadata = UnmarshalJSON(activeChannel.version)
abortTransactionUnless(previousMetadata === metadata)
}

return version, nil
}
```
Expand All @@ -430,8 +444,6 @@ function onChanOpenTry(
counterpartyPortIdentifier: Identifier,
counterpartyChannelIdentifier: Identifier,
counterpartyVersion: string) (version: string, err: Error) {
// only ordered channels allowed
abortTransactionUnless(order === ORDERED)
// validate port ID
abortTransactionUnless(portIdentifier === "icahost")
// create the interchain account with the counterpartyPortIdentifier
Expand Down Expand Up @@ -477,7 +489,6 @@ function onChanOpenAck(
abortTransactionUnless(IsSupportedTxType(metadata.TxType))
abortTransactionUnless(metadata.ControllerConnectionId === connectionId)
abortTransactionUnless(metadata.HostConnectionId === counterpartyConnectionId)


// state change to keep track of successfully registered interchain account
SetInterchainAccountAddress(portID, metadata.Address)
Expand Down Expand Up @@ -523,6 +534,152 @@ function onChanCloseConfirm(
}
```

### Upgrade handshake

```typescript
// Called on Controller Chain by Authority
function onChanUpgradeInit(
portIdentifier: Identifier,
channelIdentifier: Identifier,
order: ChannelOrder,
connectionHops: [Identifier],
upgradeSequence: uin64
version: string) => (version: string, err: Error) {
// new version proposed in the upgrade
abortTransactionUnless(version !== "")
metadata = UnmarshalJSON(version)

// retrieve the existing channel version.
// In ibc-go, for example, this is done using the GetAppVersion
// function of the ICS4Wrapper interface.
// See https://github.com/cosmos/ibc-go/blob/ac6300bd857cd2bd6915ae51e67c92848cbfb086/modules/core/05-port/types/module.go#L128-L132
channel = provableStore.get(channelPath(portIdentifier, channelIdentifier))
currentMetadata = UnmarshalJSON(channel.version)

// validate metadata
abortTransactionUnless(metadata.Version === "ics27-1")
// all elements in encoding list and tx type list must be supported
abortTransactionUnless(IsSupportedEncoding(metadata.Encoding))
abortTransactionUnless(IsSupportedTxType(metadata.TxType))

// the interchain account address on the host chain
// must remain the same after the upgrade.
abortTransactionUnless(currentMetadata.Address === metadata.Address)

// at the moment it is not supported to perform upgrades that
// change the connection ID of the controller or host chains.
// therefore these connection IDs much remain the same as before.
abortTransactionUnless(currentMetadata.ControllerConnectionId === metadata.ControllerConnectionId)
abortTransactionUnless(currentMetadata.HostConnectionId === metadata.HostConnectionId)
// the proposed connection hop must not change
abortTransactionUnless(currentMetadata.ControllerConnectionId === connectionHops[0])

version = marshalJSON(metadata)
return version, nil
}
```

```typescript
// Called on Host Chain by Relayer
function onChanUpgradeTry(
portIdentifier: Identifier,
channelIdentifier: Identifier,
order: ChannelOrder,
connectionHops: [Identifier],
upgradeSequence: uint64,
counterpartyPortIdentifier: Identifier,
counterpartyChannelIdentifier: Identifier,
counterpartyVersion: string) => (version: string, err: Error) {
// validate port ID
abortTransactionUnless(portIdentifier === "icahost")

// upgrade version proposed by counterparty
abortTransactionUnless(counterpartyVersion !== "")

// retrieve the existing channel version.
// In ibc-go, for example, this is done using the GetAppVersion
// function of the ICS4Wrapper interface.
// See https://github.com/cosmos/ibc-go/blob/ac6300bd857cd2bd6915ae51e67c92848cbfb086/modules/core/05-port/types/module.go#L128-L132
channel = provableStore.get(channelPath(portIdentifier, channelIdentifier))
currentMetadata = UnmarshalJSON(channel.version)

// validate metadata
abortTransactionUnless(metadata.Version === "ics27-1")
// all elements in encoding list and tx type list must be supported
abortTransactionUnless(IsSupportedEncoding(metadata.Encoding))
abortTransactionUnless(IsSupportedTxType(metadata.TxType))

// the interchain account address on the host chain
// must remain the same after the upgrade.
abortTransactionUnless(currentMetadata.Address === metadata.Address)

// at the moment it is not supported to perform upgrades that
// change the connection ID of the controller or host chains.
// therefore these connection IDs much remain the same as before.
abortTransactionUnless(currentMetadata.ControllerConnectionId === metadata.ControllerConnectionId)
abortTransactionUnless(currentMetadata.HostConnectionId === metadata.HostConnectionId)
// the proposed connection hop must not change
abortTransactionUnless(currentMetadata.HostConnectionId === connectionHops[0])

return counterpartyVersion, nil
}
```

```typescript
// Called on Controller Chain by Relayer
function onChanUpgradeAck(
portIdentifier: Identifier,
channelIdentifier: Identifier,
counterpartyVersion: string) => Error {
// final upgrade version proposed by counterparty
abortTransactionUnless(counterpartyVersion !== "")
metadata = UnmarshalJSON(counterpartyVersion)

// retrieve the existing channel version.
// In ibc-go, for example, this is done using the GetAppVersion
// function of the ICS4Wrapper interface.
// See https://github.com/cosmos/ibc-go/blob/ac6300bd857cd2bd6915ae51e67c92848cbfb086/modules/core/05-port/types/module.go#L128-L132
channel = provableStore.get(channelPath(portIdentifier, channelIdentifier))
currentMetadata = UnmarshalJSON(channel.version)

// validate metadata
abortTransactionUnless(metadata.Version === "ics27-1")
// all elements in encoding list and tx type list must be supported
abortTransactionUnless(IsSupportedEncoding(metadata.Encoding))
abortTransactionUnless(IsSupportedTxType(metadata.TxType))

// the interchain account address on the host chain
// must remain the same after the upgrade.
abortTransactionUnless(currentMetadata.Address === metadata.Address)

// at the moment it is not supported to perform upgrades that
// change the connection ID of the controller or host chains.
// therefore these connection IDs much remain the same as before.
abortTransactionUnless(currentMetadata.ControllerConnectionId === metadata.ControllerConnectionId)
abortTransactionUnless(currentMetadata.HostConnectionId === metadata.HostConnectionId)

return nil
}
```

```typescript
// Called on Controller and Host Chains by Relayer
function onChanUpgradeOpen(
portIdentifier: Identifier,
channelIdentifier: Identifier) {
// no-op
}
```

```typescript
// Called on Controller and/or Host Chain by Relayer
function onChanUpgradeRestore(
portIdentifier: Identifier,
channelIdentifier: Identifier) {
// no-op
}
```

### Packet relay
`onRecvPacket` is called by the routing module when a packet addressed to this module has been received.

Expand Down

0 comments on commit b6e3ca5

Please sign in to comment.