From 2a5b27e5c6cbb2f1aeb8891b35eee3cadcc3c084 Mon Sep 17 00:00:00 2001 From: Christopher Goes <cwgoes@pluranimity.org> Date: Thu, 4 Jul 2019 13:59:44 +0200 Subject: [PATCH] Merge PR #143: ICS 005: Port Allocation --- README.md | 6 +- assets/deps.png | 3 + .../interchain-standards-image.jpg | Bin deps.png | 3 - scripts/check_dependencies.py | 2 +- spec/ics-003-connection-semantics/state.png | 2 +- .../README.md | 61 +++--- spec/ics-005-port-allocation/README.md | 178 ++++++++++++++++++ spec/ics-024-host-requirements/README.md | 4 +- spec/ics-025-handler-interface/README.md | 22 +-- spec/ics-026-relayer-module/README.md | 10 +- 11 files changed, 237 insertions(+), 54 deletions(-) create mode 100644 assets/deps.png rename interchain-standards-image.jpg => assets/interchain-standards-image.jpg (100%) delete mode 100644 deps.png create mode 100644 spec/ics-005-port-allocation/README.md diff --git a/README.md b/README.md index 8f38c89cff6a..7f29cb915fe9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Interchain Standards Development -![banner](./interchain-standards-image.jpg) + +![banner](./assets/interchain-standards-image.jpg) ## Synopsis @@ -42,6 +43,7 @@ All standards in the "draft" stage are listed here in order of their ICS numbers | [2](spec/ics-002-consensus-verification) | Consensus Verification | Draft | | [3](spec/ics-003-connection-semantics) | Connection Semantics | Draft | | [4](spec/ics-004-channel-and-packet-semantics) | Channel & Packet Semantics | Draft | +| [5](spec/ics-005-port-allocation) | Port Allocation | Draft | | [18](spec/ics-018-relayer-algorithms) | Relayer Algorithms | Draft | | [23](spec/ics-023-vector-commitments) | Vector Commitments | Draft | | [24](spec/ics-024-host-requirements) | Host Requirements | Draft | @@ -52,4 +54,4 @@ All standards in the "draft" stage are listed here in order of their ICS numbers Directed arrows indicate a dependency relationship (that origin depends on destination). -![deps](deps.png) +![deps](assets/deps.png) diff --git a/assets/deps.png b/assets/deps.png new file mode 100644 index 000000000000..a5c70e230cf3 --- /dev/null +++ b/assets/deps.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f6bcad868736846b528f83481e0c2a86cc63f455394060089d4220de615798b +size 58872 diff --git a/interchain-standards-image.jpg b/assets/interchain-standards-image.jpg similarity index 100% rename from interchain-standards-image.jpg rename to assets/interchain-standards-image.jpg diff --git a/deps.png b/deps.png deleted file mode 100644 index 241a50d368b7..000000000000 --- a/deps.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:9aa780487763b92fa2eb07a1382364d2881d372a26a549c53b0dad71ba323040 -size 56005 diff --git a/scripts/check_dependencies.py b/scripts/check_dependencies.py index 3b55373f623e..2e3a902923c0 100755 --- a/scripts/check_dependencies.py +++ b/scripts/check_dependencies.py @@ -51,4 +51,4 @@ print('Drawing dependency graph...') nx.draw_circular(G, with_labels = True, font_weight = 'bold', node_size = 500) -plt.savefig('deps.png') +plt.savefig('assets/deps.png') diff --git a/spec/ics-003-connection-semantics/state.png b/spec/ics-003-connection-semantics/state.png index 421ada96ea63..eb047dbb6864 100644 --- a/spec/ics-003-connection-semantics/state.png +++ b/spec/ics-003-connection-semantics/state.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:178874921a98d971f7a518323ce619115cae48f560b4937726a5a06c6449b780 +oid sha256:ab6ff3a273ddcd83c7353debf72e7f6dda825c32605c32f7ff93aed6ae3bb96d size 346289 diff --git a/spec/ics-004-channel-and-packet-semantics/README.md b/spec/ics-004-channel-and-packet-semantics/README.md index e21723090f3a..d1b469a620c6 100644 --- a/spec/ics-004-channel-and-packet-semantics/README.md +++ b/spec/ics-004-channel-and-packet-semantics/README.md @@ -3,7 +3,7 @@ ics: 4 title: Channel & Packet Semantics stage: draft category: ibc-core -requires: 2, 3, 23, 24 +requires: 2, 3, 5, 23, 24 author: Christopher Goes <cwgoes@tendermint.com> created: 2019-03-07 modified: 2019-06-05 @@ -29,6 +29,8 @@ In order to provide the desired ordering, exactly-once delivery, and module perm `Connection` is as defined in [ICS 3](../ics-003-connection-semantics). +`Port` and `authenticate` are as defined in [ICS 5](../ics-005-port-allocation). + `Commitment`, `CommitmentProof`, and `CommitmentRoot` are as defined in [ICS 23](../ics-023-vector-commitments). `commit` is a generic collision-resistant hash function, the specifics of which must be agreed on by the modules utilizing the channel. @@ -57,16 +59,16 @@ An *end* of a channel is a data structure on one chain storing channel metadata: interface ChannelEnd { state: ChannelEndState counterpartyChannelIdentifier: Identifier - moduleIdentifier: Identifier - counterpartyModuleIdentifier: Identifier + portIdentifier: Identifier + counterpartyPortIdentifier: Identifier nextTimeoutHeight: uint64 } ``` - The `state` is the current state of the channel end. - The `counterpartyChannelIdentifier` identifies the channel end on the counterparty chain. -- The `moduleIdentifier` identifies the module which owns this channel end. -- The `counterpartyModuleIdentifier` identifies the module on the counterparty chain which owns the other end of the channel. +- The `portIdentifier` identifies the module which owns this channel end. +- The `counterpartyPortIdentifier` identifies the module on the counterparty chain which owns the other end of the channel. - The `nextSequenceSend`, stored separately, tracks the sequence number for the next packet to be sent. - The `nextSequenceRecv`, stored separately, tracks the sequence number for the next packet to be received. - The `nextTimeoutHeight` stores the timeout height for the next stage of the handshake, used only in channel opening and closing handshakes. @@ -201,12 +203,13 @@ could be implemented to provide this). ```typescript function chanOpenInit( connectionIdentifier: Identifier, channelIdentifier: Identifier, - counterpartyChannelIdentifier: Identifier, counterpartyModuleIdentifier: Identifier, nextTimeoutHeight: uint64) { + portIdentifier: Identifier, counterpartyChannelIdentifier: Identifier, + counterpartyPortIdentifier: Identifier, nextTimeoutHeight: uint64) { assert(get(channelKey(connectionIdentifier, channelIdentifier)) === nil) connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) - moduleIdentifier = getCallingModule() - channel = Channel{INIT, moduleIdentifier, counterpartyModuleIdentifier, + assert(authenticate(get(portKey(portIdentifier)))) + channel = Channel{INIT, portIdentifier, counterpartyPortIdentifier, counterpartyChannelIdentifier, nextTimeoutHeight} set(channelKey(connectionIdentifier, channelIdentifier), channel) set(nextSequenceSendKey(connectionIdentifier, channelIdentifier), 0) @@ -219,12 +222,12 @@ The `chanOpenTry` function is called by a module to accept the first step of a c ```typescript function chanOpenTry( connectionIdentifier: Identifier, channelIdentifier: Identifier, counterpartyChannelIdentifier: Identifier, - moduleIdentifier: Identifier, counterpartyModuleIdentifier: Identifier, + portIdentifier: Identifier, counterpartyPortIdentifier: Identifier, timeoutHeight: uint64, nextTimeoutHeight: uint64, proofInit: CommitmentProof, proofHeight: uint64) { assert(getConsensusState().height < timeoutHeight) assert(get(channelKey(connectionIdentifier, channelIdentifier)) === null) - assert(getCallingModule() === moduleIdentifier) + assert(authenticate(get(portKey(portIdentifier)))) connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) counterpartyStateRoot = get(rootKey(connection.clientIdentifier, proofHeight)) @@ -232,9 +235,9 @@ function chanOpenTry( counterpartyStateRoot, proofInit, channelKey(connection.counterpartyConnectionIdentifier, counterpartyChannelIdentifier), - Channel{INIT, counterpartyModuleIdentifier, moduleIdentifier, channelIdentifier, timeoutHeight} + Channel{INIT, counterpartyPortIdentifier, portIdentifier, channelIdentifier, timeoutHeight} )) - channel = Channel{OPENTRY, moduleIdentifier, counterpartyModuleIdentifier, + channel = Channel{OPENTRY, portIdentifier, counterpartyPortIdentifier, counterpartyChannelIdentifier, nextTimeoutHeight} set(channelKey(connectionIdentifier, channelIdentifier), channel) set(nextSequenceSendKey(connectionIdentifier, channelIdentifier), 0) @@ -253,7 +256,7 @@ function chanOpenAck( assert(getConsensusState().height < timeoutHeight) channel = get(channelKey(connectionIdentifier, channelIdentifier)) assert(channel.state === INIT) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) counterpartyStateRoot = get(rootKey(connection.clientIdentifier, proofHeight)) @@ -261,7 +264,7 @@ function chanOpenAck( counterpartyStateRoot, proofTry, channelKey(connection.counterpartyConnectionIdentifier, channel.counterpartyChannelIdentifier), - Channel{OPENTRY, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + Channel{OPENTRY, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} )) channel.state = OPEN @@ -280,7 +283,7 @@ function chanOpenConfirm( assert(getConsensusState().height < timeoutHeight) channel = get(channelKey(connectionIdentifier, channelIdentifier)) assert(channel.state === OPENTRY) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) counterpartyStateRoot = get(rootKey(connection.clientIdentifier, proofHeight)) @@ -288,7 +291,7 @@ function chanOpenConfirm( counterpartyStateRoot, proofAck, channelKey(connection.counterpartyConnectionIdentifier, channel.counterpartyChannelIdentifier), - Channel{OPEN, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + Channel{OPEN, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} )) channel.state = OPEN @@ -325,12 +328,12 @@ function chanOpenTimeout( verifyMembership( counterpartyStateRoot, proofTimeout, channelKey(connection.counterpartyConnectionIdentifier, channel.counterpartyChannelIdentifier), - Channel{INIT, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + Channel{INIT, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} ) ) case OPEN: - expected = Channel{OPENTRY, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + expected = Channel{OPENTRY, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} assert(verifyMembership( counterpartyStateRoot, proofTimeout, @@ -374,7 +377,7 @@ function chanCloseTry( connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) counterpartyStateRoot = get(rootKey(connection.clientIdentifier, proofHeight)) - expected = Channel{INIT, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + expected = Channel{INIT, channel.counterpartyPortIdentifier, channel.portIdentifier, channel.channelIdentifier, timeoutHeight} assert(verifyMembership( counterpartyStateRoot, @@ -401,7 +404,7 @@ function chanCloseAck( connection = get(connectionKey(connectionIdentifier)) assert(connection.state === OPEN) counterpartyStateRoot = get(rootKey(connection.clientIdentifier, proofHeight)) - expected = Channel{CLOSED, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + expected = Channel{CLOSED, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} assert(verifyMembership( counterpartyStateRoot, @@ -427,10 +430,10 @@ function chanCloseTimeout( assert(proofHeight >= connection.nextTimeoutHeight) switch channel.state { case CLOSETRY: - expected = Channel{OPEN, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + expected = Channel{OPEN, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} case CLOSED: - expected = Channel{CLOSETRY, channel.counterpartyModuleIdentifier, channel.moduleIdentifier, + expected = Channel{CLOSETRY, channel.counterpartyPortIdentifier, channel.portIdentifier, channelIdentifier, timeoutHeight} } verifyMembership( @@ -457,7 +460,7 @@ Calling modules MUST execute application logic atomically in conjunction with ca The IBC handler performs the following steps in order: - Checks that the channel & connection are open to send packets -- Checks that the calling module owns the channel end +- Checks that the calling module owns the sending port - Checks that the packet metadata matches the channel & connection information - Checks that the timeout height specified has not already passed on the destination chain - Increments the send sequence counter associated with the channel @@ -469,7 +472,7 @@ Note that the full packet is not stored in the state of the chain - merely a sho function sendPacket(packet: Packet) { channel = get(channelKey(packet.sourceConnection, packet.sourceChannel)) assert(channel.state === OPEN) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) assert(packet.destChannel === channel.counterpartyChannelIdentifier) connection = get(connectionKey(packet.sourceConnection)) assert(connection.state === OPEN) @@ -492,7 +495,7 @@ Calling modules MUST execute application logic atomically in conjunction with ca The IBC handler performs the following steps in order: - Checks that the channel & connection are open to receive packets -- Checks that the calling module owns the channel end +- Checks that the calling module owns the receiving port - Checks that the packet metadata matches the channel & connection information - Checks that the packet sequence is the next sequence the channel end expects to receive - Checks that the timeout height has not yet passed @@ -503,7 +506,7 @@ The IBC handler performs the following steps in order: function recvPacket(packet: Packet, proof: CommitmentProof, proofHeight: uint64) { channel = get(channelKey(packet.destConnection, packet.destChannel)) assert(channel.state === OPEN) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) assert(packet.sourceChannel === channel.counterpartyChannelIdentifier) nextSequenceRecv = get(nextSequenceRecvKey(packet.destConnection, packet.destChannel)) assert(packet.sequence === nextSequenceRecv) @@ -541,7 +544,7 @@ Calling modules MUST atomically execute appropriate application timeout-handling function timeoutPacket(packet: Packet, proof: CommitmentProof, proofHeight: uint64, nextSequenceRecv: uint64) { channel = get(channelKey(packet.sourceConnection, packet.sourceChannel)) assert(channel.state === OPEN) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) assert(packet.destChannel === channel.counterpartyChannelIdentifier) connection = get(connectionKey(packet.sourceConnection)) @@ -588,7 +591,7 @@ Calling modules MUST NOT execute any application logic in conjunction with calli function recvTimeoutPacket(packet: Packet, proof: CommitmentProof, proofHeight: uint64) { channel = get(channelKey(packet.destConnection, packet.destChannel)) assert(channel.state === OPEN) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) assert(packet.sourceChannel === channel.counterpartyChannelIdentifier) connection = get(connectionKey(connectionIdentifier)) @@ -621,7 +624,7 @@ function recvTimeoutPacket(packet: Packet, proof: CommitmentProof, proofHeight: function cleanupPacket(packet: Packet, proof: CommitmentProof, proofHeight: uint64, nextSequenceRecv: uint64) { channel = get(channelKey(packet.sourceConnection, packet.sourceChannel)) assert(channel.state === OPEN) - assert(getCallingModule() === channel.moduleIdentifier) + assert(authenticate(get(portKey(channel.portIdentifier)))) assert(packet.destChannel === channel.counterpartyChannelIdentifier) connection = get(connectionKey(packet.sourceConnection)) diff --git a/spec/ics-005-port-allocation/README.md b/spec/ics-005-port-allocation/README.md new file mode 100644 index 000000000000..198b4392548e --- /dev/null +++ b/spec/ics-005-port-allocation/README.md @@ -0,0 +1,178 @@ +--- +ics: 5 +title: Port Allocation +stage: Draft +requires: 24 +required-by: 4 +category: IBC Core +author: Christopher Goes <cwgoes@tendermint.com> +created: 29 June 2019 +modified: 29 June 2019 +--- + +## Synopsis + +This standard specifies the port allocation system by which modules can bind to uniquely named ports, allocated by the IBC handler, +from and to which channels can then be opened, and which can be transferred or later released by the module which originally bound to them and then reused. + +### Motivation + +The interblockchain communication protocol is designed to faciliate module-to-module traffic, where modules are independent, possibly mutually distrusted, self-contained +elements of code executing on sovereign ledgers. In order to provide the desired end-to-end semantics, the IBC handler must permission channels to particular modules, and +for convenience they should be addressable by name. This specification defines the *port allocation and ownership* system which realises that model. + +Conventions may emerge as to what kind of module logic is bound to a particular port name, such as "bank" for fungible token handling or "staking" for interchain collateralization. +This is analogous to port 80's common use for HTTP servers — the protocol cannot enforce that particular module logic is *actually* bound to conventional ports, so +users must check that themselves. + +### Definitions + +`Identifier`, `get`, `set`, and `del` are defined as in [ICS 24](../ics-024-host-requirements). + +A *port* is a particular kind of identifier which is used to permission channel opening and usage to modules. + +A *module* is a subcomponent of the host state machine independent of the IBC handler. Examples include Ethereum smart contracts and Cosmos SDK & Substrate modules. +The IBC specification makes no assumptions of module functionality other than the ability of the host state machine to use object-capability or source authentication to permission ports to modules. + +### Desired Properties + +- Once a module has bound to a port, no other modules can use that port until the module releases it +- A module can, on its option, release a port or transfer it to another module +- A single module can bind to multiple ports at once +- Ports are allocated first-come first-serve and "reserved" ports for known modules can be bound when the chain is first started + +## Technical Specification + +### Data Structures + +The host state machine MUST support either object-capability reference or source authentication for modules. + +In the former case, the IBC handler must have the ability to generate *object-capability keys*, unique, opaque references +which can be passed to a module and will not be duplicable by other modules. Two examples are store keys as used in the Cosmos SDK ([reference](https://github.com/cosmos/cosmos-sdk/blob/master/store/types/store.go#L224)) +and object references as used in Agoric's Javascript runtime ([reference](https://github.com/Agoric/SwingSet)). + +```typescript +type CapabilityKey object +``` + +```typescript +function newCapabilityKey(): CapabilityKey { + // provided by host state machine, e.g. pointer address in Cosmos SDK +} +``` + +In the latter case, the IBC handler must have the ability to securely read the *source identifier* of the calling module, +a unique string for each module in the host state machine, which cannot be altered by the module or faked by another module. +An example is smart contract addresses as used by Ethereum ([reference](https://ethereum.github.io/yellowpaper/paper.pdf)). + +```typescript +type SourceIdentifier string +``` + +```typescript +function callingModuleIdentifier(): SourceIdentifier { + // provided by host state machine, e.g. contract address in Ethereum +} +``` + +`generate` and `authenticate` functions are then defined as follows. + +In the former case, `generate` returns a new object-capability key, which must be returned by the outer-layer function, and `authenticate` requires that the outer-layer function take an extra argument `capability`, which is an object-capability key with uniqueness enforced by the host state machine. + +``` +function generate(): CapabilityKey { + return newCapabilityKey() +} +``` + +``` +function authenticate(key: CapabilityKey) { + return capability === key +} +``` + +In the latter case, `generate` returns the calling module's identifier and `authenticate` merely checks it. + +``` +function generate(): SourceIdentifier { + return callingModuleIdentifier() +} +``` + +``` +function authenticate(id: SourceIdentifier) { + return callingModuleIdentifier() === id +} +``` + +### Subprotocols + +#### Preliminaries + +`portKey` takes an `Identifier` and returns the store key under which the object-capability reference or owner module identifier associated with a port should be stored. + +```typescript +function portKey(id: Identifier) { + return "ports/{id}" +} +``` + +#### Binding to a port + +The IBC handler MUST implement `bindPort`. `bindPort` binds to an unallocated port, failing if the port has already been allocated. + +```typescript +function bindPort(id: Identifier) { + assert(get(portKey(id)) === null) + key = generate() + set(key, portKey(id)) + return key +} +``` + +#### Transferring ownership of a port + +If the host state machine supports object-capability keys, no additional protocol is necessary, since the port reference is a bearer capability. If it does not, the IBC handler MAY implement the following `transferPort` function. + +```typescript +function transferPort(id: Identifier) { + assert(authenticate(get(portKey(id)))) + key = generate() + set(portKey(id), key) +} +``` + +#### Releasing a port + +The IBC handler MUST implement the `releasePort` function, which allows a module to release a port such that other modules may then bind to it. + +```typescript +function releasePort(id: Identifier) { + assert(authenticate(get(portKey(id)))) + del(portKey(id)) +} +``` + +## Backwards Compatibility + +Not applicable. + +## Forwards Compatibility + +Port binding is not a wire protocol, so interfaces can change independently on separate chains as long as the ownership semantics are unaffected. + +## Example Implementation + +Coming soon. + +## Other Implementations + +Coming soon. + +## History + +29 June 2019 - Initial draft + +## Copyright + +All content herein is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). diff --git a/spec/ics-024-host-requirements/README.md b/spec/ics-024-host-requirements/README.md index 83ab8d6b0a3c..43f53b8fcce8 100644 --- a/spec/ics-024-host-requirements/README.md +++ b/spec/ics-024-host-requirements/README.md @@ -3,7 +3,7 @@ ics: 24 title: Host State Machine Requirements stage: draft category: ibc-core -required-by: 2, 3, 4, 18 +required-by: 2, 3, 4, 5, 18 author: Christopher Goes <cwgoes@tendermint.com> created: 2019-04-16 modified: 2019-05-11 @@ -89,7 +89,7 @@ Host chains MUST permission interaction with the IBC handler such that: - A single module can bind to multiple ports - Ports are allocated first-come first-serve and "reserved" ports for known modules can be bound when the chain is first started -This permissioning can be implemented either with unique references (object capabilities) for each port (a la the Cosmos SDK) or with source authentication (a la Ethereum), in either case enforced by the host state machine. +This permissioning can be implemented either with unique references (object capabilities) for each port (a la the Cosmos SDK) or with source authentication (a la Ethereum), in either case enforced by the host state machine. See [ICS 5](../ics-005-port-allocation) for details. Modules which wish to make use of particular IBC features MAY implement certain handler functions, e.g. to add additional logic to a channel handshake with an associated module on another chain. diff --git a/spec/ics-025-handler-interface/README.md b/spec/ics-025-handler-interface/README.md index 115757ae3129..25772ea8f05c 100644 --- a/spec/ics-025-handler-interface/README.md +++ b/spec/ics-025-handler-interface/README.md @@ -32,7 +32,7 @@ IBC is an inter-module communication protocol, designed to faciliate reliable, a ### Desired Properties - Creation of clients, connections, and channels should be as permissionless as possible. -- The module set should be dynamic: chains should be able to add and destroy modules at will with a persistent IBC handler. +- The module set should be dynamic: chains should be able to add and destroy modules, which can themselves bind to and unbind from ports, at will with a persistent IBC handler. - Modules should be able to write their own more complex abstractions on top of IBC to provide additional semantics or guarantees. ## Technical Specification @@ -208,32 +208,32 @@ function queryConnection(id: Identifier): ConnectionEnd | void { ### Channel lifecycle management -By default, channels are owned by the creating module, meaning only the creating module can inspect, close, or send on the channel. A module can create any number of channels. +By default, channels are owned by the creating port, meaning only the module bound to that port can inspect, close, or send on the channel. A port can create any number of channels. `chanOpenInit` tries to start the handshake to create a new channel with the provided options, failing if the connection is not found or the options are invalid. ```typescript function chanOpenInit( connectionIdentifier: Identifier, channelIdentifier: Identifier, - counterpartyChannelIdentifier: Identifier, counterpartyModuleIdentifier: Identifier, nextTimeoutHeight: uint64) { + counterpartyChannelIdentifier: Identifier, counterpartyPortIdentifier: Identifier, nextTimeoutHeight: uint64) { // defined in ICS 4 } ``` -`chanOpenTry` tries to initialize a channel based on proof of an initialization attempt on the counterparty chain, failing if the channel identifier is unavailable, the proof is invalid, or the calling module is not authorized. +`chanOpenTry` tries to initialize a channel based on proof of an initialization attempt on the counterparty chain, failing if the channel identifier is unavailable, the proof is invalid, or the calling module is not bound to the port. The default IBC relayer module will allow external calls to `chanOpenTry`. ```typescript function chanOpenTry( connectionIdentifier: Identifier, channelIdentifier: Identifier, counterpartyChannelIdentifier: Identifier, - moduleIdentifier: Identifier, counterpartyModuleIdentifier: Identifier, + portIdentifier: Identifier, counterpartyPortIdentifier: Identifier, timeoutHeight: uint64, nextTimeoutHeight: uint64, proofInit: CommitmentProof) { // defined in ICS 4 } ``` -`chanOpenAck` acknowledges a channel creation in progress on another chain, failing if the channel identifier is not found, the proof is invalid, or the calling module is not authorized. +`chanOpenAck` acknowledges a channel creation in progress on another chain, failing if the channel identifier is not found, the proof is invalid, or the calling module is not bound to the port. The default IBC relayer module will allow external calls to `chanOpenAck`. @@ -245,7 +245,7 @@ function chanOpenAck( } ``` -`chanOpenConfirm` finalizes the channel opening handshake, failing if the channel identifier is not found, the proof is invalid, or the calling module is not authorized. +`chanOpenConfirm` finalizes the channel opening handshake, failing if the channel identifier is not found, the proof is invalid, or the calling module is not bound to the port. The default IBC relayer module will allow external calls to `chanOpenConfirm`. @@ -324,9 +324,9 @@ function chanCloseTimeout( ### Packet relay -Packets are permissioned by channel (only a module which owns a channel can send on it). +Packets are permissioned by channel (only a port which owns a channel can send or receive on it). -`sendPacket` attempts to send a packet, returning an error if the packet cannot be sent (perhaps because the sending module does not own the channel in question or because the channel is frozen), and returning a unique identifier if successful. +`sendPacket` attempts to send a packet, returning an error if the packet cannot be sent (perhaps because the sending module is not bound to the port in question or because the channel is frozen), and returning a unique identifier if successful. The returned identifier will be the same as that sent by the timeout handler `timeoutPacket`, so it can be used by the sending module to associate a specific action with a specific packet timeout. @@ -338,7 +338,7 @@ function sendPacket(packet: Packet) { } ``` -`recvPacket` attempts to receive a packet, returning an error if the calling module is not authorized to handle the packet, or if the packet does not exist or has been already handled. +`recvPacket` attempts to receive a packet, returning an error if the calling module is not bound to the associated port, or if the packet does not exist or has been already handled. The default IBC relayer module will allow external calls to `recvPacket`. @@ -348,7 +348,7 @@ function recvPacket(packet: Packet, proof: CommitmentProof) { } ``` -`timeoutPacket` attemps to handle a packet timeout, returning an error if the calling module is not authorized to handle the packet timeout, or if the packet does not exist, has not timed out, or has already been handled. +`timeoutPacket` attemps to handle a packet timeout, returning an error if the calling module is not bound to the associated port, or if the packet does not exist, has not timed out, or has already been handled. The default IBC relayer module will allow external calls to `timeoutPacket`. diff --git a/spec/ics-026-relayer-module/README.md b/spec/ics-026-relayer-module/README.md index 92344a95ced1..8bc8ba781f68 100644 --- a/spec/ics-026-relayer-module/README.md +++ b/spec/ics-026-relayer-module/README.md @@ -15,7 +15,7 @@ The relayer module can keep a lookup table of modules, which it can use to look ### Motivation -The default IBC handler uses a receiver call pattern, where modules must individually call the IBC handler in order to start handshakes, accept handshakes, send and receive packets, etc. This is flexible and simple (see [Design Patterns](../../ibc/5_IBC_DESIGN_PATTERNS.md)) +The default IBC handler uses a receiver call pattern, where modules must individually call the IBC handler in order to bind to ports, start handshakes, accept handshakes, send and receive packets, etc. This is flexible and simple (see [Design Patterns](../../ibc/5_IBC_DESIGN_PATTERNS.md)) but is a bit tricky to understand and may require extra work on the part of relayer processes, who must track the state of many modules. This standard describes an IBC "relayer module" to automate most common functionality, route packets, and simplify the task of relayers. ### Definitions @@ -24,7 +24,7 @@ All functions provided by the IBC handler interface are defined as in [ICS 25](. ### Desired Properties -- Modules should be able to own channels through the relayer module. +- Modules should be able to bind to ports and own channels through the relayer module. - No overhead should be added for packet sends and receives other than the layer of call indirection. ## Technical Specification @@ -125,7 +125,7 @@ interface ChanOpenInit { connectionIdentifier: Identifier channelIdentifier: Identifier counterpartyChannelIdentifier: Identifier - counterpartyModuleIdentifier: Identifier + counterpartyPortIdentifier: Identifier nextTimeoutHeight: uint64 } ``` @@ -135,8 +135,8 @@ interface ChanOpenTry { connectionIdentifier: Identifier channelIdentifier: Identifier counterpartyChannelIdentifier: Identifier - moduleIdentifier: Identifier - counterpartyModuleIdentifier: Identifier + portIdentifier: Identifier + counterpartyPortIdentifier: Identifier timeoutHeight: uint64 nextTimeoutHeight: uint64 proofInit: CommitmentProof