From baf074e7a64599e53cb1f4d7dcd8b9771d2aad73 Mon Sep 17 00:00:00 2001 From: Bo Du Date: Thu, 9 Mar 2023 02:18:39 -0500 Subject: [PATCH 1/5] feat: extend 02-client --- spec/core/ics-002-client-semantics/README.md | 109 +++++++++++++++++-- 1 file changed, 99 insertions(+), 10 deletions(-) diff --git a/spec/core/ics-002-client-semantics/README.md b/spec/core/ics-002-client-semantics/README.md index 6104da8da..622006906 100644 --- a/spec/core/ics-002-client-semantics/README.md +++ b/spec/core/ics-002-client-semantics/README.md @@ -8,7 +8,7 @@ requires: 23, 24 required-by: 3 author: Juwoon Yun , Christopher Goes , Aditya Sripal created: 2019-02-25 -modified: 2022-08-04 +modified: 2023-03-07 --- ## Synopsis @@ -29,7 +29,8 @@ many processes operating a Byzantine fault-tolerant consensus algorithm (e.g., T This standard also specifies how the light client's functionality is registered and how its data is stored and updated by the IBC protocol. The stored client instances can be introspected by a third party actor, -such as a user inspecting the state of the state machine and deciding whether or not to send an IBC packet. +such as a user inspecting the state of the state machine and deciding whether or not to send an IBC packet. +Client instances can also express read-only dependencies on existing client instances. These are called conditional light clients. ### Motivation @@ -67,6 +68,22 @@ appropriate gas metering mechanism to charge for compute and storage. On a host which supports WASM execution, for example, the validity predicate and misbehaviour predicate could be provided as executable WASM functions when the client instance is created. +Conditional clients can express dependencies on existing client instances. The idea is here is that modular blockchains change +the way a logical blockchain can be expressed. Since a logical blockchain can be broken up into its constituent parts, +a single client can become multiple clients. This results in greater state layer diversity for IBC. + +For example, we could have a different client for each of the following functional layers of the blockchain stack: +* Data availability +* Sequencing or transaction ordering +* Execution + * Settlement + +Clients may also represent other things further contributing to state layer diversity: +* Security provider (e.g. checkpointing on BTC) +* Attestation (e.g. fraud prover attestations) +* Permissioned relay (e.g. bring your own relayer) + + ### Definitions * `get`, `set`, `Path`, and `Identifier` are as defined in [ICS 24](../ics-024-host-requirements). @@ -131,16 +148,23 @@ types may require additional properties. Light clients MUST provide state verification functions that provide a secure way to verify the state of the remote state machines using the existing `ConsensusState`s. These state verification functions enable higher-level protocol abstractions to -verify sub-components of the state of the remote state machines. +verify sub-components of the state of the remote state machines. The behaviour of the following +depending on whether the counterparty is a monolithic or modular blockchain. -`ValidityPredicate`s MUST reflect the behaviour of the remote state machine and its `Consensus`, i.e., -`ValidityPredicate`s accept *only* state updates that contain state updates generated by -the `Consensus` of the remote state machine. +In the monolithic case, `ValidityPredicate`s MUST reflect the behaviour of the remote state machine +and its `Consensus`, i.e., `ValidityPredicate`s accept *only* state updates that contain state updates +generated by the `Consensus` of the remote state machine. In case of misbehavior, the behaviour of the `ValidityPredicate` might differ from the behaviour of the remote state machine and its `Consensus` (since clients do not execute the `Consensus` of the remote state machine). In this case, a `Misbehaviour` SHOULD be submitted to the host state machine, -which would result in the client being frozen and higher-level intervention being necessary. +which would result in the client being frozen and higher-level intervention being necessary. +Additionally, a slashable bond may be assigned to a client for economic security. + + +In the modular case, `ValidityPredicate` MUST reflect the behaviour of the remote logical blockchain where +the logical chain can be split up into multiple parts. For each logical part, different types of proofs can be accepted +to prove the execution of that part. ## Technical Specification @@ -318,6 +342,16 @@ 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 ClientMessage which updates the client to a valid state. +Optionally, if there exists a bond assigned to this client, the client may include slashing logic to incentivize both reporting +of good behaviour and reporting of misbehaviour. This mechanism can also be used in connecting optimistic rollups where you can +have an attester bond some economic stake in order to secure lower latency client updates. + +The client bond address are based on cosmos SDK [ADR-028](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-028-public-key-addresses.md). + +```typescript +address.Module(moduleName, subModuleName, clientID, "bonded_tokens_pool") +``` + #### `CommitmentProof` `CommitmentProof` is an opaque data structure defined by a client type in accordance with [ICS 23](../ics-023-vector-commitments). @@ -504,6 +538,19 @@ type verifyMembership = (ClientState, Height, CommitmentProof, Path, Value) => b type verifyNonMembership = (ClientState, Height, CommitmentProof, Path) => boolean ``` +###### Modular blockchain clients + +Clients for modular blockchains will have client depdencies on other clients. Splitting out data availability, +sequencing and execution into different chains gets us the following dependency relationship: + +``` +Execution -> sequencing -> data availability +``` + +For example, when connecting to an optimistic rollup on top of a shared sequencer and a common DA layer we do the following: +* Verify that a sequenced block is available on the DA network to start fraud window +* Wait until fraud window has passed before accepting the optimstic block + ### Sub-protocols IBC handlers MUST implement the functions defined below. @@ -536,12 +583,13 @@ Calling `createClient` with the client type and initial consensus state creates ```typescript function createClient( clientType: ClientType, - consensusState: ConsensusState) { + consensusState: ConsensusState, + clientDependencies: []Identifier) { // implementations may define a identifier generation function identifier = generateClientIdentifier() abortTransactionUnless(provableStore.get(clientStatePath(identifier)) === null) abortSystemUnless(provableStore.get(clientTypePath(identifier)) === null) - clientType.initialise(identifier, consensusState) + clientType.initialise(identifier, consensusState, clientDependencies) provableStore.set(clientTypePath(identifier), clientType) } ``` @@ -576,7 +624,13 @@ function updateClient( clientState = provableStore.get(clientStatePath(id)) abortTransactionUnless(clientState !== null) - clientState.VerifyClientMessage(clientMessage) + // get client dependencies (conditional client) + dependencies = [] + for (const clientID of clientState.clientDependencies) { + dependencies.push(provableStore.get(clientStatePath(clientID))) + } + + clientState.VerifyClientMessage(clientMessage, dependencies) foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage) if foundMisbehaviour { @@ -607,6 +661,39 @@ function submitMisbehaviourToClient( abortTransactionUnless(clientState.checkForMisbehaviour(clientMessage)) // update state based on misbehaviour clientState.UpdateStateOnMisbehaviour(misbehaviour) + // slash bond if any + bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") + bank.iterateAccountBalances(bondAddress, (token: Coin) { + // slashed bond is paid out to the misbehaviour reporter + bank.sendCoinsFromModuleToAccount(bondAddress, misbehaviour.payee, token) + }) + clear(bonded) +} +``` + +#### Bonding + +A slashable bond may be placed on a client to economically guarantee correct behaviour and/or incentivize reporting of misbehaviour. + +```typescript +function bondToken( + id: Identifier, + sender: string, + token: Coin) { + bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") + bank.sendCoinsFromAccountToModule(sender, bondAddress, token) + bonded[sender][token.denom] = bonded[sender][token.denom].add(token) +} + +function unbondToken( + id: Identifier, + receiver: string, + token: Coin) { + if (bonded[receiver][token.denom].isGTE(token) { + bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") + bank.sendCoinsFromModuleToAccount(bondAddress, receiver, token) + bonded[receiver][token.denom] = bonded[receiver][token.denom].sub(token) + } } ``` @@ -646,6 +733,8 @@ Jul 27, 2022 - Addition of `verifyClientState` function, and move `ClientState` August 4, 2022 - Changes to ClientState interface and associated handler to align with changes in 02-client-refactor ADR: https://github.com/cosmos/ibc-go/pull/1871 +March 9, 2023 - Adds conditional clients and bonding + ## Copyright All content herein is licensed under [Apache 2.0](https://www.apache.org/licenses/LICENSE-2.0). From d9f38149a7b2371f477282ef75ed8281af478ade Mon Sep 17 00:00:00 2001 From: Bo Du Date: Thu, 9 Mar 2023 02:20:57 -0500 Subject: [PATCH 2/5] chore: update date --- spec/core/ics-002-client-semantics/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/core/ics-002-client-semantics/README.md b/spec/core/ics-002-client-semantics/README.md index 622006906..ff77d69ed 100644 --- a/spec/core/ics-002-client-semantics/README.md +++ b/spec/core/ics-002-client-semantics/README.md @@ -8,7 +8,7 @@ requires: 23, 24 required-by: 3 author: Juwoon Yun , Christopher Goes , Aditya Sripal created: 2019-02-25 -modified: 2023-03-07 +modified: 2023-03-09 --- ## Synopsis From 292383a09b231bd039ef7b430407c973a84f198e Mon Sep 17 00:00:00 2001 From: Bo Du Date: Fri, 31 Mar 2023 07:21:37 -0400 Subject: [PATCH 3/5] feat: + deps to client state & remove bonding --- spec/core/ics-002-client-semantics/README.md | 103 ++++++++++--------- 1 file changed, 54 insertions(+), 49 deletions(-) diff --git a/spec/core/ics-002-client-semantics/README.md b/spec/core/ics-002-client-semantics/README.md index ff77d69ed..a41facdfc 100644 --- a/spec/core/ics-002-client-semantics/README.md +++ b/spec/core/ics-002-client-semantics/README.md @@ -8,7 +8,7 @@ requires: 23, 24 required-by: 3 author: Juwoon Yun , Christopher Goes , Aditya Sripal created: 2019-02-25 -modified: 2023-03-09 +modified: 2023-03-31 --- ## Synopsis @@ -159,7 +159,6 @@ In case of misbehavior, the behaviour of the `ValidityPredicate` might differ fr the remote state machine and its `Consensus` (since clients do not execute the `Consensus` of the remote state machine). In this case, a `Misbehaviour` SHOULD be submitted to the host state machine, which would result in the client being frozen and higher-level intervention being necessary. -Additionally, a slashable bond may be assigned to a client for economic security. In the modular case, `ValidityPredicate` MUST reflect the behaviour of the remote logical blockchain where @@ -268,6 +267,48 @@ type getTimestampAtHeight = ( ) => uint64 ``` +Client types MUST define methods to verify membership and non membership proofs. + +```typescript +type verifyMembership = ( + height: Height, + delayTimePeriod: uint64, + delayBlockPeriod: uint64, + proof: []byte, + path: []byte, + value: []byte, +) => error + +type verifyNonMembership = ( + height: Height, + delayTimePeriod: uint64, + delayBlockPeriod: uint64, + proof: []byte, + path: []byte, +) => error +``` + +Client types MUST define methods to handle client messages for managing state. + +``` +type verifyClientMessage(clientMsg: ClientMessage) => error + +type checkForMisbehaviour(clientMsg: ClientMessage) => bool + +type updateStateOnMisbehaviour(clientMsg: ClientMessage) + +type updateState(clientMsg: ClientMessage) => []Height +``` + +Client types MAY define a list of client dependencies on existing clients. + +``` +type clientDependencies() => []Identifier +``` + +Client types MUST define methods to handle client messages for managing state. + + #### `ClientMessage` A `ClientMessage` is an opaque data structure defined by a client type which provides information to update the client. @@ -342,16 +383,6 @@ 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 ClientMessage which updates the client to a valid state. -Optionally, if there exists a bond assigned to this client, the client may include slashing logic to incentivize both reporting -of good behaviour and reporting of misbehaviour. This mechanism can also be used in connecting optimistic rollups where you can -have an attester bond some economic stake in order to secure lower latency client updates. - -The client bond address are based on cosmos SDK [ADR-028](https://github.com/cosmos/cosmos-sdk/blob/main/docs/architecture/adr-028-public-key-addresses.md). - -```typescript -address.Module(moduleName, subModuleName, clientID, "bonded_tokens_pool") -``` - #### `CommitmentProof` `CommitmentProof` is an opaque data structure defined by a client type in accordance with [ICS 23](../ics-023-vector-commitments). @@ -582,7 +613,7 @@ Calling `createClient` with the client type and initial consensus state creates ```typescript function createClient( - clientType: ClientType, + clientState: ClientState, consensusState: ConsensusState, clientDependencies: []Identifier) { // implementations may define a identifier generation function @@ -630,7 +661,7 @@ function updateClient( dependencies.push(provableStore.get(clientStatePath(clientID))) } - clientState.VerifyClientMessage(clientMessage, dependencies) + clientState.verifyClientMessage(clientMessage, dependencies) foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage) if foundMisbehaviour { @@ -655,45 +686,19 @@ function submitMisbehaviourToClient( clientMessage: ClientMessage) { clientState = provableStore.get(clientStatePath(id)) abortTransactionUnless(clientState !== null) + + // get client dependencies (conditional client) + dependencies = [] + for (const clientID of clientState.clientDependencies) { + dependencies.push(provableStore.get(clientStatePath(clientID))) + } + // authenticate client message - clientState.verifyClientMessage(clientMessage) + clientState.verifyClientMessage(clientMessage, dependencies) // check that client message is valid instance of misbehaviour abortTransactionUnless(clientState.checkForMisbehaviour(clientMessage)) // update state based on misbehaviour clientState.UpdateStateOnMisbehaviour(misbehaviour) - // slash bond if any - bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") - bank.iterateAccountBalances(bondAddress, (token: Coin) { - // slashed bond is paid out to the misbehaviour reporter - bank.sendCoinsFromModuleToAccount(bondAddress, misbehaviour.payee, token) - }) - clear(bonded) -} -``` - -#### Bonding - -A slashable bond may be placed on a client to economically guarantee correct behaviour and/or incentivize reporting of misbehaviour. - -```typescript -function bondToken( - id: Identifier, - sender: string, - token: Coin) { - bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") - bank.sendCoinsFromAccountToModule(sender, bondAddress, token) - bonded[sender][token.denom] = bonded[sender][token.denom].add(token) -} - -function unbondToken( - id: Identifier, - receiver: string, - token: Coin) { - if (bonded[receiver][token.denom].isGTE(token) { - bondAddress = address.Module(moduleName, subModuleName, id, "bonded_tokens_pool") - bank.sendCoinsFromModuleToAccount(bondAddress, receiver, token) - bonded[receiver][token.denom] = bonded[receiver][token.denom].sub(token) - } } ``` @@ -733,7 +738,7 @@ Jul 27, 2022 - Addition of `verifyClientState` function, and move `ClientState` August 4, 2022 - Changes to ClientState interface and associated handler to align with changes in 02-client-refactor ADR: https://github.com/cosmos/ibc-go/pull/1871 -March 9, 2023 - Adds conditional clients and bonding +March 31, 2023 - Adds client dependencies to ClientState and adds ClientState interface methods ## Copyright From 0ba831a56a1b4f038560203d7df58548d344b791 Mon Sep 17 00:00:00 2001 From: Bo Du Date: Fri, 31 Mar 2023 07:28:36 -0400 Subject: [PATCH 4/5] chore: remove dupe line --- spec/core/ics-002-client-semantics/README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/spec/core/ics-002-client-semantics/README.md b/spec/core/ics-002-client-semantics/README.md index a41facdfc..213f04f81 100644 --- a/spec/core/ics-002-client-semantics/README.md +++ b/spec/core/ics-002-client-semantics/README.md @@ -306,9 +306,6 @@ Client types MAY define a list of client dependencies on existing clients. type clientDependencies() => []Identifier ``` -Client types MUST define methods to handle client messages for managing state. - - #### `ClientMessage` A `ClientMessage` is an opaque data structure defined by a client type which provides information to update the client. From cff7bb0bbbc5c1c8f607e153c4986529f3384842 Mon Sep 17 00:00:00 2001 From: Bo Du Date: Fri, 31 Mar 2023 07:43:42 -0400 Subject: [PATCH 5/5] chore: remove dupe line & update createClient --- spec/core/ics-002-client-semantics/README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/spec/core/ics-002-client-semantics/README.md b/spec/core/ics-002-client-semantics/README.md index 213f04f81..bfa6a2fe6 100644 --- a/spec/core/ics-002-client-semantics/README.md +++ b/spec/core/ics-002-client-semantics/README.md @@ -160,7 +160,6 @@ the remote state machine and its `Consensus` (since clients do not execute the ` remote state machine). In this case, a `Misbehaviour` SHOULD be submitted to the host state machine, which would result in the client being frozen and higher-level intervention being necessary. - In the modular case, `ValidityPredicate` MUST reflect the behaviour of the remote logical blockchain where the logical chain can be split up into multiple parts. For each logical part, different types of proofs can be accepted to prove the execution of that part. @@ -611,13 +610,11 @@ Calling `createClient` with the client type and initial consensus state creates ```typescript function createClient( clientState: ClientState, - consensusState: ConsensusState, - clientDependencies: []Identifier) { + consensusState: ConsensusState) { // implementations may define a identifier generation function - identifier = generateClientIdentifier() - abortTransactionUnless(provableStore.get(clientStatePath(identifier)) === null) - abortSystemUnless(provableStore.get(clientTypePath(identifier)) === null) - clientType.initialise(identifier, consensusState, clientDependencies) + // an auto incrementing counter in the identifier avoids naming conflicts + identifier = generateClientIdentifier(clientState.clientType) + clientState.initialise(provableStore.get(identifier), consensusState) provableStore.set(clientTypePath(identifier), clientType) } ```