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

Put the path choices in clients instead of spec-wide #293

Merged
merged 9 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
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
15 changes: 12 additions & 3 deletions misc/aspell_dict
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
personal_ws-1.1 en 455
personal_ws-1.1 en 464
unescrow
onChanCloseConfirm
clientKey
Expand Down Expand Up @@ -42,6 +42,7 @@ handleClientFreeze
validRound
recvPacket
duplicable
verifyPacketCommitment
collateralising
OpValidityPredicate
packetCommitmentPath
Expand Down Expand Up @@ -110,13 +111,15 @@ handlePacketTimeout
PacketSend
unescrowing
InitialPubkey
verifyPacketAcknowledgementAbsence
handlePacketRecv
verifiedRoots
coffeescript
proofTry
escrowing
publicKey
tokenize
verifyPacketAcknowledgement
interchain
Ethereum
PacketTimeout
Expand All @@ -136,7 +139,7 @@ pendingDatagrams
len
handlePacketTimeoutClose
startRound
ChannelEnd
channelEnd
timeoutPropose
counterparty
connectionPath
Expand Down Expand Up @@ -244,7 +247,7 @@ nextSequenceSendKey
datatypes
getRoot
Ethereum's
ConnectionEnd
connectionEnd
expectedConsensusState
handleChanOpenInit
YYYY
Expand Down Expand Up @@ -317,6 +320,7 @@ onChanOpenConfirm
counterintuitive
ClientUpdate
ClientFreeze
verifyOutgoingPacket
VMs
ConnectionState
txs
Expand All @@ -337,6 +341,7 @@ channelIdentifier
handleClientCreate
channelSet
ABCI
verifyConnectionState
struct
consensusState
Automatability
Expand Down Expand Up @@ -365,6 +370,7 @@ Multichain
connId
blockchain's
blockchains
Merklized
Nomic
serialisable
chanOpenTry
Expand All @@ -379,6 +385,7 @@ keyspaces
counterpartyStateRoot
JSON
PacketAcknowledgement
verifyClientConsensusState
consensusHeight
createMembershipProof
Yun
Expand All @@ -400,6 +407,7 @@ clientIdentifier
handleChanOpenTry
pickVersion
chanOpenTimeout
verifyNextSequenceRecv
th
unallocated
portIdentifier
Expand All @@ -415,6 +423,7 @@ Strawman
tx
bytestring
validateConnectionIdentifier
verifyChannelState
updatePort
incentivisation
datastream
Expand Down
2 changes: 1 addition & 1 deletion scripts/tslint.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"interface-name": false,
"object-literal-sort-keys": false,
"trailing-comma": false,
"max-line-length": [true, 140]
"max-line-length": [true, 160]
},
"rulesDirectory": []
}
Binary file modified spec.pdf
Binary file not shown.
218 changes: 206 additions & 12 deletions spec/ics-002-client-semantics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -266,9 +266,133 @@ at a particular finalised height (necessarily associated with a particular commi

#### State verification

Client types must define functions, in accordance with [ICS 23](../ics-023-vector-commitments), to verify presence or absence of particular key/value pairs
in state at particular heights. The behaviour of these functions MUST comply with the properties defined in [ICS 23](../ics-023-vector-commitments); however,
internal implementation details may differ (for example, a loopback client could simply read directly from the state and require no proofs).
Client types must define functions to authenticate internal state of the state machine which the client tracks.
Internal implementation details may differ (for example, a loopback client could simply read directly from the state and require no proofs).

##### Required functions

`verifyClientConsensusState` verifies a proof of the consensus state of the specified client stored on the target machine.

```typescript
type verifyClientConsensusState = (
clientState: ClientState,
height: uint64,
proof: CommitmentProof,
clientIdentifier: Identifier,
consensusState: ConsensusState)
=> boolean
```

`verifyConnectionState` verifies a proof of the connection state of the specified connection end stored on the target machine.

```typescript
type verifyConnectionState = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
connectionIdentifier: Identifier,
connectionEnd: ConnectionEnd)
=> boolean
```

`verifyChannelState` verifies a proof of the channel state of the specified channel end, under the specified port, stored on the target machine.

```typescript
type verifyChannelState = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
channelEnd: ChannelEnd)
=> boolean
```

`verifyPacketCommitment` verifies a proof of an outgoing packet commitment at the specified port, specified channel, and specified sequence.

```typescript
type verifyPacketCommitment = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64,
commitment: bytes)
=> boolean
```

`verifyPacketAcknowledgement` verifies a proof of an incoming packet acknowledgement at the specified port, specified channel, and specified sequence.

```typescript
type verifyPacketAcknowledgement = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64,
acknowledgement: bytes)
=> boolean
```

`verifyPacketAcknowledgementAbsence` verifies a proof of the absence of an incoming packet acknowledgement at the specified port, specified channel, and specified sequence.

```typescript
type verifyPacketAcknowledgementAbsence = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64)
=> boolean
```

`verifyNextSequenceRecv` verifies a proof of the next sequence number to be received of the specified channel at the specified port.

```typescript
type verifyNextSequenceRecv = (
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
nextSequenceRecv: uint64)
=> boolean
```

##### Implementation strategies

###### Loopback

A loopback client of a local machine merely reads from the local state, to which it must have access.

###### Simple signatures

A client of a solo machine with a known public key checks signatures on messages sent by that local machine,
which are provided as the `Proof` parameter. The `height` parameter can be used as a replay protection nonce.

Multi-signature or threshold signature schemes can also be used in such a fashion.

###### Proxy clients

Proxy clients verify another (proxy) machine's verification of the target machine, by including in the
proof first a proof of the client state on the proxy machine, and then a secondary proof of the sub-state of
the target machine with respect to the client state on the proxy machine. This allows the proxy client to
avoid storing and tracking the consensus state of the target machine itself, at the cost of adding
security assumptions of proxy machine correctness.

###### Merklized state trees

For clients of state machines with Merklized state trees, these functions can be implemented by calling `verifyMembership` or `verifyNonMembership`, using a verified Merkle
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
Expand Down Expand Up @@ -473,27 +597,97 @@ function checkValidityAndUpdateState(
clientState.verifiedRoots[sequence] = header.commitmentRoot
}

// state membership verification function defined by the client type
function verifyMembership(
function verifyClientConsensusState(
clientState: ClientState,
sequence: uint64,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
clientIdentifier: Identifier,
consensusState: ConsensusState) {
path = applyPrefix(prefix, "clients/{clientIdentifier}/consensusState")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, consensusState, proof)
}

function verifyConnectionState(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
path: Path,
value: Value) {
connectionIdentifier: Identifier,
connectionEnd: ConnectionEnd) {
path = applyPrefix(prefix, "connection/{connectionIdentifier}")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, value, proof)
return clientState.verifiedRoots[sequence].verifyMembership(path, connectionEnd, proof)
}

