Skip to content
Cosmopediaby Unity Nodes
Documentationcosmos/ibc (ICS specifications)cosmos/ibc › spec › app › ics-028-cross-chain-validationView on cosmos/ibc (ICS specifications) ↗

CCV: Technical Specification - Methods

<!-- omit in toc -->

CCV: Technical Specification - Methods

↑ Back to main document

↑ Back to technical specification

<!-- omit in toc -->

Outline

General Methods

↑ Back to Outline

To express the error conditions, the following specification of the sub-protocols uses the exception system of the host state machine, which is exposed through two functions (as defined in ICS 24): abortTransactionUnless and abortSystemUnless.

BeginBlock and EndBlock

↑ Back to Outline

The functions BeginBlock() and EndBlock() (see Implemented Interfaces) are split across the CCV sub-protocols.

<!-- omit in toc -->

[CCV-PCF-BBLOCK.1]

// PCF: Provider Chain Function
// implements the AppModule interface
function BeginBlock() {
    BeginBlockInit()
    BeginBlockCCR()
}
  • Caller
    • The ABCI application.
  • Trigger Event
    • A BeginBlock message is received from the consensus engine; BeginBlock messages are sent once per block.
  • Precondition
    • True.
  • Postcondition
    • BeginBlockInit() is invoked (see [CCV-PCF-BBLOCK-INIT.1], i.e., it contains the BeginBlock() logic needed for the Initialization sub-protocol).
    • BeginBlockCCR() is invoked (see [CCV-PCF-BBLOCK-CCR.1], i.e., it contains the BeginBlock() logic needed for the Consumer Chain Removal sub-protocol).
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-PCF-EBLOCK.1]

// PCF: Provider Chain Function
// implements the AppModule interface
function EndBlock(): [ValidatorUpdate] {
  EndBlockCIS()
  EndBlockCCR()
  EndBlockVSU()

  // do not return anything to the consensus engine
  return []   
}
  • Caller
    • The ABCI application.
  • Trigger Event
    • An EndBlock message is received from the consensus engine; EndBlock messages are sent once per block.
  • Precondition
    • True.
  • Postcondition
    • EndBlockCIS() is invoked (see [CCV-PCF-EBLOCK-CIS.1], i.e., it contains the EndBlock() logic needed for the Consumer Initiated Slashing sub-protocol).
    • EndBlockCCR() is invoked (see [CCV-PCF-EBLOCK-CCR.1], i.e., it contains the EndBlock() logic needed for the Consumer Chain Removal sub-protocol).
    • EndBlockVSU() is invoked (see [CCV-PCF-EBLOCK-VSU.1], i.e., it contains the EndBlock() logic needed for the Validator Set Update sub-protocol).
  • Error Condition
    • None.

Note: The provider CCV module expects the provider Staking module to update its view of the validator set before the EndBlock() of the provider CCV module is invoked. A solution is for the provider Staking module to update its view during EndBlock() and then, the EndBlock() of the provider Staking module to be executed before the EndBlock() of the provider CCV module.


<!-- omit in toc -->

[CCV-CCF-BBLOCK.1]

// CCF: Consumer Chain Function
// implements the AppModule interface
function BeginBlock() {
    BeginBlockInit()
    BeginBlockCCR()
    BeginBlockCIS()
}
  • Caller
    • The ABCI application.
  • Trigger Event
    • A BeginBlock message is received from the consensus engine; BeginBlock messages are sent once per block.
  • Precondition
    • True.
  • Postcondition
    • BeginBlockInit() is invoked (see [CCV-CCF-BBLOCK-INIT.1], i.e., it contains the BeginBlock() logic needed for the Channel Initialization sub-protocol).
    • BeginBlockCCR() is invoked (see [CCV-CCF-BBLOCK-CCR.1], i.e., it contains the BeginBlock() logic needed for the Consumer Chain Removal sub-protocol).
    • BeginBlockCIS() is invoked (see [CCV-CCF-BBLOCK-CIS.1], i.e., it contains the BeginBlock() logic needed for the Consumer Initiated Slashing sub-protocol).
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-CCF-EBLOCK.1]

