forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge PR cosmos#121: Unification & cleanup
- Loading branch information
Showing
7 changed files
with
173 additions
and
117 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
# Possibly Relevant Research | ||
|
||
## Multi-chain routing & state transition atomicity | ||
|
||
- [Anonymous Multi-Hop Locks for Blockchain Scalability and Interoperability](https://eprint.iacr.org/2018/472.pdf) - analyzes the lightning network, but possibly relevant. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,16 +3,8 @@ ics: 3 | |
title: Connection Semantics | ||
stage: draft | ||
category: ibc-core | ||
<<<<<<< HEAD | ||
requires: 23, 24 | ||
required-by: 25 | ||
======= | ||
requires: 2, 23, 24 | ||
<<<<<<< HEAD:spec/ics-3-connection-semantics/README.md | ||
>>>>>>> master | ||
======= | ||
required-by: 4 | ||
>>>>>>> master:spec/ics-003-connection-semantics/README.md | ||
required-by: 4, 25 | ||
author: Christopher Goes <[email protected]>, Juwoon Yun <[email protected]> | ||
created: 2019-03-07 | ||
modified: 2019-05-17 | ||
|
@@ -72,7 +64,7 @@ Once a negotiation handshake has completed: | |
|
||
### Data Structures | ||
|
||
This ICS defines the `Connection` type: | ||
This ICS defines the `ConnectionState` and `ConnectionEnd` types: | ||
|
||
```typescript | ||
enum ConnectionState { | ||
|
@@ -85,15 +77,25 @@ enum ConnectionState { | |
``` | ||
|
||
```typescript | ||
interface Connection { | ||
interface ConnectionEnd { | ||
state: ConnectionState | ||
counterpartyIdentifier: Identifier | ||
counterpartyConnectionIdentifier: Identifier | ||
clientIdentifier: Identifier | ||
counterpartyClientIdentifier: Identifier | ||
nextTimeoutHeight: uint64 | ||
} | ||
``` | ||
|
||
### Store keys | ||
|
||
Connection keys are stored under a unique identifier. | ||
|
||
```typescript | ||
function connectionKey(id: Identifier): Key { | ||
return "connections/{id}" | ||
} | ||
``` | ||
|
||
### Subprotocols | ||
|
||
This ICS defines two subprotocols: opening handshake and closing handshake. Header tracking and closing-by-equivocation are defined in [ICS 2](../ics-002-consensus-verification). Datagrams defined herein are handled as external messages by the IBC relayer module defined in [ICS 26](../ics-026-relayer-module). | ||
|
@@ -125,36 +127,38 @@ This subprotocol need not be permissioned, modulo anti-spam measures. | |
|
||
```typescript | ||
function connOpenInit( | ||
identifier: Identifier, desiredCounterpartyIdentifier: Identifier, | ||
identifier: Identifier, desiredCounterpartyConnectionIdentifier: Identifier, | ||
clientIdentifier: Identifier, counterpartyClientIdentifier: Identifier, nextTimeoutHeight: uint64) { | ||
assert(get("connections/{identifier}") == null) | ||
assert(get(connectionKey(identifier)) == null) | ||
state = INIT | ||
connection = Connection{state, desiredCounterpartyIdentifier, clientIdentifier, | ||
connection = ConnectionEnd{state, desiredCounterpartyConnectionIdentifier, clientIdentifier, | ||
counterpartyClientIdentifier, nextTimeoutHeight} | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
|
||
*ConnOpenTry* relays notice of a connection attempt on chain A to chain B. | ||
|
||
```typescript | ||
function connOpenTry( | ||
desiredIdentifier: Identifier, counterpartyIdentifier: Identifier, | ||
desiredIdentifier: Identifier, counterpartyConnectionIdentifier: Identifier, | ||
counterpartyClientIdentifier: Identifier, clientIdentifier: Identifier, | ||
proofInit: CommitmentProof, timeoutHeight: uint64, nextTimeoutHeight: uint64) { | ||
assert(getConsensusState().getHeight() <= timeoutHeight) | ||
consensusState = get("clients/{clientIdentifier}") | ||
consensusState = get(consensusStateKey(clientIdentifier)) | ||
expectedConsensusState = getConsensusState() | ||
expected = Connection{INIT, desiredIdentifier, counterpartyClientIdentifier, clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState.getRoot(), proofInit, "connections/{counterpartyIdentifier}", expected)) | ||
expected = ConnectionEnd{INIT, desiredIdentifier, counterpartyClientIdentifier, clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState.getRoot(), proofInit, | ||
connectionKey(counterpartyConnectionIdentifier), expected)) | ||
assert(verifyMembership(consensusState.getRoot(), proofInit, | ||
"clients/{counterpartyClientIdentifier}", expectedConsensusState)) | ||
assert(get("connections/{desiredIdentifier}") === null) | ||
consensusStateKey(counterpartyClientIdentifier), | ||
expectedConsensusState)) | ||
assert(get(connectionKey(desiredIdentifier)) === null) | ||
identifier = desiredIdentifier | ||
state = TRYOPEN | ||
connection = Connection{state, counterpartyIdentifier, clientIdentifier, | ||
counterpartyClientIdentifier, nextTimeoutHeight} | ||
set("connections/{identifier}", connection) | ||
connection = ConnectionEnd{state, counterpartyConnectionIdentifier, clientIdentifier, | ||
counterpartyClientIdentifier, nextTimeoutHeight} | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
|
||
|
@@ -165,18 +169,19 @@ function connOpenAck( | |
identifier: Identifier, proofTry: CommitmentProof, | ||
timeoutHeight: uint64, nextTimeoutHeight: uint64) { | ||
assert(getConsensusState().getHeight() <= timeoutHeight) | ||
connection = get("connections/{identifier}") | ||
connection = get(connectionKey(identifier)) | ||
assert(connection.state === INIT) | ||
consensusState = get("clients/{connection.clientIdentifier}") | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
expectedConsensusState = getConsensusState() | ||
expected = Connection{TRYOPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofTry, "connections/{connection.counterpartyIdentifier}", expected)) | ||
expected = ConnectionEnd{TRYOPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofTry, | ||
connectionKey(connection.counterpartyConnectionIdentifier), expected)) | ||
assert(verifyMembership(consensusState, proofTry, | ||
"clients/{connection.counterpartyClientIdentifier}", expectedConsensusState)) | ||
consensusStateKey(connection.counterpartyClientIdentifier), expectedConsensusState)) | ||
connection.state = OPEN | ||
connection.nextTimeoutHeight = nextTimeoutHeight | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
|
||
|
@@ -185,52 +190,53 @@ function connOpenAck( | |
```typescript | ||
function connOpenConfirm(identifier: Identifier, proofAck: CommitmentProof, timeoutHeight: uint64) | ||
assert(getConsensusState().getHeight() <= timeoutHeight) | ||
connection = get("connections/{identifier}") | ||
connection = get(connectionKey(identifier)) | ||
assert(connection.state === TRYOPEN) | ||
consensusState = get("clients/{connection.clientIdentifier}") | ||
expected = Connection{OPEN, identifier, connection.counterpartyClientIdentifier, | ||
Gconnection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofAck, "connections/{connection.counterpartyIdentifier}", expected)) | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
expected = ConnectionEnd{OPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofAck, | ||
connectionKey(connection.counterpartyConnectionIdentifier), expected)) | ||
connection.state = OPEN | ||
connection.nextTimeoutHeight = 0 | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
``` | ||
*ConnOpenTimeout* aborts a connection opening attempt due to a timeout on the other side. | ||
```typescript | ||
function connOpenTimeout(identifier: Identifier, proofTimeout: CommitmentProof, timeoutHeight: uint64) { | ||
connection = get("connections/{identifier}") | ||
consensusState = get("clients/{connection.clientIdentifier}") | ||
connection = get(connectionKey(identifier)) | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
assert(consensusState.getHeight() > connection.nextTimeoutHeight) | ||
switch state { | ||
case INIT: | ||
assert(verifyNonMembership( | ||
consensusState, proofTimeout, | ||
"connections/{connection.counterpartyIdentifier}")) | ||
connectionKey(connection.counterpartyConnectionIdentifier))) | ||
case TRYOPEN: | ||
assert( | ||
verifyMembership( | ||
consensusState, proofTimeout, | ||
"connections/{connection.counterpartyIdentifier}", | ||
Connection{INIT, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
connectionKey(connection.counterpartyConnectionIdentifier), | ||
ConnectionEnd{INIT, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
) | ||
|| | ||
verifyNonMembership( | ||
consensusState, proofTimeout, | ||
"connections/{connection.counterpartyIdentifier}" | ||
connectionKey(connection.counterpartyConnectionIdentifier) | ||
) | ||
) | ||
case OPEN: | ||
assert(verifyMembership( | ||
consensusState, proofTimeout, | ||
"connections/{connection.counterpartyIdentifier}", | ||
Connection{TRYOPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
connectionKey(connection.counterpartyConnectionIdentifier), | ||
ConnectionEnd{TRYOPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
)) | ||
} | ||
delete("connections/{identifier}") | ||
delete(connectionKey(identifier)) | ||
} | ||
``` | ||
|
@@ -258,11 +264,11 @@ A correct protocol execution flows as follows (note that all calls are made thro | |
```typescript | ||
function connCloseInit(identifier: Identifier, nextTimeoutHeight: uint64) { | ||
connection = get("connections/{identifier}") | ||
connection = get(connectionKey(identifier)) | ||
assert(connection.state === OPEN) | ||
connection.state = CLOSETRY | ||
connection.nextTimeoutHeight = nextTimeoutHeight | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
|
@@ -273,15 +279,15 @@ function connCloseTry( | |
identifier: Identifier, proofInit: CommitmentProof, | ||
timeoutHeight: uint64, nextTimeoutHeight: uint64) { | ||
assert(getConsensusState().getHeight() <= timeoutHeight) | ||
connection = get("connections/{identifier}") | ||
connection = get(connectionKey(identifier)) | ||
assert(connection.state === OPEN) | ||
consensusState = get("clients/{connection.clientIdentifier}") | ||
expected = Connection{CLOSETRY, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofInit, "connections/{counterpartyIdentifier}", expected)) | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
expected = ConnectionEnd{CLOSETRY, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofInit, connectionKey(counterpartyConnectionIdentifier), expected)) | ||
connection.state = CLOSED | ||
connection.nextTimeoutHeight = nextTimeoutHeight | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
|
@@ -290,46 +296,46 @@ function connCloseTry( | |
```typescript | ||
function connCloseAck(identifier: Identifier, proofTry: CommitmentProof, timeoutHeight: uint64) { | ||
assert(getConsensusState().getHeight() <= timeoutHeight) | ||
connection = get("connections/{identifier}") | ||
connection = get(connectionKey(identifier)) | ||
assert(connection.state === CLOSETRY) | ||
consensusState = get("clients/{connection.clientIdentifier}") | ||
expected = Connection{CLOSED, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofTry, "connections/{counterpartyIdentifier}", expected)) | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
expected = ConnectionEnd{CLOSED, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership(consensusState, proofTry, connectionKey(counterpartyConnectionIdentifier), expected)) | ||
connection.state = CLOSED | ||
connection.nextTimeoutHeight = 0 | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
``` | ||
*ConnCloseTimeout* aborts a connection closing attempt due to a timeout on the other side and reopens the connection. | ||
```typescript | ||
function connCloseTimeout(identifier: Identifier, proofTimeout: CommitmentProof, timeoutHeight: uint64) { | ||
connection = get("connections/{identifier}") | ||
consensusState = get("clients/{connection/clientIdentifier}") | ||
connection = get(connectionKey(identifier)) | ||
consensusState = get(consensusStateKey(connection.clientIdentifier)) | ||
assert(consensusState.getHeight() > connection.nextTimeoutHeight) | ||
switch state { | ||
case CLOSETRY: | ||
expected = Connection{OPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
expected = ConnectionEnd{OPEN, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership( | ||
consensusState, proofTimeout, | ||
"connections/{counterpartyIdentifier}", expected | ||
connectionKey(counterpartyConnectionIdentifier), expected | ||
)) | ||
connection.state = OPEN | ||
connection.nextTimeoutHeight = 0 | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
case CLOSED: | ||
expected = Connection{CLOSETRY, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
expected = ConnectionEnd{CLOSETRY, identifier, connection.counterpartyClientIdentifier, | ||
connection.clientIdentifier, timeoutHeight} | ||
assert(verifyMembership( | ||
consensusState, proofTimeout, | ||
"connections/{counterpartyIdentifier}", expected | ||
connectionKey(counterpartyConnectionIdentifier), expected | ||
)) | ||
connection.state = OPEN | ||
connection.nextTimeoutHeight = 0 | ||
set("connections/{identifier}", connection) | ||
set(connectionKey(identifier), connection) | ||
} | ||
} | ||
``` | ||
|
@@ -340,6 +346,16 @@ The equivocation detection subprotocol is defined in [ICS 2](../ics-002-consensu | |
Implementing chains may want to allow applications to register handlers to take action upon discovery of an equivocation. Further discussion is deferred to ICS 12. | ||
#### Querying | ||
Connections can be queried by identifier with `queryConnection`. | ||
```typescript | ||
function queryConnection(id: Identifier): ConnectionEnd | void { | ||
return get(connectionKey(id)) | ||
} | ||
``` | ||
## Backwards Compatibility | ||
Not applicable. | ||
|
Oops, something went wrong.