// state non-membership function defined by the client type
function verifyNonMembership(
function verifyChannelState(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
channelEnd: ChannelEnd) {
path = applyPrefix(prefix, "ports/{portIdentifier}/channels/{channelIdentifier}")
Copy link

@fedekunze fedekunze Nov 21, 2019

Choose a reason for hiding this comment

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

question: why do we want to expose the paths hardcoded on the client? do we expect ICS02 to be customized? Why not pass the path param directly instead of the prefix?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are example implementations, not necessarily required.

They will vary per client type. See #286

abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, channelEnd, proof)
}

function verifyPacketCommitment(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64,
commitment: bytes) {
path = applyPrefix(prefix, "ports/{portIdentifier}/channels/{channelIdentifier}/packets/{sequence}")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, commitment, proof)
}

function verifyPacketAcknowledgement(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64,
acknowledgement: bytes) {
path = applyPrefix(prefix, "ports/{portIdentifier}/channels/{channelIdentifier}/acknowledgements/{sequence}")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, acknowledgement, proof)
}

function verifyPacketAcknowledgementAbsence(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
path: Path) {
portIdentifier: Identifier,
channelIdentifier: Identifier,
sequence: uint64) {
path = applyPrefix(prefix, "ports/{portIdentifier}/channels/{channelIdentifier}/acknowledgements/{sequence}")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyNonMembership(path, proof)
}

function verifyNextSequenceRecv(
clientState: ClientState,
height: uint64,
prefix: CommitmentPrefix,
proof: CommitmentProof,
portIdentifier: Identifier,
channelIdentifier: Identifier,
nextSequenceRecv: uint64) {
path = applyPrefix(prefix, "ports/{portIdentifier}/channels/{channelIdentifier}/nextSequenceRecv")
abortTransactionUnless(!clientState.frozen)
return clientState.verifiedRoots[sequence].verifyMembership(path, nextSequenceRecv, proof)
}

// misbehaviour verification function defined by the client type
// any duplicate signature by a past or current key freezes the client
function checkMisbehaviourAndUpdateState(
Expand Down
Loading