// CCF: Consumer Chain Function
// implements the AppModule interface
function EndBlock(): [ValidatorUpdate] {
  EndBlockRD()

  // return the validator set updates to the consensus engine
  return EndBlockVSU()
}
  • Caller
    • The ABCI application.
  • Trigger Event
    • An EndBlock message is received from the consensus engine; EndBlock messages are sent once per block.
  • Precondition
    • True. x
  • Postcondition
    • EndBlockRD() is invoked (see [CCV-PCF-EBLOCK-RD.1], i.e., it contains the EndBlock() logic needed for the Reward Distribution sub-protocol).
    • EndBlockVSU() is invoked and the return value is returned to the consensus engine (see [CCV-CCF-EBLOCK-VSU.1], i.e., it contains the EndBlock() logic needed for the Validator Set Update sub-protocol).
  • Error Condition
    • None.

Packet Relay

↑ Back to Outline

<!-- omit in toc -->

[CCV-PCF-RCVP.1]

// PCF: Provider Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onRecvPacket(packet: Packet): bytes {
  switch typeof(packet.data) {
    case VSCMaturedPacketData:
      return onRecvVSCMaturedPacket(packet)
    case SlashPacketData:
      return onRecvSlashPacket(packet)
    default:
      // unexpected packet type
      return PacketError
  }    
}
  • Caller
    • The provider IBC routing module.
  • Trigger Event
    • The provider IBC routing module receives a packet on a channel owned by the provider CCV module.
  • Precondition
    • True.
  • Postcondition
    • If the packet is a VSCMaturedPacket, the acknowledgement obtained from invoking the onRecvVSCMaturedPacket method is returned.
    • If the packet is a SlashPacket, the acknowledgement obtained from invoking the onRecvSlashPacket method is returned.
    • Otherwise, an error acknowledgement is returned.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-PCF-ACKP.1]

// PCF: Provider Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onAcknowledgePacket(packet: Packet, ack: bytes) {
  switch typeof(packet.data) {
    case VSCPacketData:
      onAcknowledgeVSCPacket(packet, ack)
    default:
      // unexpected packet type
      abortTransactionUnless(FALSE)
  }
}
  • Caller
    • The provider IBC routing module.
  • Trigger Event
    • The provider IBC routing module receives an acknowledgement on a channel owned by the provider CCV module.
  • Precondition
    • True.
  • Postcondition
    • If the acknowledgement is for a VSCPacket, the onAcknowledgeVSCPacket method is invoked.
    • Otherwise, the transaction is aborted.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-PCF-TOP.1]

// PCF: Provider Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onTimeoutPacket(packet Packet) {
  switch typeof(packet.data) {
    case VSCPacketData:
      onTimeoutVSCPacket(packet)
    default:
      // unexpected packet type
      abortTransactionUnless(FALSE) 
  }
}
  • Caller
    • The provider IBC routing module.
  • Trigger Event
    • A packet sent on a channel owned by the provider CCV module timed out as a result of either
      • the timeout height or timeout timestamp passing on the consumer chain without the packet being received (see timeoutPacket defined in ICS4);
      • or the channel being closed without the packet being received (see timeoutOnClose defined in ICS4).
  • Precondition
    • The Correct Relayer assumption is violated (see the Assumptions section).
  • Postcondition
    • If the timeout is for a VSCPacket, the onTimeoutVSCPacket method is invoked.
    • Otherwise, the transaction is aborted.
  • Error Condition
    • None.

<!-- omit in toc -->

[CCV-CCF-RCVP.1]

// CCF: Consumer Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onRecvPacket(packet: Packet): bytes {
  switch typeof(packet.data) {
    case VSCPacketData:
      return onRecvVSCPacket(packet)
    default:
      // unexpected packet type
      return PacketError
  }
}
  • Caller
    • The consumer IBC routing module.
  • Trigger Event
    • The consumer IBC routing module receives a packet on a channel owned by the consumer CCV module.
  • Precondition
    • True.
  • Postcondition
    • If the packet is a VSCPacket, the acknowledgement obtained from invoking the onRecvVSCPacket method is returned.
    • Otherwise, an error acknowledgement is returned.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-CCF-ACKP.1]

// CCF: Consumer Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onAcknowledgePacket(packet: Packet, ack: bytes) {
  switch typeof(packet.data) {
    case VSCMaturedPacketData:
      onAcknowledgeVSCMaturedPacket(packet, ack)
    case SlashPacketData:
      onAcknowledgeSlashPacket(packet, ack)
    default:
      // unexpected packet type
      abortTransactionUnless(FALSE)
  }
}
  • Caller
    • The consumer IBC routing module.
  • Trigger Event
    • The consumer IBC routing module receives an acknowledgement on a channel owned by the consumer CCV module.
  • Precondition
    • True.
  • Postcondition
    • If the acknowledgement is for a VSCMaturedPacket, the onAcknowledgeVSCMaturedPacket method is invoked.
    • If the acknowledgement is for a SlashPacket, the onAcknowledgeSlashPacket method is invoked.
    • Otherwise, the transaction is aborted.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-CCF-TOP.1]

