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

Abstract height type #447

Merged
merged 11 commits into from
Jul 21, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
Binary file modified spec.pdf
Binary file not shown.
78 changes: 55 additions & 23 deletions spec/ics-002-client-semantics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,27 @@ Once misbehaviour is detected, clients SHOULD be frozen so that no future update
A permissioned entity such as a chain governance system or trusted multi-signature MAY be allowed
to intervene to unfreeze a frozen client & provide a new correct header.

#### Height

`Height` is an opaque data structure defined by a client type.
It must form a partially ordered set & provide operations for comparison.

```typescript
type Height
```

```typescript
enum Ord {

Choose a reason for hiding this comment

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

can we rename it to Cmp instead? it's more widely used by various libraries in Go (eg big.Int)

Choose a reason for hiding this comment

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

actually, I think Cmp should be a function from Height

func (h Height) Cmp(b Height): int {
  if h.epochNumber < b.epochNumber {
    return -1
  } else if h.epochNumber == b.epochNumber {
    if a.epochHeight < b.epochHeight {
      return -1
    } else if h.epochHeight == b.epochHeight {
      return 0
    }
  }
  return 1
}

something in those lines

Choose a reason for hiding this comment

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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, I'm not a huge fan of returning an int since there are more valid values for int than valid return values for this function. It's fine if we use Cmp to implement this in the Cosmos SDK code, though.

LT
EQ
GT
}

type compare = (height: Height) => Ord
```

A height is either `LT` (less than), `EQ` (equal to), or `GT` (greater than) another height.

#### ClientState

`ClientState` is an opaque data structure defined by a client type.
Expand All @@ -279,7 +300,7 @@ Client types MUST define a method to fetch the current height (height of the mos
```typescript
type latestClientHeight = (
clientState: ClientState)
=> uint64
=> Height
```

#### CommitmentProof
Expand All @@ -300,10 +321,10 @@ Internal implementation details may differ (for example, a loopback client could
```typescript
type verifyClientConsensusState = (
clientState: ClientState,
height: uint64,
height: Height,
proof: CommitmentProof,
clientIdentifier: Identifier,
consensusStateHeight: uint64,
consensusStateHeight: Height,
consensusState: ConsensusState)
=> boolean
```
Expand All @@ -313,7 +334,7 @@ type verifyClientConsensusState = (
```typescript
type verifyConnectionState = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
connectionIdentifier: Identifier,
Expand All @@ -326,7 +347,7 @@ type verifyConnectionState = (
```typescript
type verifyChannelState = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
Expand All @@ -340,7 +361,7 @@ type verifyChannelState = (
```typescript
type verifyPacketData = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
Expand All @@ -355,7 +376,7 @@ type verifyPacketData = (
```typescript
type verifyPacketAcknowledgement = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
Expand All @@ -370,7 +391,7 @@ type verifyPacketAcknowledgement = (
```typescript
type verifyPacketAcknowledgementAbsence = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
Expand All @@ -384,7 +405,7 @@ type verifyPacketAcknowledgementAbsence = (
```typescript
type verifyNextSequenceRecv = (
clientState: ClientState,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
Expand All @@ -402,15 +423,15 @@ These query endpoints are assumed to be exposed over HTTP or an equivalent RPC A
`queryHeader` MUST be defined by the chain which is validated by a particular client, and should allow for retrieval of headers by height. This endpoint is assumed to be untrusted.

```typescript
type queryHeader = (height: uint64) => Header
type queryHeader = (height: Height) => Header
```

`queryChainConsensusState` MAY be defined by the chain which is validated by a particular client, to allow for the retrieval of the current consensus state which can be used to construct a new client.
When used in this fashion, the returned `ConsensusState` MUST be manually confirmed by the querying entity, since it is subjective. This endpoint is assumed to be untrusted. The precise nature of the
`ConsensusState` may vary per client type.

```typescript
type queryChainConsensusState = (height: uint64) => ConsensusState
type queryChainConsensusState = (height: Height) => ConsensusState
```

Note that retrieval of past consensus states by height (as opposed to just the current consensus state) is convenient but not required.
Expand All @@ -430,7 +451,7 @@ function queryClientState(identifier: Identifier): ClientState {
The `ClientState` type SHOULD expose its latest verified height (from which the consensus state can then be retrieved using `queryConsensusState` if desired).

```typescript
type latestHeight = (state: ClientState) => uint64
type latestHeight = (state: ClientState) => Height
```

Client types SHOULD define the following standardised query functions in order to allow relayers & other off-chain entities to interface with on-chain state in a standard API.
Expand All @@ -440,7 +461,7 @@ Client types SHOULD define the following standardised query functions in order t
```typescript
type queryConsensusState = (
identifier: Identifier,
height: uint64
height: Height,
) => ConsensusState
```

Expand All @@ -453,46 +474,46 @@ These functions may constitute external queries over RPC to a full node as well
```typescript
type queryAndProveClientConsensusState = (
clientIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
consensusStateHeight: uint64) => ConsensusState, Proof
consensusStateHeight: Height) => ConsensusState, Proof

type queryAndProveConnectionState = (
connectionIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix) => ConnectionEnd, Proof

type queryAndProveChannelState = (
portIdentifier: Identifier,
channelIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix) => ChannelEnd, Proof

type queryAndProvePacketData = (
portIdentifier: Identifier,
channelIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
sequence: uint64) => []byte, Proof

type queryAndProvePacketAcknowledgement = (
portIdentifier: Identifier,
channelIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
sequence: uint64) => []byte, Proof

type queryAndProvePacketAcknowledgementAbsence = (
portIdentifier: Identifier,
channelIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix,
sequence: uint64) => Proof

type queryAndProveNextSequenceRecv = (
portIdentifier: Identifier,
channelIdentifier: Identifier,
height: uint64,
height: Height,
prefix: CommitmentPrefix) => uint64, Proof
```

Expand Down Expand Up @@ -523,11 +544,11 @@ For clients of state machines with Merklized state trees, these functions can be
root stored in the `ClientState`, to verify presence or absence of particular key/value pairs in state at particular heights in accordance with [ICS 23](../ics-023-vector-commitments).

```typescript
type verifyMembership = (ClientState, uint64, CommitmentProof, Path, Value) => boolean
type verifyMembership = (ClientState, Height, CommitmentProof, Path, Value) => boolean
```

```typescript
type verifyNonMembership = (ClientState, uint64, CommitmentProof, Path) => boolean
type verifyNonMembership = (ClientState, Height, CommitmentProof, Path) => boolean
```

### Sub-protocols
Expand Down Expand Up @@ -637,6 +658,17 @@ The client-specific types are then defined as follows:
- `checkMisbehaviourAndUpdateState` checks for two headers with the same height & different commitment roots, then mutates the internal state

```typescript
type Height = uint64

function compare(h1: Height, h2: Height): Ord {
if h1 < h2
return LT
else if h1 === h2
return EQ
else
return GT
}

interface ClientState {
frozen: boolean
pastPublicKeys: Set<PublicKey>
Expand Down