x/ccv/consumer
Overview
The ICS consumer module enables consumer chains to use stake locked on a provider chain as collateral for their own proof-of-stake based block production.
The consumer module established a IBC ordered channel to the provider chain. This channel is used by the provider chain to regularly send validator updates to the consumer chain. The consumer sends these updates to its own consensus engine. This means that the consumer module acts as a staking module of the consumer chain.
Regularly, the consumer module sends a part of the consumer chain's block rewards to the provider chain as ICS rewards.
If one of the validators in the consumer chain's validator set is missing enough blocks (i.e., downtime infraction), the consumer module notifies the provider chain by sending an IBC packet to the provider module. As a result, the misbehaving validator is punished on the provider chain.
State
For clarity, the description of the consumer module state is split into features.
For a more accurate description, check out the x/ccv/consumer/types/keys.go
file, which contains the definitions of all the keys.
Provider Connection
ProviderClientID
ProviderClientID
is the ID of the provider client on which the CCV channel is built.
Format: byte(3) -> string
ProviderChannelID
ProviderChannelID
is the ID of the CCV channel.
Format: byte(4) -> string
Changeover
PreCCV
PreCCV
is the flag set when the consumer chain is in the process of a standalone to consumer chain changeover.
Format: byte(7) -> uint64
InitialValSet
InitialValSet
is the initial validator set on the consumer chain.
Format: byte(8) -> GenesisState
Note that only the InitialValSet
field of the ProviderInfo
field of GenesisState
is set, i.e.,
message GenesisState {
...
ProviderInfo provider = 14
[ (gogoproto.nullable) = false ];
}
message ProviderInfo {
// InitialValset filled in on new chain and on restart.
repeated .tendermint.abci.ValidatorUpdate initial_val_set = 3
[ (gogoproto.nullable) = false ];
}
InitGenesisHeight
InitGenesisHeight
is the height when the consumer module was initialized (i.e., the InitGenesis
method was called).
Format: byte(17) -> uint64
PrevStandaloneChain
PrevStandaloneChain
is the flag set when the consumer chain was previously a standalone chain.
Format: byte(19) -> []byte{}
Validator Updates
PendingChanges
PendingChanges
are the validator updates received from the provider that were not yet sent to the consensus engine.
Format: byte(5) -> ValidatorSetChangePacketData
Note that only the ValidatorUpdates
field of ValidatorSetChangePacketData
is set.
CrossChainValidator
CrossChainValidator
is the internal state of a consumer validator with consensus address addr
.
Format: byte(16) | addr -> CrossChainValidator
, where CrossChainValidator
is defined as
message CrossChainValidator {
bytes address = 1;
int64 power = 2;
// pubkey is the consensus public key of the validator, as a Protobuf Any.
google.protobuf.Any pubkey = 3 [
(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey",
(gogoproto.moretags) = "yaml:\"consensus_pubkey\""
];
// deprecated
bool opted_out = 4 [deprecated = true];
}
HistoricalInfo
HistoricalInfo
is the header and validator information for a given block.
For more details, see the Cosmos SDK docs.
Format: byte(11) | height -> HistoricalInfo
, where HistoricalInfo
is defined in the staking module as
message HistoricalInfo {
tendermint.types.Header header = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
repeated Validator valset = 2 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}
Reward Distribution
LastDistributionTransmission
LastDistributionTransmission
is the block height of the last attempt to send ICS rewards to the provider module.
Format: byte(1) -> LastTransmissionBlockHeight
, where LastTransmissionBlockHeight
is defined as
message LastTransmissionBlockHeight {
int64 height = 1;
}
Downtime Infractions
OutstandingDowntime
OutstandingDowntime
is the flag set when a SlashPacket
is queued to be sent to the provider for a downtime infraction of a validator with consensus address addr
.
The flag is unset when receiving from the provider a VSCPacket
with a slash acknowledgement (see SlashAcks
in ValidatorSetChangePacketData
).
Format: byte(14) | addr -> []byte{}
HeightValsetUpdateID
HeightValsetUpdateID
is the validator set update ID associated with a block height.
Format: byte(13) | height -> uint64
PendingPacketsIndex
PendingPacketsIndex
is the next index available to store packet data to be sent to the provider chain (see below).
Format: byte(20) -> uint64
PendingDataPacketsV1
PendingDataPacketsV1
is the queue of packet data to be sent to the provider chain.
In general, packets in this queue will be sent to the provider in the end blocker, unless
- the CCV channel is not yet established;
- the provider client is expired;
- the last slash packet sent was not yet acknowledged by the provider chain.
Format: byte(15) | index -> ConsumerPacketData
, where index
is the index of the packet in the queue and ConsumerPacketData
is defined as
message ConsumerPacketData {
ConsumerPacketDataType type = 1;
oneof data {
SlashPacketData slashPacketData = 2;
VSCMaturedPacketData vscMaturedPacketData = 3;
}
}
SlashRecord
SlashRecord
is the record storing the state of a SlashPacket sent to the provider chain that was not yet acknowledged.
See ADR 008 for more details.
Format: byte(21) -> SlashRecord
, where SlashRecord
is defined as
message SlashRecord {
bool waiting_on_reply = 1;
google.protobuf.Timestamp send_time = 2
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
}
State Transitions
TBA
IBC Callbacks
The consumer module is an IBC application that implements the IBC module callback.
OnChanOpenInit
OnChanOpenInit
first verifies that the CCV channel was not already created.
Then, it validates the channel parameters -- an ordered IBC channel connected on the consumer
port
and with the counterparty port set to provider
-- and asserts that the version matches the expected version
(only version 1
is supported).
Finally, it verifies that the underlying client is the expected client of the provider chain (i.e., provided in the consumer module genesis state).
OnChanOpenTry
OnChanOpenTry
returns an error. MsgChannelOpenTry
should be sent to the provider.
OnChanOpenAck
OnChanOpenAck
first verifies that the CCV channel was not already created.
Then it verifies that the counterparty version matches the expected version
(only version 1
is supported).
If the verification passes, it stores the ProviderFeePoolAddr in the state.
Finally, if the DistributionTransmissionChannel parameter is not set,
it initiates the opening handshake for a token transfer channel over the same connection as the CCV channel
by calling the ChannelOpenInit
method of the IBC module.
OnChanOpenConfirm
OnChanOpenConfirm
returns an error. MsgChanOpenConfirm
should be sent to the provider.
OnChanCloseInit
OnChanCloseInit
allows relayers to close duplicate OPEN channels, if the channel handshake is completed.
OnChanCloseConfirm
OnChanCloseConfirm
is a no-op.
OnRecvPacket
OnRecvPacket
unmarshals the IBC packet data into a ValidatorSetChangePacketData
struct (see below) and executes the handling logic.
- If it is the first packet received, sets the underlying IBC channel as the canonical CCV channel.
- Collects validator updates to be sent to the consensus engine at the end of the block.
- Store in state the block height to VSC id (i.e.,
valset_update_id
) mapping. - Removed the outstanding downtime flags from the validator for which the jailing
for downtime infractions was acknowledged by the provider chain (see the
slash_acks
field inValidatorSetChangePacketData
).
message ValidatorSetChangePacketData {
repeated .tendermint.abci.ValidatorUpdate validator_updates = 1 [
(gogoproto.nullable) = false,
(gogoproto.moretags) = "yaml:\"validator_updates\""
];
uint64 valset_update_id = 2;
// consensus address of consumer chain validators
// successfully jailed on the provider chain
repeated string slash_acks = 3;
}
OnAcknowledgementPacket
OnAcknowledgementPacket
enables the consumer module to confirm that the provider module received
the previously sent SlashPacket
and it unblocks the sending of the next SlashPacket
.
This functionality is needed for throttling jailing on the provider chain. For more details, see ADR-008.
OnTimeoutPacket
OnTimeoutPacket
is a no-op.
Messages
MsgUpdateParams
MsgUpdateParams
updates the consumer module parameters.
The params are updated through a governance proposal where the signer is the gov module account address.
message MsgUpdateParams {
option (cosmos.msg.v1.signer) = "authority";
// signer is the address of the governance account.
string authority = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// params defines the x/consumer parameters to update.
interchain_security.ccv.v1.ConsumerParams params = 2 [(gogoproto.nullable) = false];
}
BeginBlock
In the BeginBlock
of the consumer module the following actions are performed:
- Store in state the block height to VSC id mapping needed for sending to the provider the height of infractions committed on the consumer chain.
- Track historical entries. This is the same logic as in the
x/staking
module.
EndBlock
In the EndBlock
of the consumer module the following actions are performed:
- If
PreCCV
state is active, i.e., the consumer chain is a previously standalone chain that was just upgraded to include the consumer module, then execute the changeover logic. - Otherwise, distribute block rewards internally and once every BlocksPerDistributionTransmission send ICS rewards to the provider chain.
- Send slash packets to the provider chain reporting infractions validators committed on the consumer chain.
- Send to the consensus engine validator updates reveived from the provider chain.
Hooks
TBA
Events
TBA
Parameters
The consumer module parameters are set by the provider when creating the consumer genesis (i.e., when launching the consumer chain). As a result, changes of these parameters might result in incompatibilities between different versions of consumers and providers.
The consumer module contains the following parameters.
Enabled
Enabled
is deprecated.
BlocksPerDistributionTransmission
Type | Default value |
---|---|
int64 | 1000 |
BlocksPerDistributionTransmission
is the number of blocks between rewards transfers from the consumer to the provider.
DistributionTransmissionChannel
Type | Default value |
---|---|
string | "" |
DistributionTransmissionChannel
is the provider chain IBC channel used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.
Providing an IBC transfer channel enables a consumer chain to re-use one of the existing channels to the provider for consumer chain rewards distribution.
This will preserve the ibc denom
that may already be in use.
This is especially important for standalone chains transitioning to become consumer chains.
For more details, see the changeover procedure.
ProviderFeePoolAddrStr
Type | Default value |
---|---|
string | "" |
ProviderFeePoolAddrStr
is the provider chain fee pool address used for receiving consumer chain reward distribution token transfers. This is automatically set during the consumer-provider handshake procedure.
CcvTimeoutPeriod
Type | Default value |
---|---|
time.Duration | 2419200s (4 weeks) |
CcvTimeoutPeriod
is the period used to compute the timeout timestamp when sending IBC packets.
CcvTimeoutPeriod
may have different values on the provider and consumer chains.
TransferTimeoutPeriod
Type | Default value |
---|---|
time.Duration | 3600s (1 hour) |
TransferTimeoutPeriod
is the timeout period for consumer chain reward distribution IBC packets.
ConsumerRedistributionFraction
Type | Default value |
---|---|
string | "0.75" |
ConsumerRedistributionFraction
is the fraction of tokens allocated to the consumer redistribution address during distribution events.
The fraction is a string representing a decimal number. For example "0.75"
would represent 75%
.
For example, a consumer with ConsumerRedistributionFraction
set to "0.75"
would send 75%
of its block rewards and accumulated fees to the consumer redistribution address, and the remaining 25%
to the provider chain every BlocksPerDistributionTransmission
blocks.
HistoricalEntries
Type | Default value |
---|---|
int64 | 10000 |
HistoricalEntries
is the number of historical info entries to persist in store (see the staking module parameter with the same name for details).
HistoricalEntries
is needed since the consumer module acts as a staking module on the consumer chain.
UnbondingPeriod
Type | Default value |
---|---|
time.Duration | 1209600s (2 weeks) |
UnbondingPeriod
is the unbonding period on the consumer chain.
It is recommended that every consumer chain set and unbonding period shorter than provider unbonding period, e.g., one week shorter.
SoftOptOutThreshold
SoftOptOutThreshold
is deprecated.
RewardDenoms
Type | Default value |
---|---|
[]string | []string |
RewardDenoms
are the denominations which are allowed to be sent to the provider as ICS rewards.
ProviderRewardDenoms
Type | Default value |
---|---|
[]string | []string |
ProviderRewardDenoms
are the denominations coming from the provider which are allowed to be used as ICS rewards. e.g. "uatom".
RetryDelayPeriod
Type | Default value |
---|---|
time.Duration | 3600s (1 hour) |
RetryDelayPeriod
is the period at which the consumer retries to send a SlashPacket
that was rejected by the provider.
For more details, see ADR-008.
Client
CLI
A user can interact with the consumer
module using the CLI.
Query
The query
commands allow users to query consumer
state.
interchain-security-cd query ccvconsumer --help
Next Fee Distribution
The next-fee-distribution
command allows to query next fee distribution data.
interchain-security-cd query ccvconsumer next-fee-distribution [flags]
Example
interchain-security-cd query ccvconsumer next-fee-distribution
Output:
data:
currentHeight: "967"
distribution_fraction: "0.75"
lastHeight: "960"
nextHeight: "980"
toConsumer: ""
toProvider: ""
total: ""
Provider Info
The provider-info
command allows to query provider info.
interchain-security-cd query ccvconsumer provider-info [flags]
Example
interchain-security-cd query ccvconsumer provider-info
Output:
consumer:
chainID: pion-1
channelID: channel-0
clientID: 07-tendermint-0
connectionID: connection-0
provider:
chainID: provider
channelID: channel-0
clientID: 07-tendermint-0
connectionID: connection-0
Throttle State
The throttle-state
command allows to query on-chain state relevant with slash packet throttling.
interchain-security-cd query ccvconsumer throttle-state [flags]
Example
interchain-security-cd query ccvconsumer throttle-state
Output:
packet_data_queue:
- slashPacketData:
infraction: INFRACTION_DOWNTIME
validator:
address: mb06cu8SzQJOdYSzrJAK43Q8at8=
power: "500"
valset_update_id: "48"
type: CONSUMER_PACKET_TYPE_SLASH
slash_record:
send_time: "2024-10-02T07:58:24.405645924Z"
waiting_on_reply: true
Params
The params
command allows to query consumer module parameters.
interchain-security-cd query ccvconsumer params [flags]
Example
interchain-security-cd query ccvconsumer params
Output:
params:
blocks_per_distribution_transmission: "1000"
ccv_timeout_period: 2419200s
consumer_id: "0"
consumer_redistribution_fraction: "0.75"
distribution_transmission_channel: channel-1
enabled: true
historical_entries: "10000"
provider_fee_pool_addr_str: cosmos1ap0mh6xzfn8943urr84q6ae7zfnar48am2erhd
provider_reward_denoms: []
retry_delay_period: 3600s
reward_denoms: []
soft_opt_out_threshold: "0"
transfer_timeout_period: 3600s
unbonding_period: 1209600s
gRPC
A user can query the consumer
module using gRPC endpoints.
Next Fee Distribution
The QueryNextFeeDistribution
endpoint queries next fee distribution data.
interchain_security.ccv.consumer.v1.Query/QueryNextFeeDistribution
Example
grpcurl -plaintext localhost:9090 interchain_security.ccv.consumer.v1.Query/QueryNextFeeDistribution
Output:
{
"data": {
"currentHeight": "402",
"lastHeight": "400",
"nextHeight": "420",
"distributionFraction": "0.75"
}
}
Provider Info
The QueryProviderInfo
endpoint queries provider info.
interchain_security.ccv.consumer.v1.Query/QueryProviderInfo
Example
grpcurl -plaintext localhost:9090 interchain_security.ccv.consumer.v1.Query/QueryProviderInfo
Output:
{
"consumer": {
"chainID": "pion-1",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
},
"provider": {
"chainID": "provider",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
}
}
Throttle State
The QueryThrottleState
endpoint queries on-chain state relevant with slash packet throttling.
interchain_security.ccv.consumer.v1.Query/QueryThrottleState
Example
grpcurl -plaintext localhost:9090 interchain_security.ccv.consumer.v1.Query/QueryThrottleState
Output:
{
"slashRecord": {
"waitingOnReply": true,
"sendTime": "2024-10-02T07:58:24.405645924Z"
},
"packetDataQueue": [
{
"type": "CONSUMER_PACKET_TYPE_SLASH",
"slashPacketData": {
"validator": {
"address": "mb06cu8SzQJOdYSzrJAK43Q8at8=",
"power": "500"
},
"valsetUpdateId": "48",
"infraction": "INFRACTION_DOWNTIME"
}
}
]
}
Params
The QueryParams
endpoint queries consumer module parameters.
interchain_security.ccv.consumer.v1.Query/QueryParams
Example
grpcurl -plaintext localhost:9090 interchain_security.ccv.consumer.v1.Query/QueryParams
Output:
{
"params": {
"enabled": true,
"blocksPerDistributionTransmission": "1000",
"distributionTransmissionChannel": "channel-1",
"providerFeePoolAddrStr": "cosmos1ap0mh6xzfn8943urr84q6ae7zfnar48am2erhd",
"ccvTimeoutPeriod": "2419200s",
"transferTimeoutPeriod": "3600s",
"consumerRedistributionFraction": "0.75",
"historicalEntries": "10000",
"unbondingPeriod": "1209600s",
"softOptOutThreshold": "0",
"retryDelayPeriod": "3600s",
"consumerId": "0"
}
}
REST
A user can query the consumer
module using REST endpoints.
Next Fee Distribution
The next-fee-distribution
endpoint queries next fee distribution data.
/interchain_security/ccv/consumer/next-fee-distribution
Example
curl http://localhost:1317/interchain_security/ccv/consumer/next-fee-distribution
Output:
{
"data": {
"currentHeight": "402",
"lastHeight": "400",
"nextHeight": "420",
"distributionFraction": "0.75"
}
}
Provider Info
The QueryProviderInfo
endpoint queries provider info.
/interchain_security/ccv/consumer/provider-info
Example
curl http://localhost:1317/interchain_security/ccv/consumer/provider-info
Output:
{
"consumer": {
"chainID": "pion-1",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
},
"provider": {
"chainID": "provider",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
}
}
Throttle State
The throttle_state
endpoint queries on-chain state relevant with slash packet throttling.
/interchain_security/ccv/consumer/throttle_state
Example
curl http://localhost:1317/interchain_security/ccv/consumer/throttle_state
Output:
{
"consumer": {
"chainID": "pion-1",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
},
"provider": {
"chainID": "provider",
"clientID": "07-tendermint-0",
"connectionID": "connection-0",
"channelID": "channel-0"
}
}
Params
The params
endpoint queries consumer module parameters.
/interchain_security/ccv/consumer/params
Example
curl http://localhost:1317/interchain_security/ccv/consumer/params
Output:
{
"params": {
"enabled": true,
"blocksPerDistributionTransmission": "1000",
"distributionTransmissionChannel": "channel-1",
"providerFeePoolAddrStr": "cosmos1ap0mh6xzfn8943urr84q6ae7zfnar48am2erhd",
"ccvTimeoutPeriod": "2419200s",
"transferTimeoutPeriod": "3600s",
"consumerRedistributionFraction": "0.75",
"historicalEntries": "10000",
"unbondingPeriod": "1209600s",
"softOptOutThreshold": "0",
"retryDelayPeriod": "3600s",
"consumerId": "0"
}
}