// CCF: Consumer Chain Function
// implements the ModuleCallbacks interface defined in ICS26
function onTimeoutPacket(packet Packet) {
  switch typeof(packet.data) {
    case VSCMaturedPacketData:
      onTimeoutVSCMaturedPacket(packet)
    case SlashPacketData:
      onTimeoutSlashPacket(packet)
    default:
      // unexpected packet type
      abortTransactionUnless(FALSE) 
  }
}
  • Caller
    • The consumer IBC routing module.
  • Trigger Event
    • A packet sent on a channel owned by the consumer CCV module timed out as a result of either
      • the timeout height or timeout timestamp passing on the provider chain without the packet being received (see timeoutPacket defined in ICS4);
      • or the channel being closed without the packet being received (see timeoutOnClose defined in ICS4).
  • Precondition
    • The Correct Relayer assumption is violated (see the Assumptions section).
  • Postcondition
    • If the timeout is for a VSCMaturedPacket, the onTimeoutVSCMaturedPacket method is invoked.
    • If the timeout is for a SlashPacket, the onTimeoutSlashPacket method is invoked.
    • Otherwise, the transaction is aborted.
  • Error Condition
    • None.

Sub-protocols

Initialization

↑ Back to Outline

The initialization sub-protocol enables a provider chain and a consumer chain to create a CCV channel -- a unique, ordered IBC channel for exchanging packets. As a prerequisite, the initialization sub-protocol MUST create two IBC clients, one on the provider chain to the consumer chain and one on the consumer chain to the provider chain. This is necessary to verify the identity of the two chains (as long as the clients are trusted).

<!-- omit in toc -->

[CCV-PCF-INITG.1]

// PCF: Provider Chain Function
// implements the AppModule interface
function InitGenesis(state: ProviderGenesisState): [ValidatorUpdate] {
  // bind to ProviderPortId port 
  err = portKeeper.bindPort(ProviderPortId)
  // check whether the capability for the port can be claimed
  abortSystemUnless(err == nil)

  foreach cs in state.consumerStates {
    abortSystemUnless(validateChannelIdentifier(cs.channelId))
    chainToChannel[cs.chainId] = cs.channelId
    channelToChain[cs.channelId] = cc.chainId
  }

  // do not return anything to the consensus engine 
  return []
}
  • Caller
    • The ABCI application.
  • Trigger Event
    • An InitChain message is received from the consensus engine; the InitChain message is sent when the provider chain is first started.
  • Precondition
    • The provider CCV module is in the initial state.
  • Postcondition
    • The capability for the port ProviderPortId is claimed.
    • For each consumer state in the ProviderGenesisState, the initial state is set, i.e., the following mappings chainToChannel, channelToChain are set.
  • Error Condition
    • The capability for the port ProviderPortId cannot be claimed.
    • For any consumer state in the ProviderGenesisState, the channel ID is not valid (cf. the validation function defined in ICS 4).
<!-- omit in toc -->

[CCV-PCF-HCAPROP.1]

// PCF: Provider Chain Function
// implements governance proposal Handler 
function HandleConsumerAdditionProposal(p: ConsumerAdditionProposal) {
    // store the proposal as a pending addition proposal
    pendingConsumerAdditionProposals.Append(p)
}
  • Caller
    • EndBlock() method of Governance module.
  • Trigger Event
    • A governance proposal ConsumerAdditionProposal has passed (i.e., it got the necessary votes).
  • Precondition
    • True.
  • Postcondition
    • The proposal is appended to the list of pending addition proposals, i.e., pendingConsumerAdditionProposals.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-PCF-BBLOCK-INIT.1]

// PCF: Provider Chain Function
function BeginBlockInit() {
  // iterate over the pending addition proposals and create 
  // the consumer client if the spawn time has passed
  foreach p IN pendingConsumerAdditionProposals {
    if currentTimestamp() > p.spawnTime {
      CreateConsumerClient(p)
      pendingConsumerAdditionProposals.Remove(p)
    }
  }
}
  • Caller
    • The BeginBlock() method.
  • Trigger Event
    • A BeginBlock message is received from the consensus engine; BeginBlock messages are sent once per block.
  • Precondition
    • True.
  • Postcondition
    • For each ConsumerAdditionProposal p in the list of pending addition proposals pendingConsumerAdditionProposals, if currentTimestamp() > p.spawnTime, then
      • CreateConsumerClient(p) is invoked;
      • p is removed from pendingConsumerAdditionProposals.
  • Error Condition
    • None.
