Skip to content

Commit

Permalink
Polymer/multihop (#1)
Browse files Browse the repository at this point in the history
* ICS20: Replace Metadata with Memo (cosmos#877)

* memo string replacement

* formatting

Co-authored-by: Carlos Rodriguez <[email protected]>

* ICS9: remove localhost client (cosmos#878)

* remove localhost client

* Update CHANGELOG.md

* Update README.md

* fix: update comment about channel state check in `sendPacket` (cosmos#865)

* update comment

* typo

* remove comment

Co-authored-by: Carlos Rodriguez <[email protected]>

* ICS5: fix releasePort signature (cosmos#885)

Signed-off-by: Jun Kimura <[email protected]>

Signed-off-by: Jun Kimura <[email protected]>

* ICS721: Add tokenData to PacketData (cosmos#876)

* add tokenData to PacketData; improve TypeScript formatting

* revert else style

* extend 03-connection with a proof object for chains that can't introspect their own consensus state. (cosmos#839)

* extend 03-connection with HostConsensusStateProof

* make hostConsensusStateProof optional

* ICS28: Reflect deferred unbonding completion in spec (cosmos#826)

* call UnbondingCanComplete in EndBlock

* update README

* update ics23 link (cosmos#891)

* update eli5 blog post link (cosmos#892)

* ICS28: Sovereign to consumer chain transition (cosmos#840)

* update CreateConsumerClient for sovereign chains

* update InitGenesis for sovereign chains

* establish CCV on ACK and handle preCCV completion

* update Channel Uniqueness Correctness Reasoning

* add pre-CCV module interface with staking

* add clarifications

* add overview TODO

* fix pendingChanges bug

* refactor proposal names (cosmos#855)

* Update spec/app/ics-028-cross-chain-validation/system_model_and_properties.md

Co-authored-by: Daniel T <[email protected]>

* enable optimistic opening handshakes

* remove ConsumerAdditionProposal.initialHeight

* handle proposals in BeginBlock

* pass consumer unbonding period via gov proposal

* update channel init overview - wip

* update overview

* update modified date

* add note re. the existing staking module

Co-authored-by: Daniel T <[email protected]>

* ICS28: VSCPackets should have timeout on provider (cosmos#858)

* update CreateConsumerClient for sovereign chains

* update InitGenesis for sovereign chains

* establish CCV on ACK and handle preCCV completion

* update Channel Uniqueness Correctness Reasoning

* add pre-CCV module interface with staking

* add clarifications

* add overview TODO

* fix pendingChanges bug

* refactor proposal names

* add VSC timeout

* refactor proposal names (cosmos#855)

* Update spec/app/ics-028-cross-chain-validation/system_model_and_properties.md

Co-authored-by: Daniel T <[email protected]>

* enable optimistic opening handshakes

* remove ConsumerAdditionProposal.initialHeight

* handle proposals in BeginBlock

* pass consumer unbonding period via gov proposal

* update channel init overview - wip

* update overview

* update modified date

* ICS28: Channel initialization should have a timeout (cosmos#860)

* add init timeout

* fix typo

* add note on timed out channel init

* update vsc timeout as per implementation

Co-authored-by: Daniel T <[email protected]>

* add angbrav as code owner (cosmos#895)

Co-authored-by: Carlos Rodriguez <[email protected]>

* save progress

* start adding proof generation logic and update graphical_proof.jpg

* rm spec/.DS_Store

Signed-off-by: Jun Kimura <[email protected]>
Co-authored-by: Aditya <[email protected]>
Co-authored-by: Carlos Rodriguez <[email protected]>
Co-authored-by: Carlos Rodriguez <[email protected]>
Co-authored-by: Jun Kimura <[email protected]>
Co-authored-by: Haifeng Xi <[email protected]>
Co-authored-by: Web3 Philosopher <[email protected]>
Co-authored-by: Marius Poke <[email protected]>
Co-authored-by: Daniel T <[email protected]>
Co-authored-by: Carlos Rodriguez <[email protected]>
  • Loading branch information
10 people authored Dec 16, 2022
1 parent a7e466e commit efd6298
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 39 deletions.
177 changes: 138 additions & 39 deletions spec/core/ics-032-multi-hop/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
ics: 32
ics: 33
title: Multi-hop Channel
stage: draft
required-by: 4
Expand Down Expand Up @@ -40,74 +40,173 @@ Associated definitions are as defined in referenced prior standards (where the f

## Technical Specification

The bulk of the spec will be around proof generation and verification. Channel handshake and packet message types will remain the same. Round trip messaging semantics and flow will remain the same as well. There is additional work on the verifier side on the destination chain as well as the relayers who need to query for proofs.
The bulk of the spec will be around proof generation and verification. IBC connections remain unchanged. Addiitonally, channel handshake and packet message types as well as general round trip messaging semantics and flow will remain the same. There is additional work on the verifier side on the destination chain as well as the relayers who need to query for proofs.

Messages passed over multiple hops require proof of the connection path from source chain to destination chain as well as the packet commitment on the source chain. The connection path is proven by verifying the connection state and consensus state of each connection segment in the path to the destination chain. On a high level, this can be thought of as a connection path proof chain where the destination chain can prove the each segment of the connection path by proving the state of the prior connection within the next chains state root.
Messages passed over multiple hops require proof of the connection path from source chain to destination chain as well as the packet commitment on the source chain. The connection path is proven by verifying the connection state and consensus state of each connection in the path to the destination chain. On a high level, this can be thought of as a channel path proof chain where the destination chain can prove a key/value on the source chain by iteratively proving each connection and consensus state in the channel path starting with the consensus state associated with the final client on the destination chain. Each subsequent consensus state and connection is proven until the source chain's consensus state is proven which can then be used to prove the desired key/value on the source chain.

### Channel Handshake and Packet Messages

For both channel handshake and packet messages, additional connection hops are defined in the pre-existing `connectionHops` field. The connection IDs along the channel path must be pre-existing to guarantee delivery to the correct recipient. See `Path Forgery Protection` for more info.
For both channel handshake and packet messages, additional connection hops are defined in the pre-existing `connectionHops` field. The connection IDs along the channel path must be pre-existing and in the `OPEN` state to guarantee delivery to the correct recipient. See `Path Forgery Protection` for more info.

The spec for channel handshakes and packets remains the same. See [ICS 4](https://github.com/cosmos/ibc/tree/main/spec/core/ics-004-channel-and-packet-semantics).

In terms of connection topology, a user would be able to determine a viable channel path from source -> destination using information from the [chain registry](https://github.com/cosmos/chain-registry). They can also independently verify this information via network queries.

### Multihop Relaying

Relayers would deliver channel handshake and IBC packets as they currently do except that they are required to provide more proof of the channel path. Relayers would scan packet events for the connectionHops field and determine if the packet is multi-hop by checking the number of hops in the field. If the number of hops is greater than one then the packet is a multi-hop packet and will need extra proof data.
Relayers would deliver channel handshake and IBC packets as they currently do except that they are required to provide proof of the channel path. Relayers would scan packet events for the connectionHops field and determine if the packet is multi-hop by checking the number of hops in the field. If the number of hops is greater than one then the packet is a multi-hop packet and will need extra proof data.

For each multi-hop channel (detailed proof logic below):

- Scan source chain for IBC messages to relay.
- Read the connectionHops field in from the scanned message to determine the channel path.
- Query for proof of connection and consensus state for each intermediate connection in the channel path to the destination connection.
- Query proof of packet commitment or handshake message commitment on source chain.
- Submit proofs and data to RPC endpoint on destination chain.
1. Scan source chain for IBC messages to relay.
2. Read the connectionHops field in from the scanned message to determine the channel path.
3. Lookup connection endpoints via chain registry configuration and ensure each connection in the channel path is updated to include the key/value to be proven on the source chain.
4. Query for proof of connection and consensus state for each intermediate connection in the channel path to the destination connection.
5. Query proof of packet commitment or handshake message commitment on source chain.
6. Submit proofs and data to RPC endpoint on destination chain.

Relayers are connection topology aware with configurations sourced from the [chain registry](https://github.com/cosmos/chain-registry).

### Proof Generation & Verification

Graphical depiction of proof generation.

![graphical_proof.png](graphical_proof.png)
![graphical_proof.jpg](graphical_proof.jpg)

Proof steps.

![proof_steps.png](proof_steps.png)

Pseudocode proof generation for a channel between chains `A -> B -> C`.
Pseudocode proof generation for a channel between `N` chains `C[0] --> C[i] --> C[N]`

```typescript
function queryBatchProof(client: Client, keys: []string) {
stateProofs = []
for key in keys {
resp = client.QueryABCI(abci.RequestQuery{
Path: "store/ibc/key",
Height: height,
Data: key,
Prove: true,
})
proof = ConvertProofs(resp.ProofOps)
stateProofs = append(stateProofs, proof.Proofs[0])
```go

// generic proof struct
type ProofData struct {
Key *MerklePath
Value []]byte
Proof []byte
}

// set of proofs for a multihop message
type MultihopProof struct {
KeyProof *ProofData // the key/value proof on the source chain
ConsensusProofs []*ProofData // array of consensus proofs starting with proof of chain0 state root on chain1
ConnectionProofs []*ProofData // array of connection proofs starting with proof of conn10 on chain1
}

// Generate proof of key/value at the proofHeight on source chain, chain0.
func GenerateMultihopProof(chains []*Chain, key string, value []byte, proofHeight exported.Height) *MultihopProof {

assert(len(chains) > 2)

var multihopProof MultihopProof
chain0 := chains[0] // source chain
chain1 := chains[1] // first hop chain

height01 := chain1.GetClientStateHeight(chain0) // height of chain0's client state on chain1
assert(height01 >= proofHeight) // ensure that chain0's client state is update to date

// query the key/value proof on the source chain at the proof height
keyProof, _ := chain0.QueryProofAtHeight([]byte(keyPathToProve), int64(proofHeight.GetRevisionHeight()))
prefixedKey := commitmenttypes.ApplyPrefix(chain0.GetPrefix(), commitmenttypes.NewMerklePath(key))

// assign the key/value proof
multihopProof.KeyProof = &ProofData{
Key: &prefixedKey,
Value: nil, // proven values are constructed during verification
Proof: proof,
}
return CombineProofs(stateProofs)

// generate and assign consensus and connection proofs
multihopProof.ConsensusProofs = GenerateConsensusProofs(chains)
multihopProof.ConnectionProofs = GenerateConnectionProofs(chains)

return &multihopProof
}

// Query B & A for connectionState and consensusState kvs
keys = [
"ibc/connections/{id}",
"ibc/consensusStates/{height}",
]
batchStateProofB = queryBatchProof(clientB, keys)
batchStateProofA = queryBatchProof(clientA, keys)

// Query A for channel handshake and/or packet messages
keys = [
"ibc/channelEnds/ports/{portID}/channels/{channelID}",
"ibc/commitments/ports/{portID}/channels/{channelID}/packets/{sequence}"
]
batchMessageProofA = queryBatchProof(clientA, keys)
// GenerateConsensusProofs generates consensus state proofs starting from the source chain to the N-1'th chain.
// Compute proof for each chain 3-tuple starting from the source chain, C0 to the destination chain, CN
// Step 1: |C0 ---> C1 ---> C2| ---> C3 ... ---> CN
// (i) (i+1) (i+2)
// Step 2: C0 ---> |C1 ---> C2 ---> C3| ... ---> CN
// (i) (i+1) (i+2)
// Step N-3: C0 ---> C1 ... ---> |CN-2 --> CN-1 ---> CN|
// (i) (i+1) (i+2)
func GenerateConsensusProofs(chains []*Chain, height) []*ProofData {
assert(len(chains) > 2)

var proofs []*ProofData

// iterate all but the last two chains
for i := 0; i < len(chains)-2; i++ {

previousChain := chains[i] // previous chains state root is on currentChain and is the source chain for i==0.
currentChain := chains[i+1] // currentChain is where the proof is queried and generated
nextChain := chains[i+2] // nextChain holds the state root of the currentChain

currentHeight := GetClientStateHeight(currentChain, sourceChain) // height of previous chain state on current chain
nextHeight := GetClientStateHeight(nextChain, currentChain) // height of current chain state on next chain

// consensus state of previous chain on current chain at currentHeight which is the height of A's client state on B
consensusState := GetConsensusState(currentChain, prevChain.ClientID, currentHeight)

// prefixed key for consensus state of previous chain
consensusKey := GetPrefixedConsensusStateKey(currentChain, currentHeight)

// proof of previous chain's consensus state at currentHeight on currentChain at nextHeight
consensusProof := GetConsensusStateProof(currentChain, nextHeight, currentHeight, currentChain.ClientID)

proofs = append(consStateProofs, &ProofData{
Key: &consensusKey,
Value: consensusState,
Proof: consensusProof,
})
}
return proofs
}

// GenerateConnectionProofs generates connection state proofs starting with C1 --> starting from the source chain to the N-1'th chain.
// Compute proof for each chain 3-tuple starting from the source chain, C0 to the destination chain, CN
// Step 1: |C0 ---> C1 ---> C2| ---> C3 ... ---> CN
// (i) (i+1) (i+2)
// Step 2: C0 ---> |C1 ---> C2 ---> C3| ... ---> CN
// (i) (i+1) (i+2)
// Step N-3: C0 ---> C1 ... ---> |CN-2 --> CN-1 ---> CN|
// (i) (i+1) (i+2)
func GenerateConnectionProofs(chains []*Chain) []*ProofData {
assert(len(chains) > 2)

var proofs []*ProofData

// iterate all but the last two chains
for i := 0; i < len(chains)-2; i++ {

previousChain := chains[i] // previous chains state root is on currentChain and is the source chain for i==0.
currentChain := chains[i+1] // currentChain is where the proof is queried and generated
nextChain := chains[i+2] // nextChain holds the state root of the currentChain

currentHeight := currentChain.GetClientStateHeight(sourceChain) // height of previous chain state on current chain
nextHeight := nextChain.GetClientStateHeight(currentChain) // height of current chain state on next chain

// prefixed key for the connection from currentChain to prevChain
connectionKey := GetPrefixedConnectionKey(currentChain)

// proof of current chain's connection to previous Chain.
connectionEnd := GetConnection(currentChain)

// Query proof of the currentChain's connection with the previousChain at nextHeight
// (currentChain's state root height on nextChain)
connectionProof := GetConnectionProof(currentChain, nextHeight)

proofs = append(proofs, &ProofData{
Key: &connectionKey,
Value: connectionEnd,
Proof: connectionProof,
})
}
return proofs
}
```

Pseudocode proof verification of a channel between chains `A -> B -> C` .
Expand Down
Binary file added spec/core/ics-032-multi-hop/graphical_proof.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit efd6298

Please sign in to comment.