<!-- omit in toc -->

[CCV-PCF-CRCLIENT.1]

// PCF: Provider Chain Function
// Utility method
function CreateConsumerClient(p: ConsumerAdditionProposal) {
  // check that no other consumer chain with the same chain ID exists
  if p.chainId IN chainToClient.Keys() {
    // ignore governance proposal
    return
  }

  // set consumer chain initial validator set, i.e.,
  // the validator set is the same as the validator set 
  // from own consensus state at current height
  // 
  // TODO: ownConsensusState.validatorSet VS consensusState.nextValidatorsHash
  //       specify which validator set is used as the initial val set
  ownConsensusState = getConsensusState(getCurrentHeight())
  initialValSet = ownConsensusState.validatorSet

  if p.connId != "" { // connection ID provided
    // check validity
    connectionEnd = provableStore.get("connections/{p.connId}")
    if connectionEnd == nil {
      // invalid proposal: cannot find connection
      return
    }
    clientState = provableStore.get("clients/{connectionEnd.clientIdentifier}/clientState")
    if clientState.chainID != p.chainId {
      // invalid proposal: connection not to expected chain ID
      return
    }

    // store client ID
    chainToClient[p.chainId] = connectionEnd.clientIdentifier
    // store connection ID
    chainToConnection[p.chainId] = connId

    // create and store ConsumerGenesisState
    consumerGenesisState[p.chainId] = ConsumerGenesisState {
      // consumer chain MUST start in pre-CCV state, i.e.,
      // the consumer CCV module MUST NOT pass validator updates
      // to the underlying consensus engine
      preCCV: true,
      unbondingPeriod: p.unbondingPeriod,
      connId: connectionEnd.counterpartyConnectionIdentifier,
      providerClientState: nil,
      providerConsensusState: nil,
      counterpartyClientId: "",
      initialValSet: initialValSet,
      transferChannelId: p.transferChannelId,
    }
  } 
  else {
    // create client state
    clientState = ClientState{
      chainId: p.chainId,
      unbondingPeriod: p.unbondingPeriod,
      // the height when the client was last updated is set to the first possible height; 
      // for example, in the case of a Tendermint Client, this is Height{0, 1} (see ICS-7)
      latestHeight: 0, 
    }
    // create consensus state
    consensusState = ConsensusState{
      validatorSet: initialValSet,
    }
    // create consumer chain client and store it
    clientId = clientKeeper.CreateClient(clientState, consensusState)
    chainToClient[p.chainId] = clientId
    
    // create and store ConsumerGenesisState
    consumerGenesisState[p.chainId] = ConsumerGenesisState {
      // consumer chain MUST NOT start in pre-CCV state, i.e.,
      // the consumer CCV module MUST pass validator updates
      // to the underlying consensus engine
      preCCV: false,
      unbondingPeriod: p.unbondingPeriod,
      connId: "",
      providerClientState: getHostClientState(getCurrentHeight()),
      providerConsensusState: ownConsensusState,
      counterpartyClientId: clientId,
      initialValSet: initialValSet,
      transferChannelId: p.transferChannelId,
    }
  }

  // store lockUnbondingOnTimeout flag
  lockUnbondingOnTimeout[p.chainId] = p.lockUnbondingOnTimeout

  // add init timeout timestamp for this consumer chain
  initTimeoutTimestamps[p.chainId] = currentTimestamp().Add(initTimeout)
}
  • Caller
  • Trigger Event
    • A governance proposal ConsumerAdditionProposal p has passed (i.e., it got the necessary votes).
  • Precondition
    • currentTimestamp() > p.spawnTime.
  • Postcondition
    • If a client for p.chainId already exists, the state is not changed.
    • Otherwise,
      • the validator set of the provider chain own consensus state at current height is set as the initial validator set of the consumer chain;
      • if p.connId is set, then
        • if a connection end with ID p.connId cannot be found, the state is not changed;
        • otherwise,
          • if the connection with ID p.connId is not to the chain with ID p.chainId, the state is not changed;
          • otherwise,
            • both the client ID and connection ID are stored;
            • a ConsumerGenesisState is created and stored;

Excerpt (19997 of 89116 characters). Read the whole page on cosmos/ibc (ICS specifications) ↗