diff --git a/.gitignore b/.gitignore index e5f8e1cb87..94cbdedb68 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .DS_STORE -vue/node_modules +*/node_modules vue/dist release/ docs/tla/states/ diff --git a/docs/architecture/README.md b/docs/architecture/README.md new file mode 100644 index 0000000000..2b817016b1 --- /dev/null +++ b/docs/architecture/README.md @@ -0,0 +1,30 @@ +# Architecture Decision Records (ADR) + +This is a location to record all high-level architecture decisions in the Interchain Security project. + +You can read more about the ADR concept in this [blog post](https://product.reverb.com/documenting-architecture-decisions-the-reverb-way-a3563bb24bd0#.78xhdix6t). + +An ADR should provide: + +- Context on the relevant goals and the current state +- Proposed changes to achieve the goals +- Summary of pros and cons +- References +- Changelog + +Note the distinction between an ADR and a spec. The ADR provides the context, intuition, reasoning, and +justification for a change in architecture, or for the architecture of something +new. The spec is much more compressed and streamlined summary of everything as +it is or should be. + +If recorded decisions turned out to be lacking, convene a discussion, record the new decisions here, and then modify the code to match. + +Note the context/background should be written in the present tense. + +To suggest an ADR, please make use of the [ADR template](./adr-template.md) provided. + +## Table of Contents + +| ADR \# | Description | Status | +| ------ | ----------- | ------ | +| [001](./adr-001-key-assignment.md) | Consumer chain key assignment | Accepted, Implemented | \ No newline at end of file diff --git a/docs/architecture/adr-001-key-assignment.md b/docs/architecture/adr-001-key-assignment.md new file mode 100644 index 0000000000..114d91cae6 --- /dev/null +++ b/docs/architecture/adr-001-key-assignment.md @@ -0,0 +1,267 @@ +# ADR 001: Key Assignment + +## Changelog +* 2022-12-01: Initial Draft + +## Status + +Accepted + +## Context + +KeyAssignment is the name of the feature that allows validator operators to use different consensus keys for each consumer chain validator node that they operate. + +## Decision + +It is possible to change the keys at any time by submitting a transaction (i.e., `MsgAssignConsumerKey`). + +### State required + +- `ValidatorConsumerPubKey` - Stores the validator assigned keys for every consumer chain. +```golang +ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> consumerKey +``` +- `ValidatorByConsumerAddr` - Stores the mapping from validator addresses on consumer chains to validator addresses on the provider chain. Needed for the consumer initiated slashing sub-protocol. +```golang +ValidatorsByConsumerAddrBytePrefix | len(chainID) | chainID | consumerConsAddress -> providerConsAddress +``` +- `KeyAssignmentReplacements` - Stores the key assignments that need to be replaced in the current block. Needed to apply the key assignments received in a block to the validator updates sent to the consumer chains. +```golang +KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerConsAddress -> abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower}, +``` +- `ConsumerAddrsToPrune` - Stores the mapping from VSC ids to consumer validators addresses. Needed for pruning `ValidatorByConsumerAddr`. +```golang +ConsumerAddrsToPruneBytePrefix | len(chainID) | chainID | vscID -> []consumerConsAddresses +``` + +### Protocol overview + +On receiving a `MsgAssignConsumerKey(chainID, providerAddr, consumerKey)` message: +```golang +// get validator from staking module +validator, found := stakingKeeper.GetValidator(providerAddr) +if !found { + return ErrNoValidatorFound +} +providerConsAddr := validator.GetConsAddr() + +// make sure consumer key is not in use +consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey) +if _, found := GetValidatorByConsumerAddr(ChainID, consumerAddr); found { + return ErrInvalidConsumerConsensusPubKey +} + +// check whether the consumer chain is already registered +// i.e., a client to the consumer was already created +if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered { + // get the previous key assigned for this validator on this consumer chain + oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr) + if found { + // mark this old consumer key as prunable once the VSCMaturedPacket + // for the current VSC ID is received + oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey) + vscID := GetValidatorSetUpdateId() + AppendConsumerAddrsToPrune(chainID, vscID, oldConsumerAddr) + } else { + // the validator had no key assigned on this consumer chain + oldConsumerKey := validator.TmConsPublicKey() + } + + // check whether the validator is valid, i.e., its power is positive + if currentPower := stakingKeeper.GetLastValidatorPower(providerAddr); currentPower > 0 { + // to enable multiple calls of AssignConsumerKey in the same block by the same validator + // the key assignment replacement should not be overwritten + if _, found := GetKeyAssignmentReplacement(chainID, providerConsAddr); !found { + // store old key and power for modifying the valset update in EndBlock + oldKeyAssignment := abci.ValidatorUpdate{PubKey: oldConsumerKey, Power: currentPower} + SetKeyAssignmentReplacement(chainID, providerConsAddr, oldKeyAssignment) + } + } +} else { + // if the consumer chain is not registered, then remove the previous reverse mapping + if oldConsumerKey, found := GetValidatorConsumerPubKey(chainID, providerConsAddr); found { + oldConsumerAddr := utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey) + DeleteValidatorByConsumerAddr(chainID, oldConsumerAddr) + } +} + + +// set the mapping from this validator's provider address to the new consumer key +SetValidatorConsumerPubKey(chainID, providerConsAddr, consumerKey) + +// set the reverse mapping: from this validator's new consensus address +// on the consumer to its consensus address on the provider +SetValidatorByConsumerAddr(chainID, consumerAddr, providerConsAddr) +``` + +When a new consumer chain is registered, i.e., a client to the consumer chain is created, the provider constructs the consumer CCV module part of the genesis state (see `MakeConsumerGenesis`). +```golang +func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) { + // ... + // get initial valset from the staking module + var updates []abci.ValidatorUpdate{} + stakingKeeper.IterateLastValidatorPowers(func(providerAddr sdk.ValAddress, power int64) (stop bool) { + validator := stakingKeeper.GetValidator(providerAddr) + providerKey := validator.TmConsPublicKey() + updates = append(updates, abci.ValidatorUpdate{PubKey: providerKey, Power: power}) + return false + }) + + // applies the key assignment to the initial validator + for i, update := range updates { + providerAddr := utils.TMCryptoPublicKeyToConsAddr(update.PubKey) + if consumerKey, found := GetValidatorConsumerPubKey(chainID, providerAddr); found { + updates[i].PubKey = consumerKey + } + } + gen.InitialValSet = updates + + // get a hash of the consumer validator set from the update + updatesAsValSet := tendermint.PB2TM.ValidatorUpdates(updates) + hash := tendermint.NewValidatorSet(updatesAsValSet).Hash() + + return gen, hash, nil +} +``` + +On `EndBlock` while queueing `VSCPacket`s to send to registered consumer chains: +```golang +func QueueVSCPackets() { + valUpdateID := GetValidatorSetUpdateId() + // get the validator updates from the staking module + valUpdates := stakingKeeper.GetValidatorUpdates() + + IterateConsumerChains(func(chainID, clientID string) (stop bool) { + // apply the key assignment to the validator updates + valUpdates := ApplyKeyAssignmentToValUpdates(chainID, valUpdates) + // .. + }) + // ... +} + +func ApplyKeyAssignmentToValUpdates( + chainID string, + valUpdates []abci.ValidatorUpdate, +) (newUpdates []abci.ValidatorUpdate) { + for _, valUpdate := range valUpdates { + providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey) + + // if a key assignment replacement is found, then + // remove the valupdate with the old consumer key + // and create two new valupdates + prevConsumerKey, _, found := GetKeyAssignmentReplacement(chainID, providerAddr) + if found { + // set the old consumer key's power to 0 + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: prevConsumerKey, + Power: 0, + }) + // set the new consumer key's power to the power in the update + newConsumerKey := GetValidatorConsumerPubKey(chainID, providerAddr) + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: newConsumerKey, + Power: valUpdate.Power, + }) + // delete key assignment replacement + DeleteKeyAssignmentReplacement(chainID, providerAddr) + } else { + // there is no key assignment replacement; + // check if the validator's key is assigned + consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + if found { + // replace the update containing the provider key + // with an update containing the consumer key + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: consumerKey, + Power: valUpdate.Power, + }) + } else { + // keep the same update + newUpdates = append(newUpdates, valUpdate) + } + } + } + + // iterate over the remaining key assignment replacements + IterateKeyAssignmentReplacements(chainID, func( + pAddr sdk.ConsAddress, + prevCKey tmprotocrypto.PublicKey, + power int64, + ) (stop bool) { + // set the old consumer key's power to 0 + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: prevCKey, + Power: 0, + }) + // set the new consumer key's power to the power in key assignment replacement + newConsumerKey := GetValidatorConsumerPubKey(chainID, pAddr) + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: newConsumerKey, + Power: power, + }) + return false + }) + + // remove all the key assignment replacements + + return newUpdates +} +``` + +On receiving a `SlashPacket` from a consumer chain with id `chainID` for a infraction of a validator `data.Validator`: +```golang +func HandleSlashPacket(chainID string, data ccv.SlashPacketData) (success bool, err error) { + // ... + // the slash packet validator address may be known only on the consumer chain; + // in this case, it must be mapped back to the consensus address on the provider chain + consumerAddr := sdk.ConsAddress(data.Validator.Address) + providerAddr, found := GetValidatorByConsumerAddr(chainID, consumerAddr) + if !found { + // the validator has the same key on the consumer as on the provider + providerAddr = consumer + } + // ... +} +``` + +On receiving a `VSCMatured`: +```golang +func OnRecvVSCMaturedPacket(packet channeltypes.Packet, data ccv.VSCMaturedPacketData) exported.Acknowledgement { + // ... + // prune previous consumer validator address that are no longer needed + consumerAddrs := GetConsumerAddrsToPrune(chainID, data.ValsetUpdateId) + for _, addr := range consumerAddrs { + DeleteValidatorByConsumerAddr(chainID, addr) + } + DeleteConsumerAddrsToPrune(chainID, data.ValsetUpdateId) + // ... +} +``` + +On stopping a consumer chain: +```golang +func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, lockUbd, closeChan bool) (err error) { + // ... + // deletes all the state needed for key assignments on this consumer chain + // ... +} +``` + +## Consequences + +### Positive + +- Validators can use different consensus keys on the consumer chains. + +### Negative + +- None + +### Neutral + +- The consensus state necessary to create a client to the consumer chain must use the hash returned by the `MakeConsumerGenesis` method as the `nextValsHash`. +- The consumer chain can no longer check the initial validator set against the consensus state on `InitGenesis`. + +## References + +* [Key assignment issue](https://github.com/cosmos/interchain-security/issues/26) diff --git a/docs/architecture/adr-template.md b/docs/architecture/adr-template.md new file mode 100644 index 0000000000..129ddfa8f9 --- /dev/null +++ b/docs/architecture/adr-template.md @@ -0,0 +1,37 @@ +# ADR {ADR-NUMBER}: {TITLE} + +## Changelog +* {date}: {changelog} + +## Status + +> A decision may be "proposed" if it hasn't been agreed upon yet, or "accepted" once it is agreed upon. If a later ADR changes or reverses a decision, it may be marked as "deprecated" or "superseded" with a reference to its replacement. + +{Deprecated|Proposed|Accepted} + +## Context + +> This section contains all the context one needs to understand the current state, and why there is a problem. It should be as succinct as possible and introduce the high level idea behind the solution. + +## Decision + +> This section explains all of the details of the proposed solution, including implementation details. +It should also describe affects / corollary items that may need to be changed as a part of this. +If the proposed change will be large, please also indicate a way to do the change to maximize ease of review. +(e.g. the optimal split of things to do between separate PR's) + +## Consequences + +> This section describes the consequences, after applying the decision. All consequences should be summarized here, not just the "positive" ones. + +### Positive + +### Negative + +### Neutral + +## References + +> Are there any relevant PR comments, issues that led up to this, or articles referrenced for why we made the given design choice? If so link them here! + +* {reference link} diff --git a/docs/quality_assurance.md b/docs/quality_assurance.md index 3143393c92..1e7b3bc1e6 100644 --- a/docs/quality_assurance.md +++ b/docs/quality_assurance.md @@ -47,14 +47,14 @@ IBC packets: | ID | Concern | Code Review | Unit Testing | E2E Testing | Diff. Testing | Testnet | | -- | ------- | ----------- | ------------ | ----------- | ------------- | ------- | -| 2.01 | Create IBC clients | `Scheduled` (ibc-go) | `Done` [TestCreateConsumerClient](../x/ccv/provider/keeper/proposal_test.go#117), [TestInitGenesis](../x/ccv/consumer/keeper/genesis_test.go#26) | `Done` [SetupTest](../tests/e2e/setup_test.go#39), [TestConsumerGenesis](../tests/e2e/channel_init_test.go#21) | `Future work` | `Scheduled` | -| 2.02 | Create CCV channel (handshake) | `Scheduled` (ibc-go) | `Done` [provider/ibc_module_test.go](../x/ccv/provider/ibc_module_test.go), [consumer/ibc_module_test.go](../x/ccv/consumer/ibc_module_test.go) | `Done` [SetupCCVChannel](../tests/e2e/setup_test.go#125) | `Future work` | `Scheduled` | -| 2.03 | Sending IBC packets | `Scheduled` (ibc-go) | `NA` | `Done` [TestSendVSCMaturedPackets](../tests/e2e/valset_update_test.go#39), [TestSendSlashPacket](../tests/e2e/slashing_test.go#648) | `Done` | `Scheduled` | -| 2.04 | Handling acknowledgments | `Scheduled` (ibc-go) | [Scheduled](https://github.com/cosmos/interchain-security/issues/362) | `Partial coverage` [TestOnAcknowledgementPacket](../x/ccv/consumer/keeper/relay_test.go#152), [TestSlashPacketAcknowldgement](../tests/e2e/slashing_test.go#258) | `Done` | `Scheduled` | +| 2.01 | Create IBC clients | `Scheduled` (ibc-go) | `Done` [TestCreateConsumerClient](../x/ccv/provider/keeper/proposal_test.go#117), [TestInitGenesis](../x/ccv/consumer/keeper/genesis_test.go#26) | `Done` [SetupTest](../tests/e2e/setup.go) | `Future work` | `Scheduled` | +| 2.02 | Create CCV channel (handshake) | `Scheduled` (ibc-go) | `Done` [provider/ibc_module_test.go](../x/ccv/provider/ibc_module_test.go), [consumer/ibc_module_test.go](../x/ccv/consumer/ibc_module_test.go) | `Done` [SetupCCVChannel](../tests/e2e/setup.go) | `Future work` | `Scheduled` | +| 2.03 | Sending IBC packets | `Scheduled` (ibc-go) | `NA` | `Done` [TestSendVSCMaturedPackets](../tests/e2e/valset_update.go), [TestSendSlashPacket](../tests/e2e/slashing.go) | `Done` | `Scheduled` | +| 2.04 | Handling acknowledgments | `Scheduled` (ibc-go) | [Scheduled](https://github.com/cosmos/interchain-security/issues/362) | `Partial coverage` [TestOnAcknowledgementPacket](../x/ccv/consumer/keeper/relay_test.go#152), [TestSlashPacketAcknowldgement](../tests/e2e/slashing.go) | `Done` | `Scheduled` | | 2.05 | Handling timeouts | `Scheduled` (ibc-go) | [Scheduled](https://github.com/cosmos/interchain-security/issues/362) |`NA` | `Future work` | `Scheduled` | | 2.06 | Handling IBC client expiration | `Scheduled` (ibc-go) | `NA` | `Done` [expired_client.go](../tests/e2e/expired_client.go) | `Future work` | `Scheduled` | -| 2.07 | ICS-20 channel creation | `Scheduled` (ibc-go) | `NA` | `Done` [SetupTransferChannel](../tests/e2e/setup_test.go#152) |`Future work` | `Scheduled` | -| 2.08 | ICS-20 transfer | `Scheduled` (ibc-go) | `NA` | `Done` [TestRewardsDistribution](../tests/e2e/distribution_test.go#17) | `NA` | `Scheduled` | +| 2.07 | ICS-20 channel creation | `Scheduled` (ibc-go) | `NA` | `Done` [SetupTransferChannel](../tests/e2e/setup.go) |`Future work` | `Scheduled` | +| 2.08 | ICS-20 transfer | `Scheduled` (ibc-go) | `NA` | `Done` [TestRewardsDistribution](../tests/e2e/distribution.go) | `NA` | `Scheduled` | | 2.09 | Changes in IBC-GO testing suite | `Scheduled` (ibc-go) | `NA` | `NA` | `Partial coverage` | `NA` | ### Integration with Cosmos SDK @@ -63,9 +63,9 @@ IBC packets: | ID | Concern | Code Review | Unit Testing | E2E Testing | Diff. Testing | Testnet | | -- | ------- | ----------- | ------------ | ----------- | ------------- | ------- | -| 3.01 | Changes to staking module | `Done` | `Done` [unbonding_test.go](https://github.com/cosmos/cosmos-sdk/blob/interchain-security-rebase.0.45.6/x/staking/keeper/unbonding_test.go) | `Partial coverage`
[unbonding_test.go](../tests/e2e/unbonding_test.go)
redelegation could be expanded, validator unbonding missing | `Partial coverage` | `Scheduled` | -| 3.02 | Changes to slashing module | `Done` | `NA` | `Done`
[TestValidatorDowntime](../tests/e2e/slashing_test.go#L502)
| `Partial coverage` | `Scheduled` | -| 3.03 | Changes to evidence module | `Done` | `NA` | `Done`
[TestValidatorDoubleSigning](../tests/e2e/slashing_test.go#L584)
| `NA` | `Scheduled` | +| 3.01 | Changes to staking module | `Done` | `Done` [unbonding_test.go](https://github.com/cosmos/cosmos-sdk/blob/interchain-security-rebase.0.45.6/x/staking/keeper/unbonding_test.go) | `Partial coverage`
[unbonding_test.go](../tests/e2e/unbonding.go)
redelegation could be expanded, validator unbonding missing | `Partial coverage` | `Scheduled` | +| 3.02 | Changes to slashing module | `Done` | `NA` | `Done`
[TestValidatorDowntime](../tests/e2e/slashing.go)
| `Partial coverage` | `Scheduled` | +| 3.03 | Changes to evidence module | `Done` | `NA` | `Done`
[TestValidatorDoubleSigning](../tests/e2e/slashing.go)
| `NA` | `Scheduled` | ### Provider Chain Correctness @@ -77,13 +77,13 @@ The main concern addressed in this section is the correctness of the provider ch | ID | Concern | Code Review | Unit Testing | E2e | Diff. Testing | Testnet | Protocol audit | | -- | ------- | ----------- | ------------ | --- | ------------- | ------- | -------------- | -| 4.01 | Liveness of undelegations
- unbonding delegation entries are eventually removed from `UnbondingDelegation` | `Scheduled` | `NA` | `Done`
[unbonding_test.go](../tests/e2e/unbonding_test.go) | `Done` | `Scheduled` | `NA` | +| 4.01 | Liveness of undelegations
- unbonding delegation entries are eventually removed from `UnbondingDelegation` | `Scheduled` | `NA` | `Done`
[unbonding_test.go](../tests/e2e/unbonding.go) | `Done` | `Scheduled` | `NA` | | 4.02 | Liveness of redelegations
- redelegations entries are eventually removed from `Redelegations` | `Scheduled` | `NA` | `Scheduled` | `Scheduled` | `Scheduled` | `NA` | | 4.03 | Liveness of validator unbondings
- unbonding validators with no delegations are eventually removed from `Validators` | `Scheduled` | `NA` | `NA` | `Done` | `Scheduled` | `NA` | -| 4.04 | Unbonding operations (undelegations, redelegations, validator unbondings) should eventually complete even if the CCV channel is never established (due to error)
- expected outcome: the channel initialization sub-protocol eventually times out, which leads to the consumer chain removal | `Scheduled` | `NA` | `Done` [TestUndelegationDuringInit](../tests/e2e/unbonding_test.go#145) | `Future work` | `Scheduled` | `Done` | -| 4.05 | Unbonding operations (undelegations, redelegations, validator unbondings) should eventually complete even if one of the clients expire
- expected outcome: the pending VSC packets eventually timeout, which leads to the consumer chain removal | `Scheduled` | `NA` | `Done` [TestUndelegationVscTimeout](../tests/e2e/unbonding.go#127) | `Future work` | `Scheduled` | `NA` | -| 4.06 | A validator cannot get slashed more than once for double signing, regardless of how many times it double signs on different chains (consumers or provider) | `Scheduled` | `NA` |`Done`
[TestHandleSlashPacketErrors](../tests/e2e/slashing_test.go#L317) | `Done` | `Scheduled` | `NA` | -| 4.07 | A validator cannot get slashed multiple times for downtime on the same consumer chain without requesting to `Unjail` itself on the provider chain in between | `Scheduled` | `NA` | `Partial coverage`
[TestSendSlashPacket](../tests/e2e/slashing_test.go#L648) | `Partial coverage` | `Scheduled` | `NA` | +| 4.04 | Unbonding operations (undelegations, redelegations, validator unbondings) should eventually complete even if the CCV channel is never established (due to error)
- expected outcome: the channel initialization sub-protocol eventually times out, which leads to the consumer chain removal | `Scheduled` | `NA` | `Done` [TestUndelegationDuringInit](../tests/e2e/unbonding.go) | `Future work` | `Scheduled` | `Done` | +| 4.05 | Unbonding operations (undelegations, redelegations, validator unbondings) should eventually complete even if one of the clients expire
- expected outcome: the pending VSC packets eventually timeout, which leads to the consumer chain removal | `Scheduled` | `NA` | `Done` [TestUndelegationVscTimeout](../tests/e2e/unbonding.go) | `Future work` | `Scheduled` | `NA` | +| 4.06 | A validator cannot get slashed more than once for double signing, regardless of how many times it double signs on different chains (consumers or provider) | `Scheduled` | `NA` |`Done`
[TestHandleSlashPacketErrors](../tests/e2e/slashing.go) | `Done` | `Scheduled` | `NA` | +| 4.07 | A validator cannot get slashed multiple times for downtime on the same consumer chain without requesting to `Unjail` itself on the provider chain in between | `Scheduled` | `NA` | `Partial coverage`
[TestSendSlashPacket](../tests/e2e/slashing.go) | `Partial coverage` | `Scheduled` | `NA` | | 4.08 | A validator can be slashed multiple times for downtime on different chains | `Scheduled` | `NA` | `Future work` | `NA` | `Scheduled` | `NA` | | 4.09 | The provider chain can easily be restarted with IS enabled
- `ExportGenesis` & `InitGenesis`
- requires https://github.com/informalsystems/hermes/issues/1152| `Scheduled` | `Done`
[TestInitAndExportGenesis](../x/ccv/provider/keeper/genesis_test.go#L20) | `Future work` | `Future work` | `Scheduled` | `NA` | | 4.10 | The provider chain can graciously handle a CCV packet timing out (without shuting down)
- expected outcome: consumer chain shuts down and its state in provider CCV module is removed | `Scheduled` | `Scheduled` | `NA` | `Future work` | `Scheduled` | `NA` | @@ -138,7 +138,7 @@ In addition, the implementation MUST guarantee the following [system properties] | ID | Concern re. _Consumer Rewards Distribution_ | Code Review | Unit Testing | E2e Testing | Diff. testing | Testnet | Protocol audit | | -- | ------------------------------------------- | ----------- | ------------ | ----------- | ------------- | ------- | -------------- | -| 9.01 | Validators on the provider chain receive rewards for participating in IS | `Scheduled` | `NA` | `Done` [TestRewardsDistribution](../tests/e2e/distribution_test.go#17) | `NA` | `Scheduled` | `NA` | +| 9.01 | Validators on the provider chain receive rewards for participating in IS | `Scheduled` | `NA` | `Done` [TestRewardsDistribution](../tests/e2e/distribution.go) | `NA` | `Scheduled` | `NA` | | 9.02 | The rewards sent to the provider chain are escrowed on the consumer chains (no double spend) | `Scheduled` | `NA` | `Scheduled` | `NA` | `Scheduled` | `NA` | --- @@ -157,7 +157,7 @@ The main concern addressed in this section is the correctness of the consumer ch | 10.02 | A chain has the ability to restart as a consumer chain with no more than 24 hours downtime | `Scheduled` | `NA` | `NA` | `NA` | `Scheduled` | `NA` | | 10.03 | A consumer chain has the ability to restart as a normal chain after shutting down, either controlled (via `ConsumerRemovalProposal`) or due to timing out | `Scheduled` | `NA` | `NA` | `NA` | `Scheduled` | `NA` | | 10.04 | A consumer chain has the ability to restart as a consumer chain with the same `chainId` after shutting down, either controlled (via `ConsumerRemovalProposal`) or due to timing out | `Scheduled` | `NA` | `Scheduled` | `NA` | `Scheduled` | `NA` | -| 10.05 | Governance on `gov-cc` | `Scheduled` | `NA` | `Partial Coverage` [TestDemocracyGovernanceWhitelisting](../tests/e2e/distribution_test.go#133) | `Scheduled` | `Scheduled` | `NA` | +| 10.05 | Governance on `gov-cc` | `Scheduled` | `NA` | `Partial Coverage` [TestDemocracyGovernanceWhitelisting](../tests/e2e/distribution.go) | `Scheduled` | `Scheduled` | `NA` | | 10.06 | CosmWasm on `wasm-cc` | `Scheduled` | `NA` | `Scheduled` | `NA` | `Scheduled` | `NA` | | TBA ... diff --git a/interchain-securityd b/interchain-securityd deleted file mode 100755 index e702bd9fdd..0000000000 Binary files a/interchain-securityd and /dev/null differ diff --git a/proto/interchain_security/ccv/provider/v1/genesis.proto b/proto/interchain_security/ccv/provider/v1/genesis.proto index f9ceed8309..241a866bfb 100644 --- a/proto/interchain_security/ccv/provider/v1/genesis.proto +++ b/proto/interchain_security/ccv/provider/v1/genesis.proto @@ -9,6 +9,7 @@ import "interchain_security/ccv/v1/ccv.proto"; import "interchain_security/ccv/provider/v1/provider.proto"; import "interchain_security/ccv/consumer/v1/consumer.proto"; import "interchain_security/ccv/consumer/v1/genesis.proto"; +import "tendermint/crypto/keys.proto"; // GenesisState defines the CCV provider chain genesis state @@ -36,6 +37,15 @@ message GenesisState { [ (gogoproto.nullable) = false ]; Params params = 8 [ (gogoproto.nullable) = false ]; + // empty for a new chain + repeated ValidatorConsumerPubKey validator_consumer_pubkeys = 9 + [ (gogoproto.nullable) = false ]; + // empty for a new chain + repeated ValidatorByConsumerAddr validators_by_consumer_addr = 10 + [ (gogoproto.nullable) = false ]; + // empty for a new chain + repeated ConsumerAddrsToPrune consumer_addrs_to_prune = 11 + [ (gogoproto.nullable) = false ]; } // consumer chain @@ -76,3 +86,27 @@ message ValsetUpdateIdToHeight { uint64 valset_update_id = 1; uint64 height = 2; } + +// Used to serialize the ValidatorConsumerPubKey index from key assignment +// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey +message ValidatorConsumerPubKey { + string chain_id = 1; + bytes provider_addr = 2; + tendermint.crypto.PublicKey consumer_key = 3; +} + +// Used to serialize the ValidatorConsumerAddr index from key assignment +// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr +message ValidatorByConsumerAddr { + string chain_id = 1; + bytes consumer_addr = 2; + bytes provider_addr = 3; +} + +// Used to serialize the ConsumerAddrsToPrune index from key assignment +// ConsumerAddrsToPrune: (chainID, vscID uint64) -> consumerAddrs AddressList +message ConsumerAddrsToPrune { + string chain_id = 1; + uint64 vsc_id = 2; + AddressList consumer_addrs = 3; +} \ No newline at end of file diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 3824f8e9e8..9b45690fa1 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -110,3 +110,8 @@ message ConsumerRemovalProposals { // proposals waiting for stop_time to pass repeated ConsumerRemovalProposal pending = 1; } + +// AddressList contains a list of consensus addresses +message AddressList { + repeated bytes addresses = 1; +} \ No newline at end of file diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 687f158bef..a4144b250a 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -39,6 +39,20 @@ service Query { option (google.api.http).get = "/interchain_security/ccv/provider/consumer_chain_stop_proposals"; } + + // QueryValidatorConsumerAddr queries the address + // assigned by a validator for a consumer chain. + rpc QueryValidatorConsumerAddr(QueryValidatorConsumerAddrRequest) + returns (QueryValidatorConsumerAddrResponse) { + option (google.api.http).get = "/interchain_security/ccv/provider/validator_consumer_addr"; + } + + // QueryProviderAddr returns the provider chain validator + // given a consumer chain validator address + rpc QueryValidatorProviderAddr(QueryValidatorProviderAddrRequest) + returns (QueryValidatorProviderAddrResponse) { + option (google.api.http).get = "/interchain_security/ccv/provider/validator_provider_addr"; + } } message QueryConsumerGenesisRequest { string chain_id = 1; } @@ -68,3 +82,33 @@ message Chain { string chain_id = 1; string client_id = 2; } + +message QueryValidatorConsumerAddrRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // The id of the consumer chain + string chain_id = 1; + // The consensus address of the validator on the provider chain + string provider_address = 2 + [ (gogoproto.moretags) = "yaml:\"address\"" ]; +} + +message QueryValidatorConsumerAddrResponse { + // The address of the validator on the consumer chain + string consumer_address = 1; +} + +message QueryValidatorProviderAddrRequest { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // The id of the provider chain + string chain_id = 1; + // The consensus address of the validator on the consumer chain + string consumer_address = 2 + [ (gogoproto.moretags) = "yaml:\"address\"" ]; +} + +message QueryValidatorProviderAddrResponse { + // The address of the validator on the provider chain + string provider_address = 1; +} diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto new file mode 100644 index 0000000000..567a7d9daa --- /dev/null +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -0,0 +1,29 @@ +syntax = "proto3"; +package interchain_security.ccv.provider.v1; + +option go_package = "github.com/cosmos/interchain-security/x/ccv/provider/types"; + +import "google/api/annotations.proto"; +import "gogoproto/gogo.proto"; +import "cosmos_proto/cosmos.proto"; +import "google/protobuf/any.proto"; + +// Msg defines the Msg service. +service Msg { + rpc AssignConsumerKey(MsgAssignConsumerKey) returns (MsgAssignConsumerKeyResponse); +} + +message MsgAssignConsumerKey { + option (gogoproto.equal) = false; + option (gogoproto.goproto_getters) = false; + // The chain id of the consumer chain to assign a consensus public key to + string chain_id = 1; + // The validator address on the provider + string provider_addr = 2 + [ (gogoproto.moretags) = "yaml:\"address\"" ]; + // The consensus public key to use on the consumer + google.protobuf.Any consumer_key = 3 + [ (cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey" ]; +} + +message MsgAssignConsumerKeyResponse {} \ No newline at end of file diff --git a/tests/e2e/README.md b/tests/e2e/README.md index 3657117adc..3cf782bce2 100644 --- a/tests/e2e/README.md +++ b/tests/e2e/README.md @@ -13,6 +13,7 @@ E2e tests are categorized into files as follows: - `stop_consumer.go` - e2e tests for the _Consumer Chain Removal_ sub-protocol - `normal_operations.go` - e2e tests for _normal operations_ of ICS enabled chains - `expired_client.go` - e2e tests for testing expired clients +- `key_assignment.go` - e2e tests for testing key assignment - `instance_test.go` - ties the e2e test structure into golang's standard test mechanism, with appropriate definitions for concrete app types and setup callback To run the e2e tests defined in this repo on any arbitrary consumer and provider implementation, copy the pattern exemplified in `instance_test.go` and `specific_setup.go` diff --git a/tests/e2e/channel_init.go b/tests/e2e/channel_init.go index 9785ef0c39..055cf4d800 100644 --- a/tests/e2e/channel_init.go +++ b/tests/e2e/channel_init.go @@ -1,86 +1,5 @@ package e2e -import ( - cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" - "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" - - tmtypes "github.com/tendermint/tendermint/types" - - channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" - - ccv "github.com/cosmos/interchain-security/x/ccv/types" - - abci "github.com/tendermint/tendermint/abci/types" - - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" -) - -func (suite *CCVTestSuite) TestConsumerGenesis() { - - consumerKeeper := suite.consumerApp.GetConsumerKeeper() - - genesis := consumerKeeper.ExportGenesis(suite.consumerChain.GetContext()) - - suite.Require().NotPanics(func() { - consumerKeeper.InitGenesis(suite.consumerChain.GetContext(), genesis) - // reset suite to reset provider client - suite.SetupTest() - consumerKeeper = suite.consumerApp.GetConsumerKeeper() - }) - - ctx := suite.consumerChain.GetContext() - portId := consumerKeeper.GetPort(ctx) - suite.Require().Equal(ccv.ConsumerPortID, portId) - - clientId, ok := consumerKeeper.GetProviderClientID(ctx) - suite.Require().True(ok) - _, ok = suite.consumerApp.GetIBCKeeper().ClientKeeper.GetClientState(ctx, clientId) - suite.Require().True(ok) - - suite.SetupCCVChannel(suite.path) - - origTime := suite.consumerChain.GetContext().BlockTime() - - pk1, err := cryptocodec.ToTmProtoPublicKey(ed25519.GenPrivKey().PubKey()) - suite.Require().NoError(err) - pk2, err := cryptocodec.ToTmProtoPublicKey(ed25519.GenPrivKey().PubKey()) - suite.Require().NoError(err) - pd := ccv.NewValidatorSetChangePacketData( - []abci.ValidatorUpdate{ - { - PubKey: pk1, - Power: 30, - }, - { - PubKey: pk2, - Power: 20, - }, - }, - 1, - nil, - ) - packet := channeltypes.NewPacket(pd.GetBytes(), 1, - ccv.ProviderPortID, suite.path.EndpointB.ChannelID, - ccv.ConsumerPortID, suite.path.EndpointA.ChannelID, - clienttypes.NewHeight(1, 0), 0) - consumerKeeper.OnRecvVSCPacket(suite.consumerChain.GetContext(), packet, pd) - valUpdates := tmtypes.TM2PB.ValidatorUpdates(suite.providerChain.Vals) - - restartGenesis := consumerKeeper.ExportGenesis(suite.consumerChain.GetContext()) - suite.Require().Equal(valUpdates, restartGenesis.InitialValSet) - - // ensure reset genesis is set correctly - providerChannel := suite.path.EndpointA.ChannelID - suite.Require().Equal(providerChannel, restartGenesis.ProviderChannelId) - maturityTime := consumerKeeper.GetPacketMaturityTime(suite.consumerChain.GetContext(), 1) - unbondingPeriod := consumerKeeper.GetUnbondingPeriod(suite.consumerCtx()) - suite.Require().Equal(uint64(origTime.Add(unbondingPeriod).UnixNano()), maturityTime, "maturity time is not set correctly in genesis") - - suite.Require().NotPanics(func() { - consumerKeeper.InitGenesis(suite.consumerChain.GetContext(), restartGenesis) - }) -} - // TestInitTimeout tests the init timeout func (suite *CCVTestSuite) TestInitTimeout() { testCases := []struct { @@ -144,11 +63,9 @@ func (suite *CCVTestSuite) TestInitTimeout() { initTimeout := providerKeeper.GetParams(suite.providerCtx()).InitTimeoutPeriod chainID := suite.consumerChain.ChainID - // get init timeout timestamp - ts, found := providerKeeper.GetInitTimeoutTimestamp(suite.providerCtx(), chainID) + // check that the init timeout timestamp is set + _, found := providerKeeper.GetInitTimeoutTimestamp(suite.providerCtx(), chainID) suite.Require().True(found, "cannot find init timeout timestamp; test: %s", tc.name) - expectedTs := suite.providerCtx().BlockTime().Add(initTimeout) - suite.Require().Equal(uint64(expectedTs.UnixNano()), ts, "unexpected init timeout timestamp; test: %s", tc.name) // create connection suite.coordinator.CreateConnections(suite.path) diff --git a/tests/e2e/common.go b/tests/e2e/common.go index ffd0e5473c..f0ecb629f1 100644 --- a/tests/e2e/common.go +++ b/tests/e2e/common.go @@ -189,6 +189,7 @@ func relayAllCommittedPackets( srcPortID string, srcChannelID string, expectedPackets int, + msgAndArgs ...interface{}, ) { // check that the packets are committed in state commitments := srcChain.App.GetIBCKeeper().ChannelKeeper.GetAllPacketCommitmentsAtChannel( @@ -196,18 +197,26 @@ func relayAllCommittedPackets( srcPortID, srcChannelID, ) - s.Require().Equal(expectedPackets, len(commitments), - "actual number of packet commitments does not match expectation") + s.Require().Equal( + expectedPackets, + len(commitments), + fmt.Sprintf("actual number of packet commitments does not match expectation; %s", msgAndArgs...), + ) // relay all packets from srcChain to counterparty for _, commitment := range commitments { // - get packets packet, found := srcChain.GetSentPacket(commitment.Sequence, srcChannelID) - s.Require().True(found, "did not find sent packet") - + s.Require().True( + found, + fmt.Sprintf("did not find sent packet; %s", msgAndArgs...), + ) // - relay the packet err := path.RelayPacket(packet) - s.Require().NoError(err) + s.Require().NoError( + err, + fmt.Sprintf("error while relaying packets; %s", msgAndArgs...), + ) } } diff --git a/tests/e2e/key_assignment.go b/tests/e2e/key_assignment.go new file mode 100644 index 0000000000..5987743cd4 --- /dev/null +++ b/tests/e2e/key_assignment.go @@ -0,0 +1,256 @@ +package e2e + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/ibc-go/v3/testing/mock" + providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + ccv "github.com/cosmos/interchain-security/x/ccv/types" + tmencoding "github.com/tendermint/tendermint/crypto/encoding" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" +) + +func (s *CCVTestSuite) TestKeyAssignment() { + testCases := []struct { + name string + assignFunc func(*providerkeeper.Keeper) error + expError bool + expPacketCount int + }{ + { + "assignment during channel init", func(pk *providerkeeper.Keeper) error { + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + + // check that a VSCPacket is queued + s.providerChain.NextBlock() + pendingPackets := pk.GetPendingPackets(s.providerCtx(), s.consumerChain.ChainID) + s.Require().Len(pendingPackets, 1) + + // establish CCV channel + s.SetupCCVChannel(s.path) + + return nil + }, false, 2, + }, + { + "assignment after channel init", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + return nil + }, false, 2, + }, + { + "assignment with power change", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + + // Bond some tokens on provider to change validator powers + bondAmt := sdk.NewInt(1000000) + delAddr := s.providerChain.SenderAccount.GetAddress() + delegate(s, delAddr, bondAmt) + + s.providerChain.NextBlock() + + return nil + }, false, 2, + }, + { + "double same-key assignment in same block", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + + // same key assignment + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + return nil + }, true, 2, + }, + { + "double key assignment in same block", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + + // same key assignment + validator, consumerKey = generateNewConsumerKey(s, 0) + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + return nil + }, false, 2, + }, + { + "double same-key assignment in different blocks", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + // same key assignment + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + return nil + }, true, 2, + }, + { + "double key assignment in different blocks", func(pk *providerkeeper.Keeper) error { + // establish CCV channel + s.SetupCCVChannel(s.path) + + // key assignment + validator, consumerKey := generateNewConsumerKey(s, 0) + err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + // same key assignment + validator, consumerKey = generateNewConsumerKey(s, 0) + err = pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + if err != nil { + return err + } + s.providerChain.NextBlock() + + return nil + }, false, 3, + }, + // TODO: this test should pass if we manage to change the client update mode to sequential + // { + // "key assignment for all validators in the same block", func(pk *providerkeeper.Keeper) error { + // // establish CCV channel + // s.SetupCCVChannel(s.path) + + // // key assignment + // for i, _ := range s.providerChain.Vals.Validators { + // validator, consumerKey := generateNewConsumerKey(s, i) + // err := pk.AssignConsumerKey(s.providerCtx(), s.consumerChain.ChainID, validator, consumerKey) + // if err != nil { + // return err + // } + // } + // // vscPakcketData := pk.GetPendingPackets(s.providerCtx(), s.consumerChain.ChainID) + // // s.Require().Len(vscPakcketData, 1) + // // s.Require().Len(vscPakcketData[0].ValidatorUpdates, 2*len(s.providerChain.Vals.Validators)) + + // s.providerChain.NextBlock() + + // return nil + // }, false, 2, + // }, + } + for i, tc := range testCases { + providerKeeper := s.providerApp.GetProviderKeeper() + + err := tc.assignFunc(&providerKeeper) + if tc.expError { + s.Require().Error(err, "test: "+tc.name) + } else { + s.Require().NoError(err, "test: "+tc.name) + } + + if !tc.expError { + // Bond some tokens on provider to change validator powers + bondAmt := sdk.NewInt(1000000) + delAddr := s.providerChain.SenderAccount.GetAddress() + delegate(s, delAddr, bondAmt) + + // Send CCV packet to consumer + s.providerChain.NextBlock() + + // Relay all VSC packets from provider to consumer + relayAllCommittedPackets( + s, + s.providerChain, + s.path, + ccv.ProviderPortID, + s.path.EndpointB.ChannelID, + tc.expPacketCount, + "test: "+tc.name, + ) + + // update clients + err := s.path.EndpointA.UpdateClient() + s.Require().NoError(err) + err = s.path.EndpointB.UpdateClient() + s.Require().NoError(err) + } + + if i+1 < len(testCases) { + // reset suite to reset provider client + s.SetupTest() + } + } +} + +// generateNewConsumerKey generate new consumer key for the validator with valIndex +func generateNewConsumerKey(s *CCVTestSuite, valIndex int) (stakingtypes.Validator, tmprotocrypto.PublicKey) { + // get validator + s.Require().Less(valIndex, len(s.providerChain.Vals.Validators)) + _, valAddr := s.getValByIdx(valIndex) + validator := s.getVal(s.providerCtx(), valAddr) + + // generate new PrivValidator + privVal := mock.NewPV() + tmPubKey, err := privVal.GetPubKey() + s.Require().NoError(err) + pubKey, err := tmencoding.PubKeyToProto(tmPubKey) + s.Require().NoError(err) + + // add Signer to the consumer chain + s.consumerChain.Signers[tmPubKey.Address().String()] = privVal + + return validator, pubKey +} diff --git a/tests/e2e/setup.go b/tests/e2e/setup.go index 5aff0578fc..18b3c0f295 100644 --- a/tests/e2e/setup.go +++ b/tests/e2e/setup.go @@ -1,33 +1,47 @@ package e2e import ( - "bytes" "testing" + sdk "github.com/cosmos/cosmos-sdk/types" ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" + "github.com/cosmos/ibc-go/v3/testing/mock" e2eutil "github.com/cosmos/interchain-security/testutil/e2e" + tmencoding "github.com/tendermint/tendermint/crypto/encoding" icstestingutils "github.com/cosmos/interchain-security/testutil/ibc_testing" + consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" - "github.com/cosmos/interchain-security/x/ccv/utils" transfertypes "github.com/cosmos/ibc-go/v3/modules/apps/transfer/types" - clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/stretchr/testify/suite" ) +// Callback for instantiating a new coordinator with a provider test chains +// and provider app before every test defined on the suite. +type SetupProviderCallback func(t *testing.T) ( + coord *ibctesting.Coordinator, + providerChain *ibctesting.TestChain, + providerApp e2eutil.ProviderApp, +) + +// Callback for instantiating a new consumer test chain +// and consumer app before every test defined on the suite. +type SetupConsumerCallback func(s *suite.Suite, coord *ibctesting.Coordinator, index int) ( + consumerBundle *icstestingutils.ConsumerBundle, +) + // CCVTestSuite is an in-mem test suite which implements the standard group of tests validating // the e2e functionality of ccv enabled chains. // Any method implemented for this struct will be ran when suite.Run() is called. type CCVTestSuite struct { suite.Suite - coordinator *ibctesting.Coordinator - setupCallback SetupCallback + coordinator *ibctesting.Coordinator + setupProviderCallback SetupProviderCallback + setupConsumerCallback SetupConsumerCallback providerChain *ibctesting.TestChain providerApp e2eutil.ProviderApp @@ -53,30 +67,29 @@ func NewCCVTestSuite[Tp e2eutil.ProviderApp, Tc e2eutil.ConsumerApp]( ccvSuite := new(CCVTestSuite) - // Define callback called before each test. - ccvSuite.setupCallback = func(t *testing.T) ( + // Define callback to set up the provider chain + ccvSuite.setupProviderCallback = func(t *testing.T) ( *ibctesting.Coordinator, *ibctesting.TestChain, e2eutil.ProviderApp, - map[string]*icstestingutils.ConsumerBundle, ) { // Instantiate the test coordinator. coordinator := ibctesting.NewCoordinator(t, 0) // Add provider to coordinator, store returned test chain and app. // Concrete provider app type is passed to the generic function here. - provider, providerApp := icstestingutils.AddProvider[Tp]( - coordinator, t, providerAppIniter) - - numConsumers := 5 - - // Add specified number of consumers to coordinator, store returned test chains and apps. - // Concrete consumer app type is passed to the generic function here. - consumerBundles := icstestingutils.AddConsumers[Tc]( - coordinator, t, numConsumers, consumerAppIniter) + provider, providerApp := icstestingutils.AddProvider[Tp](coordinator, t, providerAppIniter) // Pass variables to suite. - return coordinator, provider, providerApp, consumerBundles + return coordinator, provider, providerApp + } + + ccvSuite.setupConsumerCallback = func( + s *suite.Suite, + coordinator *ibctesting.Coordinator, + index int, + ) *icstestingutils.ConsumerBundle { + return icstestingutils.AddConsumer[Tp, Tc](coordinator, s, index, consumerAppIniter) } ccvSuite.skippedTests = make(map[string]bool) @@ -86,15 +99,6 @@ func NewCCVTestSuite[Tp e2eutil.ProviderApp, Tc e2eutil.ConsumerApp]( return ccvSuite } -// Callback for instantiating a new coordinator, provider/consumer test chains, and provider/consumer apps -// before every test defined on the suite. -type SetupCallback func(t *testing.T) ( - coord *ibctesting.Coordinator, - providerChain *ibctesting.TestChain, - providerApp e2eutil.ProviderApp, - consumerBundles map[string]*icstestingutils.ConsumerBundle, -) - func (suite *CCVTestSuite) BeforeTest(suiteName, testName string) { if suite.skippedTests[testName] { suite.T().Skip() @@ -103,109 +107,127 @@ func (suite *CCVTestSuite) BeforeTest(suiteName, testName string) { // SetupTest sets up in-mem state before every test func (suite *CCVTestSuite) SetupTest() { - - // Instantiate new test utils using callback + // Instantiate new coordinator and provider chain using callback suite.coordinator, suite.providerChain, - suite.providerApp, suite.consumerBundles = suite.setupCallback(suite.T()) - - // valsets must match between provider and all consumers - for _, bundle := range suite.consumerBundles { - - providerValUpdates := tmtypes.TM2PB.ValidatorUpdates(suite.providerChain.Vals) - consumerValUpdates := tmtypes.TM2PB.ValidatorUpdates(bundle.Chain.Vals) - suite.Require().True(len(providerValUpdates) == len(consumerValUpdates), "initial valset not matching") - for i := 0; i < len(providerValUpdates); i++ { - addr1 := utils.GetChangePubKeyAddress(providerValUpdates[i]) - addr2 := utils.GetChangePubKeyAddress(consumerValUpdates[i]) - suite.Require().True(bytes.Equal(addr1, addr2), "validator mismatch") - } - // Move each consumer to next block - bundle.Chain.NextBlock() - } - - // move provider to next block - suite.providerChain.NextBlock() - + suite.providerApp = suite.setupProviderCallback(suite.T()) providerKeeper := suite.providerApp.GetProviderKeeper() - for chainID, bundle := range suite.consumerBundles { - // For each consumer, create client to that consumer on the provider chain. - err := providerKeeper.CreateConsumerClient( - suite.providerCtx(), - chainID, - bundle.Chain.LastHeader.GetHeight().(clienttypes.Height), - false, - ) - suite.Require().NoError(err) - } + // re-assign all validator keys for the first consumer chain + preProposalKeyAssignment(suite, icstestingutils.FirstConsumerChainID) - // move provider to next block to commit the state - suite.providerChain.NextBlock() + // start consumer chains + numConsumers := 5 + suite.consumerBundles = make(map[string]*icstestingutils.ConsumerBundle) + for i := 0; i < numConsumers; i++ { + bundle := suite.setupConsumerCallback(&suite.Suite, suite.coordinator, i) + suite.consumerBundles[bundle.Chain.ChainID] = bundle + } // initialize each consumer chain with it's corresponding genesis state // stored on the provider. - for chainID, bundle := range suite.consumerBundles { - + for chainID := range suite.consumerBundles { consumerGenesisState, found := providerKeeper.GetConsumerGenesis( suite.providerCtx(), chainID, ) suite.Require().True(found, "consumer genesis not found") + initConsumerChain(suite, chainID, &consumerGenesisState) + } + + // try updating all clients + for _, bundle := range suite.consumerBundles { + // try updating this consumer client on the provider chain + err := bundle.Path.EndpointB.UpdateClient() + suite.Require().NoError(err) + + // try updating the provider client on this consumer chain + err = bundle.Path.EndpointA.UpdateClient() + suite.Require().NoError(err) + } +} + +// initConsumerChain initializes a consumer chain given a genesis state +func initConsumerChain( + s *CCVTestSuite, + chainID string, + genesisState *consumertypes.GenesisState, +) { + providerKeeper := s.providerApp.GetProviderKeeper() + bundle := s.consumerBundles[chainID] + + // run CCV module init genesis + s.NotPanics(func() { consumerKeeper := bundle.GetKeeper() - consumerKeeper.InitGenesis(bundle.GetCtx(), &consumerGenesisState) + consumerKeeper.InitGenesis(bundle.GetCtx(), genesisState) + }) - // Confirm client and cons state for consumer were set correctly in InitGenesis + // confirm client and cons state for consumer were set correctly in InitGenesis; + // NOTE: on restart, both ProviderClientState and ProviderConsensusState are nil + if genesisState.NewChain { consumerEndpointClientState, - consumerEndpointConsState := suite.GetConsumerEndpointClientAndConsState(*bundle) - suite.Require().Equal(consumerGenesisState.ProviderClientState, consumerEndpointClientState) - suite.Require().Equal(consumerGenesisState.ProviderConsensusState, consumerEndpointConsState) + consumerEndpointConsState := s.GetConsumerEndpointClientAndConsState(*bundle) + s.Require().Equal(genesisState.ProviderClientState, consumerEndpointClientState) + s.Require().Equal(genesisState.ProviderConsensusState, consumerEndpointConsState) + } - // create path for the CCV channel - bundle.Path = ibctesting.NewPath(bundle.Chain, suite.providerChain) + // create path for the CCV channel + bundle.Path = ibctesting.NewPath(bundle.Chain, s.providerChain) - // Set provider endpoint's clientID for each consumer - providerEndpointClientID, found := providerKeeper.GetConsumerClientId( - suite.providerCtx(), - chainID, - ) - suite.Require().True(found, "provider endpoint clientID not found") - bundle.Path.EndpointB.ClientID = providerEndpointClientID - - // Set consumer endpoint's clientID - consumerKeeper = bundle.GetKeeper() - consumerEndpointClientID, found := consumerKeeper.GetProviderClientID(bundle.GetCtx()) - suite.Require().True(found, "consumer endpoint clientID not found") - bundle.Path.EndpointA.ClientID = consumerEndpointClientID - - // Note: suite.path.EndpointA.ClientConfig and suite.path.EndpointB.ClientConfig are not populated, - // since these IBC testing package fields are unused in our tests. - - // Confirm client config is now correct - suite.ValidateEndpointsClientConfig(*bundle) - - // - channel config - bundle.Path.EndpointA.ChannelConfig.PortID = ccv.ConsumerPortID - bundle.Path.EndpointB.ChannelConfig.PortID = ccv.ProviderPortID - bundle.Path.EndpointA.ChannelConfig.Version = ccv.Version - bundle.Path.EndpointB.ChannelConfig.Version = ccv.Version - bundle.Path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED - bundle.Path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED - - // create path for the transfer channel - bundle.TransferPath = ibctesting.NewPath(bundle.Chain, suite.providerChain) - bundle.TransferPath.EndpointA.ChannelConfig.PortID = transfertypes.PortID - bundle.TransferPath.EndpointB.ChannelConfig.PortID = transfertypes.PortID - bundle.TransferPath.EndpointA.ChannelConfig.Version = transfertypes.Version - bundle.TransferPath.EndpointB.ChannelConfig.Version = transfertypes.Version + // Set provider endpoint's clientID for each consumer + providerEndpointClientID, found := providerKeeper.GetConsumerClientId( + s.providerCtx(), + chainID, + ) + s.Require().True(found, "provider endpoint clientID not found") + bundle.Path.EndpointB.ClientID = providerEndpointClientID + + // Set consumer endpoint's clientID + consumerKeeper := bundle.GetKeeper() + consumerEndpointClientID, found := consumerKeeper.GetProviderClientID(bundle.GetCtx()) + s.Require().True(found, "consumer endpoint clientID not found") + bundle.Path.EndpointA.ClientID = consumerEndpointClientID + + // Note: suite.path.EndpointA.ClientConfig and suite.path.EndpointB.ClientConfig are not populated, + // since these IBC testing package fields are unused in our tests. + + // Confirm client config is now correct + s.validateEndpointsClientConfig(*bundle) + + // - channel config + bundle.Path.EndpointA.ChannelConfig.PortID = ccv.ConsumerPortID + bundle.Path.EndpointB.ChannelConfig.PortID = ccv.ProviderPortID + bundle.Path.EndpointA.ChannelConfig.Version = ccv.Version + bundle.Path.EndpointB.ChannelConfig.Version = ccv.Version + bundle.Path.EndpointA.ChannelConfig.Order = channeltypes.ORDERED + bundle.Path.EndpointB.ChannelConfig.Order = channeltypes.ORDERED + + // create path for the transfer channel + bundle.TransferPath = ibctesting.NewPath(bundle.Chain, s.providerChain) + bundle.TransferPath.EndpointA.ChannelConfig.PortID = transfertypes.PortID + bundle.TransferPath.EndpointB.ChannelConfig.PortID = transfertypes.PortID + bundle.TransferPath.EndpointA.ChannelConfig.Version = transfertypes.Version + bundle.TransferPath.EndpointB.ChannelConfig.Version = transfertypes.Version + + // commit state on this consumer chain + s.coordinator.CommitBlock(bundle.Chain) + + // try updating this consumer client on the provider chain + err := bundle.Path.EndpointB.UpdateClient() + s.Require().NoError(err) + + // try updating the provider client on this consumer chain + err = bundle.Path.EndpointA.UpdateClient() + s.Require().NoError(err) + + if chainID == icstestingutils.FirstConsumerChainID { + // Support tests that were written before multiple consumers were supported. + firstBundle := s.getFirstBundle() + s.consumerApp = firstBundle.App + s.consumerChain = firstBundle.Chain + s.path = firstBundle.Path + s.transferPath = firstBundle.TransferPath } - - // Support tests that were written before multiple consumers were supported. - firstBundle := suite.getFirstBundle() - suite.consumerApp = firstBundle.App - suite.consumerChain = firstBundle.Chain - suite.path = firstBundle.Path - suite.transferPath = firstBundle.TransferPath } func (suite *CCVTestSuite) SetupAllCCVChannels() { @@ -215,11 +237,6 @@ func (suite *CCVTestSuite) SetupAllCCVChannels() { } func (suite *CCVTestSuite) SetupCCVChannel(path *ibctesting.Path) { - suite.StartSetupCCVChannel(path) - suite.CompleteSetupCCVChannel(path) -} - -func (suite *CCVTestSuite) StartSetupCCVChannel(path *ibctesting.Path) { suite.coordinator.CreateConnections(path) err := path.EndpointA.ChanOpenInit() @@ -227,10 +244,8 @@ func (suite *CCVTestSuite) StartSetupCCVChannel(path *ibctesting.Path) { err = path.EndpointB.ChanOpenTry() suite.Require().NoError(err) -} -func (suite *CCVTestSuite) CompleteSetupCCVChannel(path *ibctesting.Path) { - err := path.EndpointA.ChanOpenAck() + err = path.EndpointA.ChanOpenAck() suite.Require().NoError(err) err = path.EndpointB.ChanOpenConfirm() @@ -272,7 +287,7 @@ func (suite *CCVTestSuite) SetupTransferChannel() { suite.Require().NoError(err) } -func (s CCVTestSuite) ValidateEndpointsClientConfig(consumerBundle icstestingutils.ConsumerBundle) { +func (s CCVTestSuite) validateEndpointsClientConfig(consumerBundle icstestingutils.ConsumerBundle) { consumerKeeper := consumerBundle.GetKeeper() providerStakingKeeper := s.providerApp.GetStakingKeeper() @@ -296,3 +311,31 @@ func (s CCVTestSuite) ValidateEndpointsClientConfig(consumerBundle icstestinguti "unexpected unbonding period in provider client state", ) } + +// preProposalKeyAssignment assigns keys to all provider validators for +// the consumer with chainID before the chain is registered, i.e., +// before a client to the consumer is created +func preProposalKeyAssignment(s *CCVTestSuite, chainID string) { + providerKeeper := s.providerApp.GetProviderKeeper() + + for _, val := range s.providerChain.Vals.Validators { + // get SDK validator + valAddr, err := sdk.ValAddressFromHex(val.Address.String()) + s.Require().NoError(err) + validator := s.getVal(s.providerCtx(), valAddr) + + // generate new PrivValidator + privVal := mock.NewPV() + tmPubKey, err := privVal.GetPubKey() + s.Require().NoError(err) + consumerKey, err := tmencoding.PubKeyToProto(tmPubKey) + s.Require().NoError(err) + + // add Signer to the provider chain as there is no consumer chain to add it; + // as a result, NewTestChainWithValSet in AddConsumer uses providerChain.Signers + s.providerChain.Signers[tmPubKey.Address().String()] = privVal + + err = providerKeeper.AssignConsumerKey(s.providerCtx(), chainID, validator, consumerKey) + s.Require().NoError(err) + } +} diff --git a/tests/e2e/slashing.go b/tests/e2e/slashing.go index 79daa8f9ea..5951920dfd 100644 --- a/tests/e2e/slashing.go +++ b/tests/e2e/slashing.go @@ -61,6 +61,14 @@ func (s *CCVTestSuite) TestRelayAndApplySlashPacket() { pubkey, err := cryptocodec.FromTmProtoPublicKey(val.GetPubKey()) s.Require().Nil(err) consAddr := sdk.GetConsAddress(pubkey) + // map consumer consensus address to provider consensus address + if providerAddr, found := providerKeeper.GetValidatorByConsumerAddr( + s.providerCtx(), + s.consumerChain.ChainID, + consAddr, + ); found { + consAddr = providerAddr + } valData, found := providerStakingKeeper.GetValidatorByConsAddr(s.providerCtx(), consAddr) s.Require().True(found) valOldBalance := valData.Tokens diff --git a/tests/integration/actions.go b/tests/integration/actions.go index 9e4d26a4b0..3c91e132e1 100644 --- a/tests/integration/actions.go +++ b/tests/integration/actions.go @@ -13,6 +13,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" "github.com/cosmos/interchain-security/x/ccv/provider/client" + "github.com/tidwall/gjson" ) type SendTokensAction struct { @@ -79,6 +80,10 @@ func (tr TestRun) startChain( PrivValidatorKey string `json:"priv_validator_key"` NodeKey string `json:"node_key"` IpSuffix string `json:"ip_suffix"` + + ConsumerMnemonic string `json:"consumer_mnemonic"` + ConsumerPrivValidatorKey string `json:"consumer_priv_validator_key"` + StartWithConsumerKey bool `json:"start_with_consumer_key"` } var validators []jsonValAttrs @@ -91,6 +96,11 @@ func (tr TestRun) startChain( Allocation: fmt.Sprint(val.allocation) + "stake", Stake: fmt.Sprint(val.stake) + "stake", IpSuffix: tr.validatorConfigs[val.id].ipSuffix, + + ConsumerMnemonic: tr.validatorConfigs[val.id].consumerMnemonic, + ConsumerPrivValidatorKey: tr.validatorConfigs[val.id].consumerPrivValidatorKey, + // if true node will be started with consumer key for each consumer chain + StartWithConsumerKey: tr.validatorConfigs[val.id].useConsumerKey, }) } @@ -786,11 +796,16 @@ func (tr TestRun) delegateTokens( action delegateTokensAction, verbose bool, ) { + toValCfg := tr.validatorConfigs[action.to] + delegateAddr := toValCfg.valoperAddress + if action.chain != chainID("provi") && toValCfg.useConsumerKey { + delegateAddr = toValCfg.consumerValoperAddress + } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, "tx", "staking", "delegate", - tr.validatorConfigs[action.to].valoperAddress, + delegateAddr, fmt.Sprint(action.amount)+`stake`, `--from`, `validator`+fmt.Sprint(action.from), @@ -822,11 +837,16 @@ func (tr TestRun) unbondTokens( action unbondTokensAction, verbose bool, ) { + unbondFrom := tr.validatorConfigs[action.unbondFrom].valoperAddress + if tr.validatorConfigs[action.unbondFrom].useConsumerKey { + unbondFrom = tr.validatorConfigs[action.unbondFrom].consumerValoperAddress + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, "tx", "staking", "unbond", - tr.validatorConfigs[action.unbondFrom].valoperAddress, + unbondFrom, fmt.Sprint(action.amount)+`stake`, `--from`, `validator`+fmt.Sprint(action.sender), @@ -857,14 +877,26 @@ type redelegateTokensAction struct { } func (tr TestRun) redelegateTokens(action redelegateTokensAction, verbose bool) { + srcCfg := tr.validatorConfigs[action.src] + dstCfg := tr.validatorConfigs[action.dst] + + redelegateSrc := srcCfg.valoperAddress + if action.chain != chainID("provi") && srcCfg.useConsumerKey { + redelegateSrc = srcCfg.consumerValoperAddress + } + + redelegateDst := dstCfg.valoperAddress + if action.chain != chainID("provi") && dstCfg.useConsumerKey { + redelegateDst = dstCfg.consumerValoperAddress + } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[action.chain].binaryName, "tx", "staking", "redelegate", - tr.validatorConfigs[action.src].valoperAddress, - tr.validatorConfigs[action.dst].valoperAddress, + redelegateSrc, + redelegateDst, fmt.Sprint(action.amount)+`stake`, `--from`, `validator`+fmt.Sprint(action.txSender), `--chain-id`, string(tr.chainConfigs[action.chain].chainId), @@ -896,7 +928,7 @@ func (tr TestRun) invokeDowntimeSlash(action downtimeSlashAction, verbose bool) // Bring validator down tr.setValidatorDowntime(action.chain, action.validator, true, verbose) // Wait appropriate amount of blocks for validator to be slashed - tr.waitBlocks(action.chain, 3, time.Minute) + tr.waitBlocks(action.chain, 15, time.Minute) // Bring validator back up tr.setValidatorDowntime(action.chain, action.validator, false, verbose) } @@ -1055,3 +1087,105 @@ func (tr TestRun) invokeDoublesignSlash( } tr.waitBlocks("provi", 10, 2*time.Minute) } + +type assignConsumerPubKeyAction struct { + chain chainID + validator validatorID + consumerPubkey string + // reconfigureNode will change keys the node uses and restart + reconfigureNode bool + // executing the action should raise an error + expectError bool +} + +func (tr TestRun) assignConsumerPubKey(action assignConsumerPubKeyAction, verbose bool) { + valCfg := tr.validatorConfigs[action.validator] + + assignKey := fmt.Sprintf( + `%s tx provider assign-consensus-key %s '%s' --from validator%s --chain-id %s --home %s --node %s --gas 900000 --keyring-backend test -b block -y -o json`, + tr.chainConfigs[chainID("provi")].binaryName, + string(tr.chainConfigs[action.chain].chainId), + action.consumerPubkey, + action.validator, + tr.chainConfigs[chainID("provi")].chainId, + tr.getValidatorHome(chainID("provi"), action.validator), + tr.getValidatorNode(chainID("provi"), action.validator), + ) + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", + tr.containerConfig.instanceName, + "/bin/bash", "-c", + assignKey, + ) + + if verbose { + fmt.Println("assignConsumerPubKey cmd:", cmd.String()) + } + + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + jsonStr := string(bz) + code := gjson.Get(jsonStr, "code") + rawLog := gjson.Get(jsonStr, "raw_log") + if !action.expectError && code.Int() != 0 { + log.Fatalf("unexpected error during key assignment - code: %s, output: %s", code, jsonStr) + } + + if action.expectError { + if code.Int() == 0 { + } else if verbose { + fmt.Printf("got expected error during key assignment | code: %v | log: %s\n", code, rawLog) + } + } + + // node was started with provider key + // we swap the nodes's keys for consumer keys and restart it + if action.reconfigureNode { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + configureNodeCmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, "/bin/bash", + "/testnet-scripts/reconfigure-node.sh", tr.chainConfigs[action.chain].binaryName, + string(action.validator), string(action.chain), + tr.chainConfigs[action.chain].ipPrefix, valCfg.ipSuffix, + valCfg.consumerMnemonic, valCfg.consumerPrivValidatorKey, + valCfg.consumerNodeKey, + ) + + if verbose { + fmt.Println("assignConsumerPubKey - reconfigure node cmd:", configureNodeCmd.String()) + } + + cmdReader, err := configureNodeCmd.StdoutPipe() + if err != nil { + log.Fatal(err) + } + configureNodeCmd.Stderr = configureNodeCmd.Stdout + + if err := configureNodeCmd.Start(); err != nil { + log.Fatal(err) + } + + scanner := bufio.NewScanner(cmdReader) + + for scanner.Scan() { + out := scanner.Text() + if verbose { + fmt.Println("assign key - reconfigure: " + out) + } + if out == "done!!!!!!!!" { + break + } + } + if err := scanner.Err(); err != nil { + log.Fatal(err) + } + + // TODO: @MSalopek refactor this so test config is not changed at runtime + // make the validator use consumer key + valCfg.useConsumerKey = true + tr.validatorConfigs[action.validator] = valCfg + } + +} diff --git a/tests/integration/config.go b/tests/integration/config.go index 5bbc424959..f48400e09f 100644 --- a/tests/integration/config.go +++ b/tests/integration/config.go @@ -19,8 +19,19 @@ type ValidatorConfig struct { valconsAddress string privValidatorKey string nodeKey string - // Must be an integer greater than 0 and less than 254 + // Must be an integer greater than 0 and less than 253 ipSuffix string + + // consumer chain key assignment data + // keys are used on a new node + consumerMnemonic string + consumerDelAddress string + consumerValoperAddress string + consumerValconsAddress string + consumerValPubKey string + consumerPrivValidatorKey string + consumerNodeKey string + useConsumerKey bool // if true the validator node will start with consumer key } // Attributes that are unique to a chain. Allows us to map (part of) @@ -65,6 +76,16 @@ func getDefaultValidators() map[validatorID]ValidatorConfig { privValidatorKey: `{"address":"06C0F3E47CC5C748269088DC2F36411D3AAA27C6","pub_key":{"type":"tendermint/PubKeyEd25519","value":"RrclQz9bIhkIy/gfL485g3PYMeiIku4qeo495787X10="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uX+ZpDMg89a6gtqs/+MQpCTSqlkZ0nJQJOhLlCJvwvdGtyVDP1siGQjL+B8vjzmDc9gx6IiS7ip6jj3nvztfXQ=="}}`, nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"fjw4/DAhyRPnwKgXns5SV7QfswRSXMWJpHS7TyULDmJ8ofUc5poQP8dgr8bZRbCV5RV8cPqDq3FPdqwpmUbmdA=="}}`, ipSuffix: "4", + + // consumer chain assigned key + consumerMnemonic: "exile install vapor thing little toss immune notable lounge december final easy strike title end program interest quote cloth forget forward job october twenty", + consumerDelAddress: "cosmos1eeeggku6dzk3mv7wph3zq035rhtd890sjswszd", + consumerValoperAddress: "cosmosvaloper1eeeggku6dzk3mv7wph3zq035rhtd890shy69w7", + consumerValconsAddress: "cosmosvalcons1muys5jyqk4xd27e208nym85kn0t4zjcfeu63fe", + consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="}`, + consumerPrivValidatorKey: `{"address":"DF090A4880B54CD57B2A79E64D9E969BD7514B09","pub_key":{"type":"tendermint/PubKeyEd25519","value":"ujY14AgopV907IYgPAk/5x8c9267S4fQf89nyeCPTes="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TRJgf7lkTjs/sj43pyweEOanyV7H7fhnVivOi0A4yjW6NjXgCCilX3TshiA8CT/nHxz3brtLh9B/z2fJ4I9N6w=="}}`, + consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"F966RL9pi20aXRzEBe4D0xRQJtZt696Xxz44XUON52cFc83FMn1WXJbP6arvA2JPyn2LA3DLKCFHSgALrCGXGA=="}}`, + useConsumerKey: false, }, validatorID("bob"): { mnemonic: "glass trip produce surprise diamond spin excess gaze wash drum human solve dress minor artefact canoe hard ivory orange dinner hybrid moral potato jewel", @@ -74,6 +95,16 @@ func getDefaultValidators() map[validatorID]ValidatorConfig { privValidatorKey: `{"address":"99BD3A72EF12CD024E7584B3AC900AE3743C6ADF","pub_key":{"type":"tendermint/PubKeyEd25519","value":"mAN6RXYxSM4MNGSIriYiS7pHuwAcOHDQAy9/wnlSzOI="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"QePcwfWtOavNK7pBJrtoLMzarHKn6iBWfWPFeyV+IdmYA3pFdjFIzgw0ZIiuJiJLuke7ABw4cNADL3/CeVLM4g=="}}`, nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"TQ4vHcO/vKdzGtWpelkX53WdMQd4kTsWGFrdcatdXFvWyO215Rewn5IRP0FszPLWr2DqPzmuH8WvxYGk5aeOXw=="}}`, ipSuffix: "5", + + // consumer chain assigned key + consumerMnemonic: "grunt list hour endless observe better spoil penalty lab duck only layer vague fantasy satoshi record demise topple space shaft solar practice donor sphere", + consumerDelAddress: "cosmos1q90l6j6lzzgt460ehjj56azknlt5yrd4s38n97", + consumerValoperAddress: "cosmosvaloper1q90l6j6lzzgt460ehjj56azknlt5yrd449nxfd", + consumerValconsAddress: "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, + consumerPrivValidatorKey: `{"address":"E73388E246EC9945E5E70A94FE4072BD937415C4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"OFR4w+FC6EMw5fAGTrHVexyPrjzQ7QfqgZOMgVf0izlCUb6Jh7oDJim9jXP1E0koJWUfXhD+pLPgSMZ0YKu7eg=="}}`, + consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"uhPCqnL2KE8m/8OFNLQ5bN3CJr6mds+xfBi0E4umT/s2uWiJhet+vbYx88DHSdof3gGFNTIzAIxSppscBKX96w=="}}`, + useConsumerKey: false, }, validatorID("carol"): { mnemonic: "sight similar better jar bitter laptop solve fashion father jelly scissors chest uniform play unhappy convince silly clump another conduct behave reunion marble animal", @@ -83,6 +114,55 @@ func getDefaultValidators() map[validatorID]ValidatorConfig { privValidatorKey: `{"address":"C888306A908A217B9A943D1DAD8790044D0947A4","pub_key":{"type":"tendermint/PubKeyEd25519","value":"IHo4QEikWZfIKmM0X+N+BjKttz8HOzGs2npyjiba3Xk="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"z08bmSB91uFVpVmR3t2ewd/bDjZ/AzwQpe5rKjWiPG0gejhASKRZl8gqYzRf434GMq23Pwc7MazaenKOJtrdeQ=="}}`, nodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"WLTcHEjbwB24Wp3z5oBSYTvtGQonz/7IQabOFw85BN0UkkyY5HDf38o8oHlFxVI26f+DFVeICuLbe9aXKGnUeg=="}}`, ipSuffix: "6", + + // consumer chain assigned key + consumerMnemonic: "clip choose cake west range gun slam cry village receive juice galaxy lend ritual range provide ritual can since verify breeze vacant play dragon", + consumerDelAddress: "cosmos1sx6j9g2rh324a342a5f0rnx7me34r9nwgf0mc7", + consumerValoperAddress: "cosmosvaloper1sx6j9g2rh324a342a5f0rnx7me34r9nwdamw5d", + consumerValconsAddress: "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + consumerValPubKey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + consumerPrivValidatorKey: `{"address":"B41C3A40142963AA5B12DDD1C4E5890C0B3926B1","pub_key":{"type":"tendermint/PubKeyEd25519","value":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="},"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"3YaBAZLA+sl/E73lLfbFbG0u6DYm33ayr/0UpCt/vFBSLkZ/X6a1ZR0fy7fGWbN0ogP4Xc8rSx9dnvcZnqrqKw=="}}`, + consumerNodeKey: `{"priv_key":{"type":"tendermint/PrivKeyEd25519","value":"rxBzFedtD3pqgfJQblbxGusKOr47oBfr8ba0Iz14gobtDRZQZlSZ/UGP4pSHkVf+4vtkrkO1vRHBYJobuiP+7A=="}}`, + useConsumerKey: true, + }, + } +} + +func KeyAssignmentTestRun() TestRun { + return TestRun{ + name: "key-assignment", + containerConfig: ContainerConfig{ + containerName: "interchain-security-keys-container", + instanceName: "interchain-security-keys-instance", + ccvVersion: "1", + now: time.Now(), + }, + validatorConfigs: getDefaultValidators(), + chainConfigs: map[chainID]ChainConfig{ + chainID("provi"): { + chainId: chainID("provi"), + binaryName: "interchain-security-pd", + ipPrefix: "7.7.7", + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + // Custom slashing parameters for testing validator downtime functionality + // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", + }, + chainID("consu"): { + chainId: chainID("consu"), + binaryName: "interchain-security-cd", + ipPrefix: "7.7.8", + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + ".app_state.slashing.params.signed_blocks_window = \"200\" | " + + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", + }, }, } } @@ -102,8 +182,8 @@ func DefaultTestRun() TestRun { chainId: chainID("provi"), binaryName: "interchain-security-pd", ipPrefix: "7.7.7", - votingWaitTime: 5, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"5s\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"2\" | " + @@ -115,9 +195,9 @@ func DefaultTestRun() TestRun { chainId: chainID("consu"), binaryName: "interchain-security-cd", ipPrefix: "7.7.8", - votingWaitTime: 10, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + - ".app_state.slashing.params.signed_blocks_window = \"2\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + + ".app_state.slashing.params.signed_blocks_window = \"20\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + ".app_state.slashing.params.slash_fraction_downtime = \"0.010000000000000000\"", @@ -141,8 +221,8 @@ func DemocracyTestRun() TestRun { chainId: chainID("provi"), binaryName: "interchain-security-pd", ipPrefix: "7.7.7", - votingWaitTime: 5, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"5s\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"2\" | " + @@ -154,8 +234,8 @@ func DemocracyTestRun() TestRun { chainId: chainID("democ"), binaryName: "interchain-security-cdd", ipPrefix: "7.7.9", - votingWaitTime: 10, - genesisChanges: ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"10\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.ccvconsumer.params.blocks_per_distribution_transmission = \"20\" | " + ".app_state.gov.voting_params.voting_period = \"10s\" | " + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + @@ -181,8 +261,8 @@ func MultiConsumerTestRun() TestRun { chainId: chainID("provi"), binaryName: "interchain-security-pd", ipPrefix: "7.7.7", - votingWaitTime: 5, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"5s\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + // Custom slashing parameters for testing validator downtime functionality // See https://docs.cosmos.network/main/modules/slashing/04_begin_block.html#uptime-tracking ".app_state.slashing.params.signed_blocks_window = \"2\" | " + @@ -194,8 +274,8 @@ func MultiConsumerTestRun() TestRun { chainId: chainID("consu"), binaryName: "interchain-security-cd", ipPrefix: "7.7.8", - votingWaitTime: 10, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + @@ -205,8 +285,8 @@ func MultiConsumerTestRun() TestRun { chainId: chainID("densu"), binaryName: "interchain-security-cd", ipPrefix: "7.7.9", - votingWaitTime: 10, - genesisChanges: ".app_state.gov.voting_params.voting_period = \"10s\" | " + + votingWaitTime: 20, + genesisChanges: ".app_state.gov.voting_params.voting_period = \"20s\" | " + ".app_state.slashing.params.signed_blocks_window = \"2\" | " + ".app_state.slashing.params.min_signed_per_window = \"0.500000000000000000\" | " + ".app_state.slashing.params.downtime_jail_duration = \"2s\" | " + diff --git a/tests/integration/main.go b/tests/integration/main.go index a07043a46b..baaa510cd1 100644 --- a/tests/integration/main.go +++ b/tests/integration/main.go @@ -14,6 +14,7 @@ import ( ) var verbose = flag.Bool("verbose", false, "turn verbose logging on/off") +var multiconsumer = flag.Bool("multiconsumer", false, "run happy path and multiconsumer tests in parallel") var localSdkPath = flag.String("local-sdk-path", "", "path of a local sdk version to build and reference in integration tests") @@ -37,10 +38,15 @@ func main() { dmc.ValidateStringLiterals() dmc.startDocker() - mul := MultiConsumerTestRun() - mul.SetLocalSDKPath(*localSdkPath) - mul.ValidateStringLiterals() - mul.startDocker() + if *multiconsumer { + mul := MultiConsumerTestRun() + mul.SetLocalSDKPath(*localSdkPath) + mul.ValidateStringLiterals() + mul.startDocker() + + wg.Add(1) + go mul.ExecuteSteps(&wg, multipleConsumers) + } wg.Add(1) go tr.ExecuteSteps(&wg, happyPathSteps) @@ -48,9 +54,6 @@ func main() { wg.Add(1) go dmc.ExecuteSteps(&wg, democracySteps) - wg.Add(1) - go mul.ExecuteSteps(&wg, multipleConsumers) - wg.Wait() fmt.Printf("TOTAL TIME ELAPSED: %v\n", time.Since(start)) } @@ -99,6 +102,8 @@ func (tr *TestRun) runStep(step Step, verbose bool) { tr.invokeDoublesignSlash(action, verbose) case registerRepresentativeAction: tr.registerRepresentative(action, verbose) + case assignConsumerPubKeyAction: + tr.assignConsumerPubKey(action, verbose) default: log.Fatalf(fmt.Sprintf(`unknown action in testRun %s: %#v`, tr.name, action)) } diff --git a/tests/integration/state.go b/tests/integration/state.go index bfd16ca38e..a6cedfb233 100644 --- a/tests/integration/state.go +++ b/tests/integration/state.go @@ -23,6 +23,8 @@ type ChainState struct { Params *[]Param Rewards *Rewards ConsumerChains *map[chainID]bool + AssignedKeys *map[validatorID]string + ProviderKeys *map[validatorID]string // validatorID: validator provider key } type Proposal interface { @@ -130,6 +132,16 @@ func (tr TestRun) getChainState(chain chainID, modelState ChainState) ChainState chainState.ConsumerChains = &chains } + if modelState.AssignedKeys != nil { + assignedKeys := tr.getConsumerAddresses(chain, *modelState.AssignedKeys) + chainState.AssignedKeys = &assignedKeys + } + + if modelState.ProviderKeys != nil { + providerKeys := tr.getProviderAddresses(chain, *modelState.ProviderKeys) + chainState.ProviderKeys = &providerKeys + } + return chainState } @@ -236,11 +248,16 @@ func (tr TestRun) getRewards(chain chainID, modelState Rewards) Rewards { } func (tr TestRun) getReward(chain chainID, validator validatorID, blockHeight uint, isNativeDenom bool) float64 { + + delAddresss := tr.validatorConfigs[validator].delAddress + if chain != chainID("provi") && tr.validatorConfigs[validator].useConsumerKey { + delAddresss = tr.validatorConfigs[validator].consumerDelAddress + } //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, "query", "distribution", "rewards", - tr.validatorConfigs[validator].delAddress, + delAddresss, `--height`, fmt.Sprint(blockHeight), `--node`, tr.getQueryNode(chain), @@ -260,11 +277,17 @@ func (tr TestRun) getReward(chain chainID, validator validatorID, blockHeight ui } func (tr TestRun) getBalance(chain chainID, validator validatorID) uint { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + valDelAddress := tr.validatorConfigs[validator].delAddress + if chain != chainID("provi") && tr.validatorConfigs[validator].useConsumerKey { + valDelAddress = tr.validatorConfigs[validator].consumerDelAddress + } + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. bz, err := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chain].binaryName, "query", "bank", "balances", - tr.validatorConfigs[validator].delAddress, + valDelAddress, `--node`, tr.getQueryNode(chain), `-o`, `json`, @@ -418,7 +441,9 @@ func (tr TestRun) getValPower(chain chainID, validator validatorID) uint { } for _, val := range valset.Validators { - if val.Address == tr.validatorConfigs[validator].valconsAddress { + if val.Address == tr.validatorConfigs[validator].valconsAddress || + val.Address == tr.validatorConfigs[validator].consumerValconsAddress { + votingPower, err := strconv.Atoi(val.VotingPower) if err != nil { log.Fatalf("error: %v", err) @@ -499,6 +524,60 @@ func (tr TestRun) getConsumerChains(chain chainID) map[chainID]bool { return chains } +func (tr TestRun) getConsumerAddresses(chain chainID, modelState map[validatorID]string) map[validatorID]string { + actualState := map[validatorID]string{} + for k := range modelState { + actualState[k] = tr.getConsumerAddress(chain, k) + } + + return actualState +} + +func (tr TestRun) getProviderAddresses(chain chainID, modelState map[validatorID]string) map[validatorID]string { + actualState := map[validatorID]string{} + for k := range modelState { + actualState[k] = tr.getProviderAddressFromConsumer(chain, k) + } + + return actualState +} + +func (tr TestRun) getConsumerAddress(consumerChain chainID, validator validatorID) string { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + + "query", "provider", "validator-consumer-key", + string(consumerChain), tr.validatorConfigs[validator].valconsAddress, + `--node`, tr.getQueryNode(chainID("provi")), + `-o`, `json`, + ) + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + addr := gjson.Get(string(bz), "consumer_address").String() + return addr +} + +func (tr TestRun) getProviderAddressFromConsumer(consumerChain chainID, validator validatorID) string { + //#nosec G204 -- Bypass linter warning for spawning subprocess with cmd arguments. + cmd := exec.Command("docker", "exec", tr.containerConfig.instanceName, tr.chainConfigs[chainID("provi")].binaryName, + + "query", "provider", "validator-provider-key", + string(consumerChain), tr.validatorConfigs[validator].consumerValconsAddress, + `--node`, tr.getQueryNode(chainID("provi")), + `-o`, `json`, + ) + bz, err := cmd.CombinedOutput() + if err != nil { + log.Fatal(err, "\n", string(bz)) + } + + addr := gjson.Get(string(bz), "provider_address").String() + return addr +} + func (tr TestRun) getValidatorNode(chain chainID, validator validatorID) string { return "tcp://" + tr.getValidatorIP(chain, validator) + ":26658" } diff --git a/tests/integration/step_delegation.go b/tests/integration/step_delegation.go index af969e8f08..d1fb2e9de6 100644 --- a/tests/integration/step_delegation.go +++ b/tests/integration/step_delegation.go @@ -145,6 +145,7 @@ func stepsRedelegate(consumerName string) []Step { ValPowers: &map[validatorID]uint{ validatorID("alice"): 509, validatorID("bob"): 500, + // carol always uses a consumer assigned key validatorID("carol"): 501, }, }, diff --git a/tests/integration/steps.go b/tests/integration/steps.go index 526a036b5c..b3fd3c5deb 100644 --- a/tests/integration/steps.go +++ b/tests/integration/steps.go @@ -16,6 +16,7 @@ func concatSteps(steps ...[]Step) []Step { var happyPathSteps = concatSteps( stepsStartChains([]string{"consu"}, false), stepsDelegate("consu"), + stepsAssignConsumerKeyOnStartedChain("consu", "bob"), stepsUnbond("consu"), stepsRedelegate("consu"), stepsDowntime("consu"), @@ -30,6 +31,7 @@ var democracySteps = concatSteps( stepsDemocracy("democ"), ) +//nolint var multipleConsumers = concatSteps( stepsStartChains([]string{"consu", "densu"}, false), stepsMultiConsumerDelegate("consu", "densu"), diff --git a/tests/integration/steps_start_chains.go b/tests/integration/steps_start_chains.go index c6ff985615..0451e7ee16 100644 --- a/tests/integration/steps_start_chains.go +++ b/tests/integration/steps_start_chains.go @@ -57,6 +57,62 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint }, }, }, + // add a consumer key before the chain starts + // the key will be present in consumer genesis initial_val_set + { + action: assignConsumerPubKeyAction{ + chain: chainID(consumerName), + validator: validatorID("carol"), + consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + // consumer chain has not started + // we don't need to reconfigure the node + // since it will start with consumer key + reconfigureNode: false, + }, + state: State{ + chainID(consumerName): ChainState{ + AssignedKeys: &map[validatorID]string{ + validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + }, + ProviderKeys: &map[validatorID]string{ + validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + }, + }, + }, + }, + { + // op should fail - key already assigned by the same validator + action: assignConsumerPubKeyAction{ + chain: chainID(consumerName), + validator: validatorID("carol"), + consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + reconfigureNode: false, + expectError: true, + }, + state: State{}, + }, + { + // op should fail - key allready assigned by another validator + action: assignConsumerPubKeyAction{ + chain: chainID(consumerName), + validator: validatorID("bob"), + // same pub key as carol + consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`, + reconfigureNode: false, + expectError: true, + }, + state: State{ + chainID(consumerName): ChainState{ + AssignedKeys: &map[validatorID]string{ + validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + validatorID("bob"): "", + }, + ProviderKeys: &map[validatorID]string{ + validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + }, + }, + }, + }, { action: voteGovProposalAction{ chain: chainID("provi"), @@ -86,11 +142,10 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint action: startConsumerChainAction{ consumerChain: chainID(consumerName), providerChain: chainID("provi"), - // genesisChanges: consumerGenesisParams, validators: []StartChainValidator{ - {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, - {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, {id: validatorID("bob"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("alice"), stake: 500000000, allocation: 10000000000}, + {id: validatorID("carol"), stake: 500000000, allocation: 10000000000}, }, }, state: State{ @@ -98,12 +153,14 @@ func stepsStartConsumerChain(consumerName string, proposalIndex, chainIndex uint ValBalances: &map[validatorID]uint{ validatorID("alice"): 9500000000, validatorID("bob"): 9500000000, + validatorID("carol"): 9500000000, }, }, chainID(consumerName): ChainState{ ValBalances: &map[validatorID]uint{ validatorID("alice"): 10000000000, validatorID("bob"): 10000000000, + validatorID("carol"): 10000000000, }, }, }, @@ -159,3 +216,81 @@ func stepsStartChains(consumerNames []string, setupTransferChans bool) []Step { return s } + +func stepsAssignConsumerKeyOnStartedChain(consumerName, validator string) []Step { + return []Step{ + { + action: assignConsumerPubKeyAction{ + chain: chainID(consumerName), + validator: validatorID("bob"), + // reconfigure the node -> validator was using provider key + // until this point -> key matches config.consumerValPubKey for "bob" + consumerPubkey: `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"QlG+iYe6AyYpvY1z9RNJKCVlH14Q/qSz4EjGdGCru3o="}`, + reconfigureNode: true, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + // this happens after some delegations + // so that the chain does not halt if 1/3 of power is offline + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // this happens after some delegations + // so that the chain does not halt if 1/3 of power is offline + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + AssignedKeys: &map[validatorID]string{ + validatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + }, + ProviderKeys: &map[validatorID]string{ + validatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + }, + }, + }, + }, + { + action: relayPacketsAction{ + chain: chainID("provi"), + port: "provider", + channel: 0, + }, + state: State{ + chainID("provi"): ChainState{ + ValPowers: &map[validatorID]uint{ + // this happens after some delegations + // so that the chain does not halt if 1/3 of power is offline + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + }, + chainID(consumerName): ChainState{ + ValPowers: &map[validatorID]uint{ + // this happens after some delegations + // so that the chain does not halt if 1/3 of power is offline + validatorID("alice"): 511, + validatorID("bob"): 500, + validatorID("carol"): 500, + }, + AssignedKeys: &map[validatorID]string{ + validatorID("bob"): "cosmosvalcons1uuec3cjxajv5te08p220usrjhkfhg9wyvqn0tm", + validatorID("carol"): "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk", + }, + ProviderKeys: &map[validatorID]string{ + validatorID("bob"): "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39", + validatorID("carol"): "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6", + }, + }, + }, + }, + } +} diff --git a/tests/integration/testnet-scripts/reconfigure-node.sh b/tests/integration/testnet-scripts/reconfigure-node.sh new file mode 100755 index 0000000000..8be5cea329 --- /dev/null +++ b/tests/integration/testnet-scripts/reconfigure-node.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +## Key assignment of a previosuly active validator is done as follows: +# - stop node +# - replace config/node_key.json +# - replace config/priv_validator_key.json with keys to use on consumer chain +# - replace config/priv_validator_state.json -> node will need to catch up +# - restart node -> it will use the new key to sign blocks +set -eux + + +BIN=$1 +VAL_ID=$2 +CHAIN_ID=$3 +CHAIN_IP_PREFIX=$4 +VAL_IP_SUFFIX=$5 + +CONSUMER_MNEMONIC=$6 +CONSUMER_PRIVATE_KEY=$7 +CONSUMER_NODE_KEY=$8 + +# kill validator node +pkill -f /$CHAIN_ID/validator$VAL_ID + +# swap valstate -> validator will sync on restart +echo '{"height": "0","round": 0,"step": 0,"signature":"","signbytes":""}' > /$CHAIN_ID/validator$VAL_ID/data/priv_validator_state.json + + +# swap private key +# echo "$CONSUMER_NODE_KEY" > /$CHAIN_ID/assignvalidator$VAL_ID/config/node_key.json +echo "$CONSUMER_PRIVATE_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json + +echo "$CONSUMER_NODE_KEY" > /$CHAIN_ID/validator$VAL_ID/config/node_key.json + +# remove old key +$BIN keys delete validator$VAL_ID --keyring-backend test --home /$CHAIN_ID/validator$VAL_ID --yes + +# add new key from mnemonic +echo "$CONSUMER_MNEMONIC" | $BIN keys add validator$VAL_ID --keyring-backend test --home /$CHAIN_ID/validator$VAL_ID --recover --output json + + +# restart node with new key +ARGS="--home /$CHAIN_ID/validator$VAL_ID --address tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26655 --rpc.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26658 --grpc.address $CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:9091 --log_level trace --p2p.laddr tcp://$CHAIN_IP_PREFIX.$VAL_IP_SUFFIX:26656 --grpc-web.enable=false" + +ip netns exec $CHAIN_ID-$VAL_ID $BIN $ARGS start &> /$CHAIN_ID/validator$VAL_ID/logs & + +echo 'done!!!!!!!!' diff --git a/tests/integration/testnet-scripts/start-chain.sh b/tests/integration/testnet-scripts/start-chain.sh index b7b16ef512..8416b456dc 100644 --- a/tests/integration/testnet-scripts/start-chain.sh +++ b/tests/integration/testnet-scripts/start-chain.sh @@ -101,14 +101,22 @@ mv /$CHAIN_ID/edited-genesis.json /$CHAIN_ID/genesis.json for i in $(seq 0 $(($NODES - 1))); do VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") - + START_WITH_CONSUMER_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].start_with_consumer_key") # Generate an application key for each validator # Sets up an arbitrary number of validators on a single machine by manipulating # the --home parameter on gaiad - echo "$VALIDATORS" | jq -r ".[$i].mnemonic" | $BIN keys add validator$VAL_ID \ + # optionally start validator with a key different from provider chain key + if [[ "$CHAIN_ID" != "provi" && "$START_WITH_CONSUMER_KEY" = "true" ]]; then + echo "$VALIDATORS" | jq -r ".[$i].consumer_mnemonic" | $BIN keys add validator$VAL_ID \ + --home /$CHAIN_ID/validator$VAL_ID \ + --keyring-backend test \ + --recover > /dev/null + else + echo "$VALIDATORS" | jq -r ".[$i].mnemonic" | $BIN keys add validator$VAL_ID \ --home /$CHAIN_ID/validator$VAL_ID \ --keyring-backend test \ --recover > /dev/null + fi # Give validators their initial token allocations # move the genesis in @@ -131,15 +139,25 @@ done for i in $(seq 0 $(($NODES - 1))); do VAL_ID=$(echo "$VALIDATORS" | jq -r ".[$i].val_id") + # Copy in the genesis.json cp /$CHAIN_ID/genesis.json /$CHAIN_ID/validator$VAL_ID/config/genesis.json # Copy in validator state file echo '{"height": "0","round": 0,"step": 0}' > /$CHAIN_ID/validator$VAL_ID/data/priv_validator_state.json - PRIV_VALIDATOR_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].priv_validator_key") - if [[ "$PRIV_VALIDATOR_KEY" ]]; then - echo "$PRIV_VALIDATOR_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json + START_WITH_CONSUMER_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].start_with_consumer_key") + if [[ "$CHAIN_ID" != "provi" && "$START_WITH_CONSUMER_KEY" = "true" ]]; then + # start with assigned consumer key + PRIV_VALIDATOR_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].consumer_priv_validator_key") + if [[ "$PRIV_VALIDATOR_KEY" ]]; then + echo "$PRIV_VALIDATOR_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json + fi + else + PRIV_VALIDATOR_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].priv_validator_key") + if [[ "$PRIV_VALIDATOR_KEY" ]]; then + echo "$PRIV_VALIDATOR_KEY" > /$CHAIN_ID/validator$VAL_ID/config/priv_validator_key.json + fi fi NODE_KEY=$(echo "$VALIDATORS" | jq -r ".[$i].node_key") diff --git a/testutil/crypto/crypto.go b/testutil/crypto/crypto.go index 8be417f98b..4cfba703be 100644 --- a/testutil/crypto/crypto.go +++ b/testutil/crypto/crypto.go @@ -25,13 +25,13 @@ type CryptoIdentity struct { ibcmock.PV } -func NewCryptoIdentityFromBytesSeed(seed []byte) CryptoIdentity { +func NewCryptoIdentityFromBytesSeed(seed []byte) *CryptoIdentity { //lint:ignore SA1019 We don't care because this is only a test. privKey := ibcmock.PV{PrivKey: &sdkcryptokeys.PrivKey{Key: cryptoEd25519.NewKeyFromSeed(seed)}} - return CryptoIdentity{PV: privKey} + return &CryptoIdentity{PV: privKey} } -func NewCryptoIdentityFromIntSeed(i int) CryptoIdentity { +func NewCryptoIdentityFromIntSeed(i int) *CryptoIdentity { iUint64 := uint64(i) seed := []byte("AAAAAAAAabcdefghijklmnopqrstuvwx") // 8+24 bytes binary.LittleEndian.PutUint64(seed[:8], iUint64) diff --git a/testutil/e2e/debug_test.go b/testutil/e2e/debug_test.go index 945a5d076b..a243a3f6c2 100644 --- a/testutil/e2e/debug_test.go +++ b/testutil/e2e/debug_test.go @@ -52,10 +52,6 @@ func findAndCallMethod(t *testing.T, suite any, methodName string) { // Channel init tests // -func TestConsumerGenesis(t *testing.T) { - runCCVTestByName(t, "TestConsumerGenesis") -} - func TestInitTimeout(t *testing.T) { runCCVTestByName(t, "TestInitTimeout") } diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index bb96ca387f..c845cc4fb7 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -4,9 +4,15 @@ import ( "testing" sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v3/modules/core/02-client/types" ibctesting "github.com/cosmos/ibc-go/v3/testing" e2eutil "github.com/cosmos/interchain-security/testutil/e2e" consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" + + "github.com/stretchr/testify/suite" + + tmencoding "github.com/tendermint/tendermint/crypto/encoding" + tmtypes "github.com/tendermint/tendermint/types" ) // Contains generic setup code for running e2e tests against a provider, consumer, @@ -58,27 +64,66 @@ func AddDemocracyConsumer[T e2eutil.DemocConsumerApp](coordinator *ibctesting.Co return democConsumer, democConsumer.App.(T) } -// AddConsumers adds new consumer chains to the coordinator and returns the test chains and app types -// The new consumers are initialized with the valset of the existing provider chain. +// AddConsumer adds a new consumer chain with "testchain" as chainID to the coordinator +// and returns the test chain and app type. A new client is created on the provider to the new +// consumer chain (see CreateConsumerClient). The new consumer is initialized with the +// InitialValSet from the genesis state generated by the provider (see MakeConsumerGenesis). // // This method must be called after AddProvider. -func AddConsumers[T e2eutil.ConsumerApp](coordinator *ibctesting.Coordinator, - t *testing.T, numConsumers int, appIniter ibctesting.AppIniter) map[string]*ConsumerBundle { - - providerChain := coordinator.GetChain(provChainID) - - // Instantiate specified number of consumer bundles, add each consumer chain to coordinator - consumerBundles := make(map[string]*ConsumerBundle) - for i := 0; i < numConsumers; i++ { - chainID := ibctesting.GetChainID(i + 2) - testChain := ibctesting.NewTestChainWithValSet(t, coordinator, - appIniter, chainID, providerChain.Vals, providerChain.Signers) - - coordinator.Chains[chainID] = testChain - consumerBundles[chainID] = &ConsumerBundle{ - Chain: testChain, - App: testChain.App.(T), - } +func AddConsumer[Tp e2eutil.ProviderApp, Tc e2eutil.ConsumerApp]( + coordinator *ibctesting.Coordinator, + s *suite.Suite, + index int, + appIniter ibctesting.AppIniter, +) *ConsumerBundle { + // consumer chain ID + chainID := ibctesting.GetChainID(index + 2) + + // create client to the consumer on the provider chain + providerChain := coordinator.Chains[provChainID] + providerApp := providerChain.App.(Tp) + providerKeeper := providerApp.GetProviderKeeper() + err := providerKeeper.CreateConsumerClient( + providerChain.GetContext(), + chainID, + // NOTE: the initial height passed to CreateConsumerClient + // must be the height on the consumer when InitGenesis is called + clienttypes.Height{RevisionNumber: 0, RevisionHeight: 3}, + false, + ) + s.Require().NoError(err) + + // commit the state on the provider chain + coordinator.CommitBlock(providerChain) + + // get genesis state created by the provider + consumerGenesisState, found := providerKeeper.GetConsumerGenesis( + providerChain.GetContext(), + chainID, + ) + s.Require().True(found, "consumer genesis not found") + + // use InitialValSet as the valset on the consumer + var valz []*tmtypes.Validator + for _, update := range consumerGenesisState.InitialValSet { + // tmPubKey update.PubKey + tmPubKey, err := tmencoding.PubKeyFromProto(update.PubKey) + s.Require().NoError(err) + valz = append(valz, &tmtypes.Validator{ + PubKey: tmPubKey, + VotingPower: update.Power, + Address: tmPubKey.Address(), + ProposerPriority: 0, + }) + } + + // create and instantiate consumer chain + testChain := ibctesting.NewTestChainWithValSet(s.T(), coordinator, + appIniter, chainID, tmtypes.NewValidatorSet(valz), providerChain.Signers) + coordinator.Chains[chainID] = testChain + + return &ConsumerBundle{ + Chain: testChain, + App: testChain.App.(Tc), } - return consumerBundles } diff --git a/testutil/keeper/expectations.go b/testutil/keeper/expectations.go index 133c56ada2..a7d7bb163f 100644 --- a/testutil/keeper/expectations.go +++ b/testutil/keeper/expectations.go @@ -28,21 +28,20 @@ import ( func GetMocksForCreateConsumerClient(ctx sdk.Context, mocks *MockedKeepers, expectedChainID string, expectedLatestHeight clienttypes.Height) []*gomock.Call { - expectations := []*gomock.Call{ - - mocks.MockClientKeeper.EXPECT().CreateClient( - ctx, - // Allows us to expect a match by field. These are the only two client state values - // that are dependant on parameters passed to CreateConsumerClient. - extra.StructMatcher().Field( - "ChainId", expectedChainID).Field( - "LatestHeight", expectedLatestHeight, - ), - gomock.Any(), - ).Return("clientID", nil).Times(1), - } + // append MakeConsumerGenesis and CreateClient expectations + expectations := GetMocksForMakeConsumerGenesis(ctx, mocks, time.Hour) + createClientExp := mocks.MockClientKeeper.EXPECT().CreateClient( + ctx, + // Allows us to expect a match by field. These are the only two client state values + // that are dependant on parameters passed to CreateConsumerClient. + extra.StructMatcher().Field( + "ChainId", expectedChainID).Field( + "LatestHeight", expectedLatestHeight, + ), + gomock.Any(), + ).Return("clientID", nil).Times(1) + expectations = append(expectations, createClientExp) - expectations = append(expectations, GetMocksForMakeConsumerGenesis(ctx, mocks, time.Hour)...) return expectations } @@ -160,8 +159,8 @@ func ExpectCreateClientMock(ctx sdk.Context, mocks MockedKeepers, clientID strin return mocks.MockClientKeeper.EXPECT().CreateClient(ctx, clientState, consState).Return(clientID, nil).Times(1) } -func ExpectGetCapabilityMock(ctx sdk.Context, mocks MockedKeepers) *gomock.Call { +func ExpectGetCapabilityMock(ctx sdk.Context, mocks MockedKeepers, times int) *gomock.Call { return mocks.MockScopedKeeper.EXPECT().GetCapability( ctx, host.PortPath(ccv.ConsumerPortID), - ).Return(nil, true).Times(1) + ).Return(nil, true).Times(times) } diff --git a/testutil/keeper/mocks.go b/testutil/keeper/mocks.go index d96a0b381d..fcc9b7ef4e 100644 --- a/testutil/keeper/mocks.go +++ b/testutil/keeper/mocks.go @@ -180,6 +180,21 @@ func (mr *MockStakingKeeperMockRecorder) UnbondingTime(ctx interface{}) *gomock. return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UnbondingTime", reflect.TypeOf((*MockStakingKeeper)(nil).UnbondingTime), ctx) } +// GetLastValidatorPower mocks base method. +func (m *MockStakingKeeper) GetLastValidatorPower(ctx types.Context, addr types.ValAddress) int64 { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetLastValidatorPower", ctx, addr) + ret0, _ := ret[0].(int64) + return ret0 +} + + +// GetLastValidatorPower indicates an expected call of GetLastValidatorPower. +func (mr *MockStakingKeeperMockRecorder) GetLastValidatorPower(ctx, addr interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetLastValidatorPower", reflect.TypeOf((*MockStakingKeeper)(nil).GetLastValidatorPower), ctx, addr) +} + // MockSlashingKeeper is a mock of SlashingKeeper interface. type MockSlashingKeeper struct { ctrl *gomock.Controller diff --git a/x/ccv/consumer/keeper/genesis.go b/x/ccv/consumer/keeper/genesis.go index e715f8ce1d..088ce6adc4 100644 --- a/x/ccv/consumer/keeper/genesis.go +++ b/x/ccv/consumer/keeper/genesis.go @@ -1,16 +1,13 @@ package keeper import ( - "bytes" "fmt" sdk "github.com/cosmos/cosmos-sdk/types" - ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" ) // InitGenesis initializes the CCV consumer state and binds to PortID. @@ -56,12 +53,6 @@ func (k Keeper) InitGenesis(ctx sdk.Context, state *consumertypes.GenesisState) k.SetHeightValsetUpdateID(ctx, uint64(ctx.BlockHeight()), uint64(0)) } else { - // verify genesis initial valset against the latest consensus state - // IBC genesis MUST run before CCV consumer genesis - if err := k.verifyGenesisInitValset(ctx, state); err != nil { - panic(err) - } - // chain restarts with the CCV channel established if state.ProviderChannelId != "" { // set provider channel ID @@ -197,30 +188,3 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) (genesis *consumertypes.GenesisSt return } - -// verifyGenesisInitValset verifies the latest consensus state on provider client matches -// the initial validator set of restarted chain thus -func (k Keeper) verifyGenesisInitValset(ctx sdk.Context, genState *consumertypes.GenesisState) error { - - consState, ok := k.clientKeeper.GetLatestClientConsensusState(ctx, genState.ProviderClientId) - if !ok { - return fmt.Errorf("consensus state for provider client not found. MUST run IBC genesis before CCV consumer genesis") - } - tmConsState, ok := consState.(*ibctmtypes.ConsensusState) - if !ok { - return fmt.Errorf(fmt.Sprintf("consensus state has wrong type. expected: %T, got: %T", &ibctmtypes.ConsensusState{}, consState)) - } - - // ensure that initial validator set is same as initial consensus state on provider client. - // this will be verified by provider module on channel handshake. - vals, err := tmtypes.PB2TM.ValidatorUpdates(genState.InitialValSet) - if err != nil { - return err - } - valSet := tmtypes.NewValidatorSet(vals) - - if !bytes.Equal(tmConsState.NextValidatorsHash, valSet.Hash()) { - return fmt.Errorf("initial validator set does not match last consensus state of the provider client") - } - return nil -} diff --git a/x/ccv/consumer/keeper/genesis_test.go b/x/ccv/consumer/keeper/genesis_test.go index e6a22c2df2..08abb89cda 100644 --- a/x/ccv/consumer/keeper/genesis_test.go +++ b/x/ccv/consumer/keeper/genesis_test.go @@ -106,9 +106,9 @@ func TestInitGenesis(t *testing.T) { "start a new chain", func(ctx sdk.Context, mocks testutil.MockedKeepers) { gomock.InOrder( - testkeeper.ExpectGetCapabilityMock(ctx, mocks), + testkeeper.ExpectGetCapabilityMock(ctx, mocks, 1), testkeeper.ExpectCreateClientMock(ctx, mocks, provClientID, provClientState, provConsState), - testkeeper.ExpectGetCapabilityMock(ctx, mocks), + testkeeper.ExpectGetCapabilityMock(ctx, mocks, 1), ) }, consumertypes.NewInitialGenesisState( @@ -130,9 +130,7 @@ func TestInitGenesis(t *testing.T) { "restart a chain without an established CCV channel", func(ctx sdk.Context, mocks testutil.MockedKeepers) { gomock.InOrder( - testkeeper.ExpectGetCapabilityMock(ctx, mocks), - testkeeper.ExpectLatestConsensusStateMock(ctx, mocks, provClientID, provConsState), - testkeeper.ExpectGetCapabilityMock(ctx, mocks), + testkeeper.ExpectGetCapabilityMock(ctx, mocks, 2), ) }, consumertypes.NewRestartGenesisState( @@ -162,9 +160,7 @@ func TestInitGenesis(t *testing.T) { params.DistributionTransmissionChannel = "distribution-channel" params.ProviderFeePoolAddrStr = "provider-fee-pool-address" gomock.InOrder( - testkeeper.ExpectGetCapabilityMock(ctx, mocks), - testkeeper.ExpectLatestConsensusStateMock(ctx, mocks, provClientID, provConsState), - testkeeper.ExpectGetCapabilityMock(ctx, mocks), + testkeeper.ExpectGetCapabilityMock(ctx, mocks, 2), ) }, // create a genesis for a restarted chain diff --git a/x/ccv/consumer/types/genesis.go b/x/ccv/consumer/types/genesis.go index 00d2ae60cd..e8a7c65cd5 100644 --- a/x/ccv/consumer/types/genesis.go +++ b/x/ccv/consumer/types/genesis.go @@ -1,14 +1,11 @@ package types import ( - "bytes" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" ) // NewInitialGenesisState returns a consumer GenesisState for a completely new consumer chain. @@ -114,17 +111,6 @@ func (gs GenesisState) Validate() error { if gs.LastTransmissionBlockHeight.Height != 0 { return sdkerrors.Wrap(ccv.ErrInvalidGenesis, "last transmission block height must be empty for new chain") } - - // ensure that initial validator set is same as initial consensus state on provider client. - // this will be verified by provider module on channel handshake. - vals, err := tmtypes.PB2TM.ValidatorUpdates(gs.InitialValSet) - if err != nil { - return sdkerrors.Wrap(err, "could not convert val updates to validator set") - } - valSet := tmtypes.NewValidatorSet(vals) - if !bytes.Equal(gs.ProviderConsensusState.NextValidatorsHash, valSet.Hash()) { - return sdkerrors.Wrap(ccv.ErrInvalidGenesis, "initial validators does not hash to NextValidatorsHash on provider client") - } } else { // NOTE: For restart genesis, we will verify initial validator set in InitGenesis. if gs.ProviderClientId == "" { diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go index de6269d981..e505023fd4 100644 --- a/x/ccv/provider/client/cli/query.go +++ b/x/ccv/provider/client/cli/query.go @@ -1,10 +1,16 @@ package cli import ( + "fmt" + "strings" + "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/interchain-security/x/ccv/provider/types" ) @@ -22,6 +28,8 @@ func NewQueryCmd() *cobra.Command { cmd.AddCommand(CmdConsumerChains()) cmd.AddCommand(CmdConsumerStartProposals()) cmd.AddCommand(CmdConsumerStopProposals()) + cmd.AddCommand(CmdConsumerValidatorKeyAssignment()) + cmd.AddCommand(CmdProviderValidatorKey()) return cmd } @@ -143,3 +151,98 @@ func CmdConsumerStopProposals() *cobra.Command { return cmd } + +// TODO: fix naming +func CmdConsumerValidatorKeyAssignment() *cobra.Command { + bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() + cmd := &cobra.Command{ + Use: "validator-consumer-key [chainid] [provider-validator-address]", + Short: "Query assigned validator consensus public key for a consumer chain", + Long: strings.TrimSpace( + fmt.Sprintf(`Returns the currently assigned validator consensus public key for a +consumer chain, if one has been assigned. +Example: +$ %s query provider validator-consumer-key foochain %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +`, + version.AppName, bech32PrefixConsAddr, + ), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + consumerChainID := args[0] + + addr, err := sdk.ConsAddressFromBech32(args[1]) + if err != nil { + return err + } + + req := &types.QueryValidatorConsumerAddrRequest{ + ChainId: consumerChainID, + ProviderAddress: addr.String(), + } + res, err := queryClient.QueryValidatorConsumerAddr(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} + +// TODO: fix naming +func CmdProviderValidatorKey() *cobra.Command { + bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix() + cmd := &cobra.Command{ + Use: "validator-provider-key [chainid] [consumer-validator-address]", + Short: "Query validator consensus public key for the provider chain", + Long: strings.TrimSpace( + fmt.Sprintf(`Returns the currently assigned validator consensus public key for the provider chain. +Example: +$ %s query provider validator-provider-key foochain %s1gghjut3ccd8ay0zduzj64hwre2fxs9ldmqhffj +`, + version.AppName, bech32PrefixConsAddr, + ), + ), + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) (err error) { + clientCtx, err := client.GetClientQueryContext(cmd) + if err != nil { + return err + } + queryClient := types.NewQueryClient(clientCtx) + + consumerChainID := args[0] + + addr, err := sdk.ConsAddressFromBech32(args[1]) + if err != nil { + return err + } + + req := &types.QueryValidatorProviderAddrRequest{ + ChainId: consumerChainID, + ConsumerAddress: addr.String(), + } + res, err := queryClient.QueryValidatorProviderAddr(cmd.Context(), req) + if err != nil { + return err + } + + return clientCtx.PrintProto(res) + }, + } + + flags.AddQueryFlagsToCmd(cmd) + + return cmd +} diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go new file mode 100644 index 0000000000..edd230e15c --- /dev/null +++ b/x/ccv/provider/client/cli/tx.go @@ -0,0 +1,69 @@ +package cli + +import ( + "github.com/spf13/cobra" + + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/client/tx" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/interchain-security/x/ccv/provider/types" +) + +// GetTxCmd returns the transaction commands for this module +func GetTxCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: types.ModuleName, + Short: fmt.Sprintf("%s transactions subcommands", types.ModuleName), + DisableFlagParsing: true, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + + cmd.AddCommand(NewAssignConsumerKeyCmd()) + + return cmd +} + +func NewAssignConsumerKeyCmd() *cobra.Command { + cmd := &cobra.Command{ + Use: "assign-consensus-key [consumer-chain-id] [consumer-pubkey]", + Short: "assign a consensus public key to use for a consumer chain", + Args: cobra.ExactArgs(2), + RunE: func(cmd *cobra.Command, args []string) error { + clientCtx, err := client.GetClientTxContext(cmd) + if err != nil { + return err + } + + txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()). + WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever) + + providerValAddr := clientCtx.GetFromAddress() + var consumerPubKey cryptotypes.PubKey + if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[1]), &consumerPubKey); err != nil { + return err + } + + msg, err := types.NewMsgAssignConsumerKey(args[0], sdk.ValAddress(providerValAddr), consumerPubKey) + if err != nil { + return err + } + if err := msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg) + }, + } + + flags.AddTxFlagsToCmd(cmd) + + _ = cmd.MarkFlagRequired(flags.FlagFrom) + + return cmd +} diff --git a/x/ccv/provider/handler.go b/x/ccv/provider/handler.go new file mode 100644 index 0000000000..4751b8460c --- /dev/null +++ b/x/ccv/provider/handler.go @@ -0,0 +1,24 @@ +package provider + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/x/ccv/provider/types" +) + +func NewHandler(k *keeper.Keeper) sdk.Handler { + msgServer := keeper.NewMsgServerImpl(k) + + return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { + ctx = ctx.WithEventManager(sdk.NewEventManager()) + + switch msg := msg.(type) { + case *types.MsgAssignConsumerKey: + res, err := msgServer.AssignConsumerKey(sdk.WrapSDKContext(ctx), msg) + return sdk.WrapServiceResult(ctx, res, err) + default: + return nil, sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "unrecognized %s message type: %T", types.ModuleName, msg) + } + } +} diff --git a/x/ccv/provider/handler_test.go b/x/ccv/provider/handler_test.go new file mode 100644 index 0000000000..9ff5c386cd --- /dev/null +++ b/x/ccv/provider/handler_test.go @@ -0,0 +1,123 @@ +package provider_test + +import ( + "strings" + "testing" + + "github.com/golang/mock/gomock" + "github.com/stretchr/testify/require" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + + "github.com/cosmos/cosmos-sdk/testutil/testdata" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + testcrypto "github.com/cosmos/interchain-security/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/testutil/keeper" + "github.com/cosmos/interchain-security/x/ccv/provider" + keeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + "github.com/cosmos/interchain-security/x/ccv/provider/types" +) + +func TestInvalidMsg(t *testing.T) { + k, _, _, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + handler := provider.NewHandler(&k) + res, err := handler(sdk.NewContext(nil, tmproto.Header{}, false, nil), testdata.NewTestMsg()) + require.Error(t, err) + require.Nil(t, res) + require.True(t, strings.Contains(err.Error(), "unrecognized provider message type")) +} + +func TestAssignConsensusKeyForConsumerChain(t *testing.T) { + + testValProvider := testcrypto.NewCryptoIdentityFromIntSeed(0) + testValConsumer := testcrypto.NewCryptoIdentityFromIntSeed(1) + + testCases := []struct { + name string + // State-mutating setup specific to this test case + setup func(sdk.Context, keeper.Keeper, testkeeper.MockedKeepers) + expError bool + chainID string + }{ + { + name: "success", + setup: func(ctx sdk.Context, + k keeper.Keeper, mocks testkeeper.MockedKeepers) { + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator( + ctx, testValProvider.SDKValAddress(), + // Return a valid validator, found! + ).Return(testValProvider.SDKStakingValidator(), true).Times(1), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + testValConsumer.SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + expError: false, + chainID: "chainid", + }, + { + name: "fail: missing validator", + setup: func(ctx sdk.Context, + k keeper.Keeper, mocks testkeeper.MockedKeepers) { + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator( + ctx, testValProvider.SDKValAddress(), + // return false: not found! + ).Return(stakingtypes.Validator{}, false).Times(1), + ) + }, + expError: true, + chainID: "chainid", + }, + { + name: "fail: consumer key in use", + setup: func(ctx sdk.Context, + k keeper.Keeper, mocks testkeeper.MockedKeepers) { + + // Use the consumer key already + k.SetValidatorByConsumerAddr(ctx, "chainid", testValConsumer.SDKConsAddress(), testValProvider.SDKConsAddress()) + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator( + ctx, testValProvider.SDKValAddress(), + // Return a valid validator, found! + ).Return(testValProvider.SDKStakingValidator(), true).Times(1), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + testValConsumer.SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + expError: true, + chainID: "chainid", + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + + tc.setup(ctx, k, mocks) + + msg, err := types.NewMsgAssignConsumerKey(tc.chainID, + testValProvider.SDKValAddress(), testValConsumer.SDKPubKey(), + ) + + require.NoError(t, err) + + // Try to handle the message + _, err = provider.NewHandler(&k)(ctx, msg) + + if tc.expError { + require.Error(t, err, "invalid case did not return error") + } else { + require.NoError(t, err, "valid case returned error") + } + + ctrl.Finish() + }) + } +} diff --git a/x/ccv/provider/keeper/genesis.go b/x/ccv/provider/keeper/genesis.go index d866a81d3e..4013498686 100644 --- a/x/ccv/provider/keeper/genesis.go +++ b/x/ccv/provider/keeper/genesis.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/interchain-security/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" + tmcrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" ) // InitGenesis initializes the CCV provider state and binds to PortID. @@ -74,6 +75,21 @@ func (k Keeper) InitGenesis(ctx sdk.Context, genState *types.GenesisState) { } } + // Import key assignment state + for _, item := range genState.ValidatorConsumerPubkeys { + k.SetValidatorConsumerPubKey(ctx, item.ChainId, item.ProviderAddr, *item.ConsumerKey) + } + + for _, item := range genState.ValidatorsByConsumerAddr { + k.SetValidatorByConsumerAddr(ctx, item.ChainId, item.ConsumerAddr, item.ProviderAddr) + } + + for _, item := range genState.ConsumerAddrsToPrune { + for _, addr := range item.ConsumerAddrs.Addresses { + k.AppendConsumerAddrsToPrune(ctx, item.ChainId, item.VscId, addr) + } + } + k.SetParams(ctx, genState.Params) } @@ -117,7 +133,7 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return false // do not stop the iteration }) - // export provider chain states + // export provider chain state vscID := k.GetValidatorSetUpdateId(ctx) vscIDToHeights := []types.ValsetUpdateIdToHeight{} k.IterateValsetUpdateBlockHeight(ctx, func(vscID, height uint64) (stop bool) { @@ -148,6 +164,41 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { return false // do not stop the iteration }) + // Export key assignment states + validatorConsumerPubKeys := []types.ValidatorConsumerPubKey{} + k.IterateAllValidatorConsumerPubKeys(ctx, func(chainID string, providerAddr sdk.ConsAddress, consumerKey tmcrypto.PublicKey) (stop bool) { + validatorConsumerPubKeys = append(validatorConsumerPubKeys, types.ValidatorConsumerPubKey{ + ChainId: chainID, + ProviderAddr: providerAddr, + ConsumerKey: &consumerKey, + }) + return false // do not stop the iteration + }) + + validatorsByConsumerAddr := []types.ValidatorByConsumerAddr{} + k.IterateAllValidatorsByConsumerAddr(ctx, func(chainID string, consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + validatorsByConsumerAddr = append(validatorsByConsumerAddr, types.ValidatorByConsumerAddr{ + ChainId: chainID, + ConsumerAddr: consumerAddr, + ProviderAddr: providerAddr, + }) + return false // do not stop the iteration + }) + + consumerAddrsToPrune := []types.ConsumerAddrsToPrune{} + // ConsumerAddrsToPrune are added only for registered consumer chains + k.IterateConsumerChains(ctx, func(ctx sdk.Context, chainID string, _ string) (stopOuter bool) { + k.IterateConsumerAddrsToPrune(ctx, chainID, func(vscID uint64, consumerAddrs types.AddressList) (stopInner bool) { + consumerAddrsToPrune = append(consumerAddrsToPrune, types.ConsumerAddrsToPrune{ + ChainId: chainID, + VscId: vscID, + ConsumerAddrs: &consumerAddrs, + }) + return false // do not stop the iteration + }) + return false // do not stop the iteration + }) + params := k.GetParams(ctx) return types.NewGenesisState( @@ -159,5 +210,8 @@ func (k Keeper) ExportGenesis(ctx sdk.Context) *types.GenesisState { addProps, remProps, params, + validatorConsumerPubKeys, + validatorsByConsumerAddr, + consumerAddrsToPrune, ) } diff --git a/x/ccv/provider/keeper/genesis_test.go b/x/ccv/provider/keeper/genesis_test.go index 24c704a6e9..f6dd42b668 100644 --- a/x/ccv/provider/keeper/genesis_test.go +++ b/x/ccv/provider/keeper/genesis_test.go @@ -4,13 +4,14 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" sdk "github.com/cosmos/cosmos-sdk/types" host "github.com/cosmos/ibc-go/v3/modules/core/24-host" testkeeper "github.com/cosmos/interchain-security/testutil/keeper" + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" "github.com/cosmos/interchain-security/x/ccv/provider/keeper" - "github.com/cosmos/interchain-security/x/ccv/provider/types" providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" "github.com/golang/mock/gomock" @@ -27,6 +28,13 @@ func TestInitAndExportGenesis(t *testing.T) { ubdIndex := []uint64{0, 1, 2} params := providertypes.DefaultParams() + // create validator keys and addresses for key assignement + provAddr := sdk.ConsAddress(ed25519.GenPrivKey().PubKey().Address().Bytes()) + consPubKey := ed25519.GenPrivKey().PubKey() + consTmPubKey, err := cryptocodec.ToTmProtoPublicKey(consPubKey) + require.NoError(t, err) + consAddr := sdk.ConsAddress(consPubKey.Address().Bytes()) + // create genesis struct provGenesis := providertypes.NewGenesisState(vscID, []providertypes.ValsetUpdateIdToHeight{{ValsetUpdateId: vscID, Height: initHeight}}, @@ -61,15 +69,36 @@ func TestInitAndExportGenesis(t *testing.T) { UnbondingConsumerChains: []string{cChainIDs[0]}, }}, &ccv.MaturedUnbondingOps{Ids: ubdIndex}, - []providertypes.ConsumerAdditionProposal{types.ConsumerAdditionProposal{ + []providertypes.ConsumerAdditionProposal{{ ChainId: cChainIDs[0], SpawnTime: oneHourFromNow, }}, - []providertypes.ConsumerRemovalProposal{types.ConsumerRemovalProposal{ + []providertypes.ConsumerRemovalProposal{{ ChainId: cChainIDs[0], StopTime: oneHourFromNow, }}, params, + []providertypes.ValidatorConsumerPubKey{ + { + ChainId: cChainIDs[0], + ProviderAddr: provAddr, + ConsumerKey: &consTmPubKey, + }, + }, + []providertypes.ValidatorByConsumerAddr{ + { + ChainId: cChainIDs[0], + ProviderAddr: provAddr, + ConsumerAddr: consAddr, + }, + }, + []providertypes.ConsumerAddrsToPrune{ + { + ChainId: cChainIDs[0], + VscId: vscID, + ConsumerAddrs: &providertypes.AddressList{Addresses: [][]byte{consAddr}}, + }, + }, ) // Instantiate in-mem provider keeper with mocks @@ -105,6 +134,17 @@ func TestInitAndExportGenesis(t *testing.T) { require.True(t, pk.GetPendingConsumerRemovalProp(ctx, cChainIDs[0], oneHourFromNow)) require.Equal(t, provGenesis.Params, pk.GetParams(ctx)) + gotConsTmPubKey, found := pk.GetValidatorConsumerPubKey(ctx, cChainIDs[0], provAddr) + require.True(t, found) + require.True(t, consTmPubKey.Equal(gotConsTmPubKey)) + + providerAddr, found := pk.GetValidatorByConsumerAddr(ctx, cChainIDs[0], consAddr) + require.True(t, found) + require.Equal(t, provAddr, providerAddr) + + addrs := pk.GetConsumerAddrsToPrune(ctx, cChainIDs[0], vscID) + require.Equal(t, [][]byte{consAddr}, addrs.Addresses) + // check provider chain's consumer chain states assertConsumerChainStates(ctx, t, pk, provGenesis.ConsumerStates...) diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index f4d9618f63..af24b6cc00 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/cosmos/interchain-security/x/ccv/provider/types" + "github.com/cosmos/interchain-security/x/ccv/utils" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" ) @@ -71,3 +72,47 @@ func (k Keeper) QueryConsumerChainStops(goCtx context.Context, req *types.QueryC return &types.QueryConsumerChainStopProposalsResponse{Proposals: &props}, nil } + +func (k Keeper) QueryValidatorConsumerAddr(goCtx context.Context, req *types.QueryValidatorConsumerAddrRequest) (*types.QueryValidatorConsumerAddrResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + providerAddr, err := sdk.ConsAddressFromBech32(req.ProviderAddress) + if err != nil { + return nil, err + } + + consumerKey, found := k.GetValidatorConsumerPubKey(ctx, req.ChainId, providerAddr) + if !found { + return &types.QueryValidatorConsumerAddrResponse{}, nil + } + + return &types.QueryValidatorConsumerAddrResponse{ + ConsumerAddress: utils.TMCryptoPublicKeyToConsAddr(consumerKey).String(), + }, nil +} + +func (k Keeper) QueryValidatorProviderAddr(goCtx context.Context, req *types.QueryValidatorProviderAddrRequest) (*types.QueryValidatorProviderAddrResponse, error) { + if req == nil { + return nil, status.Error(codes.InvalidArgument, "empty request") + } + + ctx := sdk.UnwrapSDKContext(goCtx) + + consumerAddr, err := sdk.ConsAddressFromBech32(req.ConsumerAddress) + if err != nil { + return nil, err + } + + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, req.ChainId, consumerAddr) + if !found { + return &types.QueryValidatorProviderAddrResponse{}, nil + } + + return &types.QueryValidatorProviderAddrResponse{ + ProviderAddress: providerAddr.String(), + }, nil +} diff --git a/x/ccv/provider/keeper/hooks.go b/x/ccv/provider/keeper/hooks.go index 49aa24169f..21d0deb57f 100644 --- a/x/ccv/provider/keeper/hooks.go +++ b/x/ccv/provider/keeper/hooks.go @@ -4,9 +4,11 @@ import ( "fmt" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" sdk "github.com/cosmos/cosmos-sdk/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" + "github.com/cosmos/interchain-security/x/ccv/utils" ) // Wrapper struct @@ -57,11 +59,70 @@ func (h Hooks) AfterUnbondingInitiated(ctx sdk.Context, ID uint64) error { return nil } -// Define unimplemented methods to satisfy the StakingHooks contract +func ValidatorConsensusKeyInUse(k *Keeper, ctx sdk.Context, valAddr sdk.ValAddress) bool { + // Get the validator being added in the staking module. + val, found := k.stakingKeeper.GetValidator(ctx, valAddr) + if !found { + panic("did not find newly created validator in staking module") + } + + // Get the consensus address of the validator being added + consensusAddr, err := val.GetConsAddr() + if err != nil { + panic("could not get validator cons addr ") + } + + inUse := false + + // Search over all consumer keys which have been assigned in order to + // check if the validator being added is, or was, a consumer chain validator + k.IterateAllValidatorsByConsumerAddr(ctx, func(_ string, consumerAddr sdk.ConsAddress, _ sdk.ConsAddress) (stop bool) { + if consumerAddr.Equals(consensusAddr) { + inUse = true + return true + } + return false + }) + + return inUse +} + func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { + if ValidatorConsensusKeyInUse(h.k, ctx, valAddr) { + // Abort TX, do NOT allow validator to be created + panic("cannot create a validator with a consensus key that is already in use or was recently in use as an assigned consumer chain key") + } } -func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) { + +func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, valConsAddr sdk.ConsAddress, valAddr sdk.ValAddress) { + type StoreKey struct { + ChainID string + ProviderAddr sdk.ConsAddress + ConsumerKey tmprotocrypto.PublicKey + } + toDelete := []StoreKey{} + h.k.IterateAllValidatorConsumerPubKeys(ctx, func( + chainID string, + providerAddr sdk.ConsAddress, + consumerKey tmprotocrypto.PublicKey, + ) (stop bool) { + if providerAddr.Equals(valConsAddr) { + toDelete = append(toDelete, + StoreKey{ + ChainID: chainID, + ProviderAddr: providerAddr, + ConsumerKey: consumerKey, + }) + } + return false // do not stop + }) + for _, key := range toDelete { + consumerAddr := utils.TMCryptoPublicKeyToConsAddr(key.ConsumerKey) + h.k.DeleteValidatorByConsumerAddr(ctx, key.ChainID, consumerAddr) + h.k.DeleteValidatorConsumerPubKey(ctx, key.ChainID, key.ProviderAddr) + } } + func (h Hooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { } func (h Hooks) BeforeDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) { diff --git a/x/ccv/provider/keeper/hooks_test.go b/x/ccv/provider/keeper/hooks_test.go new file mode 100644 index 0000000000..a80d6e4c3e --- /dev/null +++ b/x/ccv/provider/keeper/hooks_test.go @@ -0,0 +1,68 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + cryptotestutil "github.com/cosmos/interchain-security/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/testutil/keeper" + providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + "github.com/golang/mock/gomock" +) + +func TestValidatorConsensusKeyInUse(t *testing.T) { + + newValidator := cryptotestutil.NewCryptoIdentityFromIntSeed(0) + anotherValidator0 := cryptotestutil.NewCryptoIdentityFromIntSeed(1) + anotherValidator1 := cryptotestutil.NewCryptoIdentityFromIntSeed(2) + + tests := []struct { + name string + setup func(sdk.Context, providerkeeper.Keeper) + expect bool + }{ + { + name: "not in use by another validator", + setup: func(ctx sdk.Context, k providerkeeper.Keeper) { + // Another validator does not exist + }, + expect: false, + }, + { + name: "in use by another validator", + setup: func(ctx sdk.Context, k providerkeeper.Keeper) { + // We are trying to add a new validator, but its address has already been used + // by another validator + k.SetValidatorByConsumerAddr(ctx, "chainid", newValidator.SDKConsAddress(), anotherValidator0.SDKConsAddress()) + }, + expect: true, + }, + { + name: "in use by one of several other validators", + setup: func(ctx sdk.Context, k providerkeeper.Keeper) { + // We are trying to add a new validator, but its address has already been used + // by another validator, of which there are several, across potentially several chains + k.SetValidatorByConsumerAddr(ctx, "chainid0", newValidator.SDKConsAddress(), anotherValidator0.SDKConsAddress()) + k.SetValidatorByConsumerAddr(ctx, "chainid1", anotherValidator1.SDKConsAddress(), anotherValidator1.SDKConsAddress()) + }, + expect: true, + }, + } + for _, tt := range tests { + k, ctx, _, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, + newValidator.SDKStakingOperator(), + ).Return(newValidator.SDKStakingValidator(), true), + ) + + tt.setup(ctx, k) + + t.Run(tt.name, func(t *testing.T) { + if actual := providerkeeper.ValidatorConsensusKeyInUse(&k, ctx, newValidator.SDKStakingOperator()); actual != tt.expect { + t.Errorf("validatorConsensusKeyInUse() = %v, want %v", actual, tt.expect) + } + }) + } +} diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go new file mode 100644 index 0000000000..8c995409bc --- /dev/null +++ b/x/ccv/provider/keeper/key_assignment.go @@ -0,0 +1,615 @@ +package keeper + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + + "github.com/cosmos/interchain-security/x/ccv/provider/types" + utils "github.com/cosmos/interchain-security/x/ccv/utils" + + abci "github.com/tendermint/tendermint/abci/types" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" +) + +// GetValidatorConsumerPubKey returns a validator's public key assigned for a consumer chain +func (k Keeper) GetValidatorConsumerPubKey( + ctx sdk.Context, + chainID string, + providerAddr sdk.ConsAddress, +) (consumerKey tmprotocrypto.PublicKey, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ConsumerValidatorsKey(chainID, providerAddr)) + if bz == nil { + return consumerKey, false + } + err := consumerKey.Unmarshal(bz) + if err != nil { + panic(err) + } + return consumerKey, true +} + +// SetValidatorConsumerPubKey sets a validator's public key assigned for a consumer chain +func (k Keeper) SetValidatorConsumerPubKey( + ctx sdk.Context, + chainID string, + providerAddr sdk.ConsAddress, + consumerKey tmprotocrypto.PublicKey, +) { + store := ctx.KVStore(k.storeKey) + bz, err := consumerKey.Marshal() + if err != nil { + panic(err) + } + store.Set(types.ConsumerValidatorsKey(chainID, providerAddr), bz) +} + +// IterateValidatorConsumerPubKeys iterates over the validators public keys assigned for a consumer chain +func (k Keeper) IterateValidatorConsumerPubKeys( + ctx sdk.Context, + chainID string, + cb func(providerAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + prefix := types.ChainIdWithLenKey(types.ConsumerValidatorsBytePrefix, chainID) + iter := sdk.KVStorePrefixIterator(store, prefix) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + _, providerAddr, err := types.ParseChainIdAndConsAddrKey(types.ConsumerValidatorsBytePrefix, iter.Key()) + if err != nil { + panic(err) + } + var consumerKey tmprotocrypto.PublicKey + err = consumerKey.Unmarshal(iter.Value()) + if err != nil { + panic(err) + } + stop := cb(providerAddr, consumerKey) + if stop { + break + } + } +} + +// IterateAllValidatorConsumerPubKeys iterates over the validators public keys assigned for all consumer chain. +// Note that IterateValidatorConsumerPubKeys cannot be used as consumer keys can be assigned for chain IDs +// that are not yet known to the provider. +func (k Keeper) IterateAllValidatorConsumerPubKeys( + ctx sdk.Context, + cb func(chainID string, providerAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, []byte{types.ConsumerValidatorsBytePrefix}) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + chainID, providerAddr, err := types.ParseChainIdAndConsAddrKey(types.ConsumerValidatorsBytePrefix, iter.Key()) + if err != nil { + panic(err) + } + var consumerKey tmprotocrypto.PublicKey + err = consumerKey.Unmarshal(iter.Value()) + if err != nil { + panic(err) + } + stop := cb(chainID, providerAddr, consumerKey) + if stop { + break + } + } +} + +// DeleteValidatorConsumerPubKey deletes a validator's public key assigned for a consumer chain +func (k Keeper) DeleteValidatorConsumerPubKey(ctx sdk.Context, chainID string, providerAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ConsumerValidatorsKey(chainID, providerAddr)) +} + +// GetValidatorByConsumerAddr returns a validator's consensus address on the provider +// given the validator's consensus address on a consumer +func (k Keeper) GetValidatorByConsumerAddr( + ctx sdk.Context, + chainID string, + consumerAddr sdk.ConsAddress, +) (providerAddr sdk.ConsAddress, found bool) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ValidatorsByConsumerAddrKey(chainID, consumerAddr)) + if bz == nil { + return providerAddr, false + } + err := providerAddr.Unmarshal(bz) + if err != nil { + panic(err) + } + return providerAddr, true +} + +// SetValidatorByConsumerAddr sets the mapping from a validator's consensus address on a consumer +// to the validator's consensus address on the provider +func (k Keeper) SetValidatorByConsumerAddr( + ctx sdk.Context, + chainID string, + consumerAddr sdk.ConsAddress, + providerAddr sdk.ConsAddress, +) { + store := ctx.KVStore(k.storeKey) + bz, err := providerAddr.Marshal() + if err != nil { + panic(err) + } + store.Set(types.ValidatorsByConsumerAddrKey(chainID, consumerAddr), bz) +} + +// IterateValidatorsByConsumerAddr iterates over all the mappings from consensus addresses +// on a given consumer chain to consensus addresses on the provider chain +func (k Keeper) IterateValidatorsByConsumerAddr( + ctx sdk.Context, + chainID string, + cb func(consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + prefix := types.ChainIdWithLenKey(types.ValidatorsByConsumerAddrBytePrefix, chainID) + iter := sdk.KVStorePrefixIterator(store, prefix) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + _, consumerAddr, err := types.ParseChainIdAndConsAddrKey(types.ValidatorsByConsumerAddrBytePrefix, iter.Key()) + if err != nil { + panic(err) + } + var providerAddr sdk.ConsAddress + err = providerAddr.Unmarshal(iter.Value()) + if err != nil { + panic(err) + } + stop := cb(consumerAddr, providerAddr) + if stop { + break + } + } +} + +// IterateAllValidatorsByConsumerAddr iterates over all the mappings from consensus addresses +// on any consumer chain to consensus addresses on the provider chain. +// Note that IterateValidatorsByConsumerAddr cannot be used as consumer keys can be assigned +// for chain IDs that are not yet known to the provider. +func (k Keeper) IterateAllValidatorsByConsumerAddr( + ctx sdk.Context, + cb func(chainID string, consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + iter := sdk.KVStorePrefixIterator(store, []byte{types.ValidatorsByConsumerAddrBytePrefix}) + defer iter.Close() + for ; iter.Valid(); iter.Next() { + chainID, consumerAddr, err := types.ParseChainIdAndConsAddrKey(types.ValidatorsByConsumerAddrBytePrefix, iter.Key()) + if err != nil { + panic(err) + } + var providerAddr sdk.ConsAddress + err = providerAddr.Unmarshal(iter.Value()) + if err != nil { + panic(err) + } + stop := cb(chainID, consumerAddr, providerAddr) + if stop { + break + } + } +} + +// DeleteValidatorByConsumerAddr deletes the mapping from a validator's consensus address on a consumer +// to the validator's consensus address on the provider +func (k Keeper) DeleteValidatorByConsumerAddr(ctx sdk.Context, chainID string, consumerAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ValidatorsByConsumerAddrKey(chainID, consumerAddr)) +} + +// GetKeyAssignmentReplacement returns the previous assigned consumer key and the current power +// for a provider validator for which a key assignment was received in this block. Both are +// needed to update the validator's power on the consumer chain at the end of the current block. +func (k Keeper) GetKeyAssignmentReplacement( + ctx sdk.Context, + chainID string, + providerAddr sdk.ConsAddress, +) (prevCKey tmprotocrypto.PublicKey, power int64, found bool) { + var pubKeyAndPower abci.ValidatorUpdate + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.KeyAssignmentReplacementsKey(chainID, providerAddr)) + if bz == nil { + return pubKeyAndPower.PubKey, pubKeyAndPower.Power, false + } + + err := pubKeyAndPower.Unmarshal(bz) + if err != nil { + panic(err) + } + return pubKeyAndPower.PubKey, pubKeyAndPower.Power, true +} + +// SetKeyAssignmentReplacement sets the previous assigned consumer key and the current power +// for a provider validator for which a key assignment was received in this block. Both are +// needed to update the validator's power on the consumer chain at the end of the current block. +func (k Keeper) SetKeyAssignmentReplacement( + ctx sdk.Context, + chainID string, + providerAddr sdk.ConsAddress, + prevCKey tmprotocrypto.PublicKey, + power int64, +) { + store := ctx.KVStore(k.storeKey) + pubKeyAndPower := abci.ValidatorUpdate{PubKey: prevCKey, Power: power} + bz, err := pubKeyAndPower.Marshal() + if err != nil { + panic(err) + } + store.Set(types.KeyAssignmentReplacementsKey(chainID, providerAddr), bz) +} + +// IterateKeyAssignmentReplacements iterates through all pairs of previous assigned consumer keys +// and current powers for all provider validator for which key assignments were received in this block. +func (k Keeper) IterateKeyAssignmentReplacements( + ctx sdk.Context, + chainID string, + cb func(providerAddr sdk.ConsAddress, prevCKey tmprotocrypto.PublicKey, power int64) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + iteratorPrefix := types.ChainIdWithLenKey(types.KeyAssignmentReplacementsBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, iteratorPrefix) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + _, providerAddr, err := types.ParseChainIdAndConsAddrKey(types.KeyAssignmentReplacementsBytePrefix, iterator.Key()) + if err != nil { + panic(err) + } + var pubKeyAndPower abci.ValidatorUpdate + err = pubKeyAndPower.Unmarshal(iterator.Value()) + if err != nil { + panic(err) + } + stop := cb(providerAddr, pubKeyAndPower.PubKey, pubKeyAndPower.Power) + if stop { + break + } + } +} + +// DeleteKeyAssignmentReplacement deletes the previous assigned consumer key and the current power +// for a provider validator for which a key assignment was received in this block. Both are +// needed to update the validator's power on the consumer chain at the end of the current block. +func (k Keeper) DeleteKeyAssignmentReplacement(ctx sdk.Context, chainID string, providerAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.KeyAssignmentReplacementsKey(chainID, providerAddr)) +} + +// AppendConsumerAddrsToPrune appends a consumer validator address to the list of consumer addresses +// that can be pruned once the VSCMaturedPacket with vscID is received. +// +// The following invariant needs to hold: +// For each consumer address cAddr in ValidatorByConsumerAddr, +// - either there exists a provider address pAddr in ValidatorConsumerPubKey, +// s.t. hash(ValidatorConsumerPubKey(pAddr)) = cAddr +// - or there exists a vscID in ConsumerAddrsToPrune s.t. cAddr in ConsumerAddrsToPrune(vscID) +func (k Keeper) AppendConsumerAddrsToPrune(ctx sdk.Context, chainID string, vscID uint64, consumerAddr sdk.ConsAddress) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ConsumerAddrsToPruneKey(chainID, vscID)) + var consumerAddrsToPrune types.AddressList + if bz != nil { + err := consumerAddrsToPrune.Unmarshal(bz) + if err != nil { + panic(err) + } + } + consumerAddrsToPrune.Addresses = append(consumerAddrsToPrune.Addresses, consumerAddr) + bz, err := consumerAddrsToPrune.Marshal() + if err != nil { + panic(err) + } + store.Set(types.ConsumerAddrsToPruneKey(chainID, vscID), bz) +} + +// GetConsumerAddrsToPrune returns the list of consumer addresses +// that can be pruned once the VSCMaturedPacket with vscID is received +func (k Keeper) GetConsumerAddrsToPrune( + ctx sdk.Context, + chainID string, + vscID uint64, +) (consumerAddrsToPrune types.AddressList) { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.ConsumerAddrsToPruneKey(chainID, vscID)) + if bz == nil { + return + } + err := consumerAddrsToPrune.Unmarshal(bz) + if err != nil { + panic(err) + } + return +} + +func (k Keeper) IterateConsumerAddrsToPrune( + ctx sdk.Context, + chainID string, + cb func(vscID uint64, consumerAddrsToPrune types.AddressList) (stop bool), +) { + store := ctx.KVStore(k.storeKey) + iteratorPrefix := types.ChainIdWithLenKey(types.ConsumerAddrsToPruneBytePrefix, chainID) + iterator := sdk.KVStorePrefixIterator(store, iteratorPrefix) + defer iterator.Close() + for ; iterator.Valid(); iterator.Next() { + _, vscID, err := types.ParseChainIdAndVscIdKey(types.ConsumerAddrsToPruneBytePrefix, iterator.Key()) + if err != nil { + panic(err) + } + var consumerAddrsToPrune types.AddressList + err = consumerAddrsToPrune.Unmarshal(iterator.Value()) + if err != nil { + panic(err) + } + stop := cb(vscID, consumerAddrsToPrune) + if stop { + break + } + } +} + +// DeleteConsumerAddrsToPrune deletes the list of consumer addresses mapped to a given VSC ID +func (k Keeper) DeleteConsumerAddrsToPrune(ctx sdk.Context, chainID string, vscID uint64) { + store := ctx.KVStore(k.storeKey) + store.Delete(types.ConsumerAddrsToPruneKey(chainID, vscID)) +} + +// AssignConsumerKey assigns the consumerKey to the validator with providerAddr +// on the consumer chain with ID chainID +func (k Keeper) AssignConsumerKey( + ctx sdk.Context, + chainID string, + validator stakingtypes.Validator, + consumerKey tmprotocrypto.PublicKey, +) error { + + consumerAddr := utils.TMCryptoPublicKeyToConsAddr(consumerKey) + + providerAddr, err := validator.GetConsAddr() + + if err != nil { + return err + } + + if existingVal, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consumerAddr); found { + // If there is a validator with using the consumer key to validate on the provider + // we prevent assigning the consumer key, unless the validator is assigning validator. + // This ensures that a validator joining the active set who has not explicitly assigned + // a consumer key, will be able to use their provider key as consumer key (as per default). + if existingVal.OperatorAddress != validator.OperatorAddress { + return sdkerrors.Wrapf( + types.ErrConsumerKeyInUse, "a different validator already uses the consumer key", + ) + } + } + + if _, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerAddr); found { + // consumer key is already in use + // prevent multiple validators from assigning the same key + return sdkerrors.Wrapf( + types.ErrConsumerKeyInUse, "a validator has assigned the consumer key already", + ) + } + + // check whether the consumer chain is already registered, + // i.e., a client to the consumer was already created + if _, consumerRegistered := k.GetConsumerClientId(ctx, chainID); consumerRegistered { + // get the previous key assigned for this validator on this consumer chain + oldConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + if found { + // mark this old consumer key as prunable once the VSCMaturedPacket + // for the current VSC ID is received; + // note: this state is removed on receiving the VSCMaturedPacket + k.AppendConsumerAddrsToPrune( + ctx, + chainID, + k.GetValidatorSetUpdateId(ctx), + utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey), + ) + } else { + // the validator had no key assigned on this consumer chain + providerKey, err := validator.TmConsPublicKey() + if err != nil { + return err + } + oldConsumerKey = providerKey + } + + // check whether the validator is valid, i.e., its power is positive + power := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator()) + if 0 < power { + // to enable multiple calls of AssignConsumerKey in the same block by the same validator + + // the key assignment replacement should not be overwritten + if _, _, found := k.GetKeyAssignmentReplacement(ctx, chainID, providerAddr); !found { + // store old key and current power for modifying the valset update in EndBlock; + // note: this state is deleted at the end of the block + k.SetKeyAssignmentReplacement( + ctx, + chainID, + providerAddr, + oldConsumerKey, + power, + ) + } + } + } else { + // if the consumer chain is not registered, then remove the mapping + // from the old consumer address to the provider address (if any) + // get the previous key assigned for this validator on this consumer chain + if oldConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr); found { + k.DeleteValidatorByConsumerAddr( + ctx, + chainID, + utils.TMCryptoPublicKeyToConsAddr(oldConsumerKey), + ) + } + } + + // set the mapping from this validator's provider address to the new consumer key; + // overwrite if already exists + // note: this state is deleted when the validator is removed from the staking module + k.SetValidatorConsumerPubKey(ctx, chainID, providerAddr, consumerKey) + + // set the mapping from this validator's new consensus address on the consumer + // to its consensus address on the provider; + // note: this state must be deleted through the pruning mechanism + k.SetValidatorByConsumerAddr(ctx, chainID, consumerAddr, providerAddr) + + return nil +} + +// ApplyKeyAssignmentToValUpdates applies the key assignment to the validator updates +// received from the staking module +func (k Keeper) ApplyKeyAssignmentToValUpdates( + ctx sdk.Context, + chainID string, + valUpdates []abci.ValidatorUpdate, +) (newUpdates []abci.ValidatorUpdate, err error) { + for _, valUpdate := range valUpdates { + providerAddr := utils.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey) + + // If a key assignment replacement is found, we remove the valupdate with the old consumer key, + // create two new valupdates, + // - setting the old consumer key's power to 0 + // - and setting the new consumer key's power to the power in the update + prevConsumerKey, _, found := k.GetKeyAssignmentReplacement(ctx, chainID, providerAddr) + if found { + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: prevConsumerKey, + Power: 0, + }) + + newConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + if !found { + return newUpdates, sdkerrors.Wrapf(types.ErrConsumerKeyNotFound, "consumer key not found for %s", providerAddr) + } + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: newConsumerKey, + Power: valUpdate.Power, + }) + k.DeleteKeyAssignmentReplacement(ctx, chainID, providerAddr) + } else { + // If a key assignment replacement is not found, we check if the validator's key is assigned. + // If it is, we replace the update containing the provider key with an update containing + // the consumer key. + // Note that this will always be the brach taken when creating the genesis state + // of a newly registered consumer chain. + consumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + if found { + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: consumerKey, + Power: valUpdate.Power, + }) + } else { + // keep the same update + newUpdates = append(newUpdates, valUpdate) + } + } + } + + // For any key assignment replacements that did not have a corresponding validator update already, + // set the old consumer key's power to 0 and the new consumer key's power to the + // power in the pending key assignment. + var addrToRemove []sdk.ConsAddress + k.IterateKeyAssignmentReplacements(ctx, chainID, func( + pAddr sdk.ConsAddress, + prevCKey tmprotocrypto.PublicKey, + power int64, + ) (stop bool) { + addrToRemove = append(addrToRemove, pAddr) + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: prevCKey, + Power: 0, + }) + + newConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, pAddr) + if !found { + err = sdkerrors.Wrapf(types.ErrConsumerKeyNotFound, "consumer key not found for %s", pAddr) + return true + } + newUpdates = append(newUpdates, abci.ValidatorUpdate{ + PubKey: newConsumerKey, + Power: power, + }) + + return false + }) + if err != nil { + return newUpdates, err + } + + // Remove the key assignment replacements + for _, addr := range addrToRemove { + k.DeleteKeyAssignmentReplacement(ctx, chainID, addr) + } + + return newUpdates, nil +} + +// GetProviderAddrFromConsumerAddr returns the consensus address of a validator with +// consAddr set as the consensus address on a consumer chain +func (k Keeper) GetProviderAddrFromConsumerAddr( + ctx sdk.Context, + chainID string, + consAddr sdk.ConsAddress, +) sdk.ConsAddress { + // check if this address is known only to the consumer chain + if providerConsAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consAddr); found { + return providerConsAddr + } + return consAddr +} + +// PruneKeyAssignments prunes the consumer addresses no longer needed +// as they cannot be referenced in slash requests (by a correct consumer) +func (k Keeper) PruneKeyAssignments(ctx sdk.Context, chainID string, vscID uint64) { + consumerAddrs := k.GetConsumerAddrsToPrune(ctx, chainID, vscID) + for _, addr := range consumerAddrs.Addresses { + k.DeleteValidatorByConsumerAddr(ctx, chainID, addr) + } + k.DeleteConsumerAddrsToPrune(ctx, chainID, vscID) +} + +// DeleteKeyAssignments deletes all the state needed for key assignments on a consumer chain +func (k Keeper) DeleteKeyAssignments(ctx sdk.Context, chainID string) { + // delete ValidatorConsumerPubKey + var addrs []sdk.ConsAddress + k.IterateValidatorConsumerPubKeys(ctx, chainID, func(providerAddr sdk.ConsAddress, _ tmprotocrypto.PublicKey) (stop bool) { + addrs = append(addrs, providerAddr) + return false // do not stop the iteration + }) + for _, addr := range addrs { + k.DeleteValidatorConsumerPubKey(ctx, chainID, addr) + } + // delete ValidatorsByConsumerAddr + addrs = nil + k.IterateValidatorsByConsumerAddr(ctx, chainID, func(consumerAddr sdk.ConsAddress, _ sdk.ConsAddress) (stop bool) { + addrs = append(addrs, consumerAddr) + return false // do not stop the iteration + }) + for _, addr := range addrs { + k.DeleteValidatorByConsumerAddr(ctx, chainID, addr) + } + // delete KeyAssignmentReplacements + addrs = nil + k.IterateKeyAssignmentReplacements(ctx, chainID, func(providerAddr sdk.ConsAddress, _ tmprotocrypto.PublicKey, _ int64) (stop bool) { + addrs = append(addrs, providerAddr) + return false // do not stop the iteration + }) + for _, addr := range addrs { + k.DeleteKeyAssignmentReplacement(ctx, chainID, addr) + } + // delete ValidatorConsumerPubKey + var ids []uint64 + k.IterateConsumerAddrsToPrune(ctx, chainID, func(vscID uint64, _ types.AddressList) (stop bool) { + ids = append(ids, vscID) + return false // do not stop the iteration + }) + for _, id := range ids { + k.DeleteConsumerAddrsToPrune(ctx, chainID, id) + } +} diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go new file mode 100644 index 0000000000..0bcd00b81e --- /dev/null +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -0,0 +1,1012 @@ +package keeper_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + cryptotestutil "github.com/cosmos/interchain-security/testutil/crypto" + testkeeper "github.com/cosmos/interchain-security/testutil/keeper" + "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" + + "math/rand" + + providerkeeper "github.com/cosmos/interchain-security/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/x/ccv/provider/types" + "github.com/cosmos/interchain-security/x/ccv/utils" + "github.com/golang/mock/gomock" +) + +type testAssignment struct { + chainID string + providerAddr sdk.ConsAddress + consumerAddr sdk.ConsAddress + consumerPubKey tmprotocrypto.PublicKey + pubKeyAndPower abci.ValidatorUpdate +} + +func TestValidatorConsumerPubKeyCRUD(t *testing.T) { + chainID := "consumer" + providerAddr := sdk.ConsAddress([]byte("providerAddr")) + consumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + keeper.SetValidatorConsumerPubKey(ctx, chainID, providerAddr, consumerKey) + + consumerPubKey, found := keeper.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + require.True(t, found, "consumer pubkey not found") + require.NotEmpty(t, consumerPubKey, "consumer pubkey is empty") + require.Equal(t, consumerPubKey, consumerKey) + + keeper.DeleteValidatorConsumerPubKey(ctx, chainID, providerAddr) + consumerPubKey, found = keeper.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) + require.False(t, found, "consumer pubkey was found") + require.Empty(t, consumerPubKey, "consumer pubkey was returned") + require.NotEqual(t, consumerPubKey, consumerKey) +} + +func TestIterateValidatorConsumerPubKeys(t *testing.T) { + + chainID := "consumer" + testAssignments := []testAssignment{ + { + providerAddr: sdk.ConsAddress([]byte("validator-1")), + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey(), + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-2")), + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey(), + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-3")), + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(3).TMProtoCryptoPublicKey(), + }, + } + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + for _, assignment := range testAssignments { + keeper.SetValidatorConsumerPubKey(ctx, chainID, assignment.providerAddr, assignment.consumerPubKey) + } + + result := []testAssignment{} + cbIterateAll := func(iteratorProviderAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool) { + result = append(result, testAssignment{ + providerAddr: iteratorProviderAddr, + consumerPubKey: consumerKey, + }) + return false + } + + keeper.IterateValidatorConsumerPubKeys(ctx, chainID, cbIterateAll) + require.Len(t, result, len(testAssignments), "incorrect result len - should be %d, got %d", len(testAssignments), len(result)) + + for i, res := range result { + require.Equal(t, testAssignments[i], res, "mismatched consumer key assignment in case %d", i) + } + + result = []testAssignment{} + cbIterateOne := func(iteratorProviderAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool) { + result = append(result, testAssignment{ + providerAddr: iteratorProviderAddr, + consumerPubKey: consumerKey, + }) + return true + } + + keeper.IterateValidatorConsumerPubKeys(ctx, chainID, cbIterateOne) + require.Len(t, result, 1, "incorrect result len - should be 1, got %d", len(result)) + + require.Equal(t, testAssignments[0], result[0], "mismatched consumer key assignment in iterate one") + +} + +func TestIterateAllValidatorConsumerPubKeys(t *testing.T) { + providerAddr := sdk.ConsAddress([]byte("validator-1")) + testAssignments := []testAssignment{ + { + chainID: "consumer-1", + providerAddr: providerAddr, + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey(), + }, + { + chainID: "consumer-2", + providerAddr: providerAddr, + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey(), + }, + { + chainID: "consumer-3", + providerAddr: providerAddr, + consumerPubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(3).TMProtoCryptoPublicKey(), + }, + } + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + for _, assignment := range testAssignments { + keeper.SetValidatorConsumerPubKey(ctx, assignment.chainID, assignment.providerAddr, assignment.consumerPubKey) + } + + result := []testAssignment{} + cbIterateAll := func(chainID string, iteratorProviderAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool) { + require.Equal(t, providerAddr, iteratorProviderAddr, "unexpected provider address in iterator - expecting just 1 provider address") + result = append(result, testAssignment{ + chainID: chainID, + providerAddr: iteratorProviderAddr, + consumerPubKey: consumerKey, + }) + return false + } + + keeper.IterateAllValidatorConsumerPubKeys(ctx, cbIterateAll) + require.Len(t, result, len(testAssignments), "incorrect result len - should be %d, got %d", len(testAssignments), len(result)) + + for i, res := range result { + require.Equal(t, testAssignments[i], res, "mismatched consumer key assignment in case %d", i) + } + + result = []testAssignment{} + cbIterateOne := func(chainID string, iteratorProviderAddr sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool) { + require.Equal(t, providerAddr, iteratorProviderAddr, "unexpected provider address in iterator - expecting just 1 provider address") + result = append(result, testAssignment{ + chainID: chainID, + providerAddr: iteratorProviderAddr, + consumerPubKey: consumerKey, + }) + return false + } + + keeper.IterateAllValidatorConsumerPubKeys(ctx, cbIterateOne) + require.Len(t, result, len(testAssignments), "incorrect result len - should be 1, got %d", len(result)) + + require.Equal(t, testAssignments[0], result[0], "mismatched consumer key assignment in iterate one") +} + +func TestValidatorByConsumerAddrCRUD(t *testing.T) { + chainID := "consumer" + providerAddr := sdk.ConsAddress([]byte("providerAddr")) + consumerAddr := sdk.ConsAddress([]byte("consumerAddr")) + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + keeper.SetValidatorByConsumerAddr(ctx, chainID, consumerAddr, providerAddr) + + providerAddrResult, found := keeper.GetValidatorByConsumerAddr(ctx, chainID, consumerAddr) + require.True(t, found, "provider address not found") + require.NotEmpty(t, providerAddrResult, "provider address is empty") + require.Equal(t, providerAddr, providerAddrResult) + + keeper.DeleteValidatorByConsumerAddr(ctx, chainID, consumerAddr) + providerAddrResult, found = keeper.GetValidatorByConsumerAddr(ctx, chainID, consumerAddr) + require.False(t, found, "provider address was found") + require.Empty(t, providerAddrResult, "provider address not empty") + require.NotEqual(t, providerAddr, providerAddrResult) +} + +func TestIterateValidatorsByConsumerAddr(t *testing.T) { + chainID := "consumer" + testAssignments := []testAssignment{ + { + providerAddr: sdk.ConsAddress([]byte("validator-1")), + consumerAddr: sdk.ConsAddress([]byte("consumer-1")), + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-2")), + consumerAddr: sdk.ConsAddress([]byte("consumer-2")), + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-3")), + consumerAddr: sdk.ConsAddress([]byte("consumer-3")), + }, + } + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + for _, assignment := range testAssignments { + keeper.SetValidatorByConsumerAddr(ctx, chainID, assignment.consumerAddr, assignment.providerAddr) + } + + result := []testAssignment{} + cbIterateAll := func(consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + result = append(result, testAssignment{ + providerAddr: providerAddr, + consumerAddr: consumerAddr, + }) + return false // continue iteration + } + + keeper.IterateValidatorsByConsumerAddr(ctx, chainID, cbIterateAll) + require.Len(t, result, len(testAssignments), "incorrect result len - should be %d, got %d", len(testAssignments), len(result)) + + for i, res := range result { + require.Equal(t, testAssignments[i], res, "mismatched consumer address assignment in case %d", i) + } + + result = []testAssignment{} + cbIterateOne := func(consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + result = append(result, testAssignment{ + providerAddr: providerAddr, + consumerAddr: consumerAddr, + }) + return true // stop after first + } + + keeper.IterateValidatorsByConsumerAddr(ctx, chainID, cbIterateOne) + require.Len(t, result, 1, "incorrect result len - should be 1, got %d", len(result)) + + require.Equal(t, testAssignments[0], result[0], "mismatched consumer address assignment in iterate one") +} + +func TestIterateAllValidatorsByConsumerAddr(t *testing.T) { + providerAddr := sdk.ConsAddress([]byte("validator-1")) + testAssignments := []testAssignment{ + { + chainID: "consumer-1", + providerAddr: providerAddr, + consumerAddr: sdk.ConsAddress([]byte("consumer-1")), + }, + { + chainID: "consumer-2", + providerAddr: providerAddr, + consumerAddr: sdk.ConsAddress([]byte("consumer-2")), + }, + { + chainID: "consumer-3", + providerAddr: providerAddr, + consumerAddr: sdk.ConsAddress([]byte("consumer-3")), + }, + } + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + for _, assignment := range testAssignments { + keeper.SetValidatorByConsumerAddr(ctx, assignment.chainID, assignment.consumerAddr, assignment.providerAddr) + } + + result := []testAssignment{} + cbIterateAll := func(chainID string, consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + result = append(result, testAssignment{ + chainID: chainID, + providerAddr: providerAddr, + consumerAddr: consumerAddr, + }) + return false // continue iteration + } + + keeper.IterateAllValidatorsByConsumerAddr(ctx, cbIterateAll) + require.Len(t, result, len(testAssignments), "incorrect result len - should be %d, got %d", len(testAssignments), len(result)) + + for i, res := range result { + require.Equal(t, testAssignments[i], res, "mismatched consumer address assignment in case %d", i) + } + + result = []testAssignment{} + cbIterateOne := func(chainID string, consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + result = append(result, testAssignment{ + chainID: chainID, + + providerAddr: providerAddr, + consumerAddr: consumerAddr, + }) + return true // stop after first + } + + keeper.IterateAllValidatorsByConsumerAddr(ctx, cbIterateOne) + require.Len(t, result, 1, "incorrect result len - should be 1, got %d", len(result)) + + require.Equal(t, testAssignments[0], result[0], "mismatched consumer address assignment in iterate one") +} + +func TestKeyAssignmentReplacementCRUD(t *testing.T) { + chainID := "consumer" + providerAddr := sdk.ConsAddress([]byte("providerAddr")) + expCPubKey := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey() + var expPower int64 = 100 + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + keeper.SetKeyAssignmentReplacement(ctx, chainID, providerAddr, expCPubKey, expPower) + + cPubKey, power, found := keeper.GetKeyAssignmentReplacement(ctx, chainID, providerAddr) + require.True(t, found, "key assignment replacement not found") + require.Equal(t, expCPubKey, cPubKey, "previous consumer key not matching") + require.Equal(t, expPower, power, "power not matching") + + keeper.DeleteKeyAssignmentReplacement(ctx, chainID, providerAddr) + _, _, found = keeper.GetKeyAssignmentReplacement(ctx, chainID, providerAddr) + require.False(t, found, "key assignment replacement found") +} + +func TestIterateKeyAssignmentReplacements(t *testing.T) { + chainID := "consumer" + testAssignments := []testAssignment{ + { + providerAddr: sdk.ConsAddress([]byte("validator-1")), + pubKeyAndPower: abci.ValidatorUpdate{ + Power: 100, + PubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey(), + }, + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-2")), + pubKeyAndPower: abci.ValidatorUpdate{ + Power: 100, + PubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey(), + }, + }, + { + providerAddr: sdk.ConsAddress([]byte("validator-3")), + pubKeyAndPower: abci.ValidatorUpdate{ + Power: 100, + PubKey: cryptotestutil.NewCryptoIdentityFromIntSeed(3).TMProtoCryptoPublicKey(), + }, + }, + } + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + for _, assignment := range testAssignments { + keeper.SetKeyAssignmentReplacement(ctx, chainID, assignment.providerAddr, assignment.pubKeyAndPower.PubKey, assignment.pubKeyAndPower.Power) + } + + result := []testAssignment{} + cbIterateAll := func(providerAddr sdk.ConsAddress, prevCKey tmprotocrypto.PublicKey, power int64) (stop bool) { + result = append(result, testAssignment{ + providerAddr: providerAddr, + pubKeyAndPower: abci.ValidatorUpdate{PubKey: prevCKey, Power: power}, + }) + return false // continue iteration + } + + keeper.IterateKeyAssignmentReplacements(ctx, chainID, cbIterateAll) + require.Len(t, result, len(testAssignments), "incorrect result len - should be %d, got %d", len(testAssignments), len(result)) + + for i, res := range result { + require.Equal(t, testAssignments[i], res, "mismatched key assignment replacement in case %d", i) + } + + result = []testAssignment{} + cbIterateOne := func(providerAddr sdk.ConsAddress, prevCKey tmprotocrypto.PublicKey, power int64) (stop bool) { + result = append(result, testAssignment{ + providerAddr: providerAddr, + pubKeyAndPower: abci.ValidatorUpdate{PubKey: prevCKey, Power: power}, + }) + return true // stop after first + } + + keeper.IterateKeyAssignmentReplacements(ctx, chainID, cbIterateOne) + require.Len(t, result, 1, "incorrect result len - should be 1, got %d", len(result)) + + require.Equal(t, testAssignments[0], result[0], "mismatched key assignment replacement in iterate one") +} + +func TestConsumerAddrsToPruneCRUD(t *testing.T) { + chainID := "consumer" + consumerAddr := sdk.ConsAddress([]byte("consumerAddr1")) + vscID := uint64(1) + + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + keeper.AppendConsumerAddrsToPrune(ctx, chainID, vscID, consumerAddr) + + addrToPrune := keeper.GetConsumerAddrsToPrune(ctx, chainID, vscID).Addresses + require.NotEmpty(t, addrToPrune, "address to prune is empty") + require.Len(t, addrToPrune, 1, "address to prune is not len 1") + require.Equal(t, sdk.ConsAddress(addrToPrune[0]), consumerAddr) + + keeper.DeleteConsumerAddrsToPrune(ctx, chainID, vscID) + addrToPrune = keeper.GetConsumerAddrsToPrune(ctx, chainID, vscID).Addresses + require.Empty(t, addrToPrune, "address to prune was returned") +} + +// checkCorrectPruningProperty checks that the pruning property is correct for a given +// consumer chain. See AppendConsumerAddrsToPrune for a formulation of the property. +func checkCorrectPruningProperty(ctx sdk.Context, k providerkeeper.Keeper, chainID string) bool { + /* + For each consumer address cAddr in ValidatorByConsumerAddr, + - either there exists a provider address pAddr in ValidatorConsumerPubKey, + s.t. hash(ValidatorConsumerPubKey(pAddr)) = cAddr + - or there exists a vscID in ConsumerAddrsToPrune s.t. cAddr in ConsumerAddrsToPrune(vscID) + */ + willBePruned := map[string]bool{} + k.IterateConsumerAddrsToPrune(ctx, chainID, func(vscID uint64, addrList providertypes.AddressList) (stop bool) { + for _, cAddr := range addrList.Addresses { + addr := sdk.ConsAddress(cAddr) + willBePruned[addr.String()] = true + } + return false + }) + good := true + k.IterateAllValidatorsByConsumerAddr(ctx, func(chainID string, consumerAddr sdk.ConsAddress, providerAddr sdk.ConsAddress) (stop bool) { + if _, ok := willBePruned[consumerAddr.String()]; ok { + // Address will be pruned, everything is fine. + return false + } + // Try to find a validator who has this consumer address currently assigned + isCurrentlyAssigned := false + k.IterateValidatorConsumerPubKeys(ctx, chainID, + func(_ sdk.ConsAddress, consumerKey tmprotocrypto.PublicKey) (stop bool) { + if utils.TMCryptoPublicKeyToConsAddr(consumerKey).Equals(consumerAddr) { + isCurrentlyAssigned = true + return true // stop iterating early + } + return false + }, + ) + if !isCurrentlyAssigned { + // Will not be pruned, and is not currently assigned: violation + good = false + return true // breakout early + } + return false + }) + return good +} + +func TestAssignConsensusKeyForConsumerChain(t *testing.T) { + + chainID := "chainID" + providerIdentities := []*cryptotestutil.CryptoIdentity{ + cryptotestutil.NewCryptoIdentityFromIntSeed(0), + cryptotestutil.NewCryptoIdentityFromIntSeed(1), + } + consumerIdentities := []*cryptotestutil.CryptoIdentity{ + cryptotestutil.NewCryptoIdentityFromIntSeed(2), + cryptotestutil.NewCryptoIdentityFromIntSeed(3), + } + + testCases := []struct { + name string + // State-mutating mockSetup specific to this test case + mockSetup func(sdk.Context, providerkeeper.Keeper, testkeeper.MockedKeepers) + doActions func(sdk.Context, providerkeeper.Keeper) + }{ + /* + 0. Consumer registered: Assign PK0->CK0 and retrieve PK0->CK0 + 1. Consumer registered: Assign PK0->CK0, PK0->CK1 and retrieve PK0->CK1 + 2. Consumer registered: Assign PK0->CK0, PK1->CK0 and error + 3. Consumer registered: Assign PK1->PK0 and error + 4. Consumer not registered: Assign PK0->CK0 and retrieve PK0->CK0 + 5. Consumer not registered: Assign PK0->CK0, PK0->CK1 and retrieve PK0->CK1 + 6. Consumer not registered: Assign PK0->CK0, PK1->CK0 and error + 7. Consumer not registered: Assign PK1->PK0 and error + */ + { + name: "0", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + ctx, providerIdentities[0].SDKValAddress(), + ).Return(int64(0)), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + k.SetConsumerClientId(ctx, chainID, "") + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[0].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "1", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + ctx, providerIdentities[0].SDKValAddress(), + ).Return(int64(0)), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[1].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + ctx, providerIdentities[0].SDKValAddress(), + ).Return(int64(0)), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + k.SetConsumerClientId(ctx, chainID, "") + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + err = k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[1].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[1].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "2", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + ctx, providerIdentities[0].SDKValAddress(), + ).Return(int64(0)), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + k.SetConsumerClientId(ctx, chainID, "") + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + err = k.AssignConsumerKey(ctx, chainID, + providerIdentities[1].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.Error(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[0].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "3", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + providerIdentities[0].SDKConsAddress(), + ).Return(providerIdentities[0].SDKStakingValidator(), true), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + k.SetConsumerClientId(ctx, chainID, "") + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[1].SDKStakingValidator(), + providerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.Error(t, err) + }, + }, + { + name: "4", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[0].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "5", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[1].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + err = k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[1].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[1].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "6", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + consumerIdentities[0].SDKConsAddress(), + ).Return(stakingtypes.Validator{}, false), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[0].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.NoError(t, err) + err = k.AssignConsumerKey(ctx, chainID, + providerIdentities[1].SDKStakingValidator(), + consumerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.Error(t, err) + providerAddr, found := k.GetValidatorByConsumerAddr(ctx, chainID, consumerIdentities[0].SDKConsAddress()) + require.True(t, found) + require.Equal(t, providerIdentities[0].SDKConsAddress(), providerAddr) + }, + }, + { + name: "7", + mockSetup: func(ctx sdk.Context, k providerkeeper.Keeper, mocks testkeeper.MockedKeepers) { + gomock.InOrder( + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, + providerIdentities[0].SDKConsAddress(), + ).Return(providerIdentities[0].SDKStakingValidator(), true), + ) + }, + doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { + err := k.AssignConsumerKey(ctx, chainID, + providerIdentities[1].SDKStakingValidator(), + providerIdentities[0].TMProtoCryptoPublicKey(), + ) + require.Error(t, err) + }, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + + tc.mockSetup(ctx, k, mocks) + tc.doActions(ctx, k) + require.True(t, checkCorrectPruningProperty(ctx, k, chainID)) + + ctrl.Finish() + }) + } +} + +// Represents the validator set of a chain +type ValSet struct { + identities []*cryptotestutil.CryptoIdentity + // indexed by same index as identities + power []int64 +} + +func CreateValSet(identities []*cryptotestutil.CryptoIdentity) ValSet { + return ValSet{ + identities: identities, + power: make([]int64, len(identities)), + } +} + +// Apply a list of validator power updates +func (vs *ValSet) apply(updates []abci.ValidatorUpdate) { + // precondition: updates must all have unique keys + // note: an insertion index should always be found + for _, u := range updates { + for i, id := range vs.identities { // n2 looping but n is tiny + // cons := sdk.ConsAddress(utils.GetChangePubKeyAddress(u)) + cons := utils.TMCryptoPublicKeyToConsAddr(u.PubKey) + if id.SDKConsAddress().Equals(cons) { + vs.power[i] = u.Power + } + } + + } +} + +// A key assignment action to be done +type Assignment struct { + val stakingtypes.Validator + ck tmprotocrypto.PublicKey +} + +// TestSimulatedAssignmentsAndUpdateApplication tests a series +// of simulated scenarios where random key assignments and validator +// set updates are generated. +func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { + + CHAINID := "chainID" + // The number of full test executions to run + NUM_EXECUTIONS := 100 + // Each test execution mimics the adding of a consumer chain and the + // assignments and power updates of several blocks + NUM_BLOCKS_PER_EXECUTION := 40 + // The number of validators to be simulated + NUM_VALIDATORS := 4 + // The number of keys that can be used. Keeping this number small is + // good because it increases the chance that different assignments will + // use the same keys, which is something we want to test. + NUM_ASSIGNABLE_KEYS := 12 + // The maximum number of key assignment actions to simulate in each + // simulated block, and before the consumer chain is registered. + NUM_ASSIGNMENTS_PER_BLOCK_MAX := 8 + + // Create some identities for the simulated provider validators to use + providerIDS := []*cryptotestutil.CryptoIdentity{} + // Create some identities which the provider validators can assign to the consumer chain + assignableIDS := []*cryptotestutil.CryptoIdentity{} + for i := 0; i < NUM_VALIDATORS; i++ { + providerIDS = append(providerIDS, cryptotestutil.NewCryptoIdentityFromIntSeed(i)) + } + // Notice that the assignable identities include the provider identities + for i := 0; i < NUM_VALIDATORS+NUM_ASSIGNABLE_KEYS; i++ { + assignableIDS = append(assignableIDS, cryptotestutil.NewCryptoIdentityFromIntSeed(i)) + } + + // Helper: simulates creation of staking module EndBlock updates. + getStakingUpdates := func() (ret []abci.ValidatorUpdate) { + // Get a random set of validators to update. It is important to test subsets of all validators. + validators := rand.Perm(len(providerIDS))[0:rand.Intn(len(providerIDS)+1)] + for _, i := range validators { + // Power 0, 1, or 2 represents + // deletion, update (from 0 or 2), update (from 0 or 1) + power := rand.Intn(3) + ret = append(ret, abci.ValidatorUpdate{ + PubKey: providerIDS[i].TMProtoCryptoPublicKey(), + Power: int64(power), + }) + } + return + } + + // Helper: simulates creation of assignment tx's to be done. + getAssignments := func() (ret []Assignment) { + for i, numAssignments := 0, rand.Intn(NUM_ASSIGNMENTS_PER_BLOCK_MAX); i < numAssignments; i++ { + randomIxP := rand.Intn(len(providerIDS)) + randomIxC := rand.Intn(len(assignableIDS)) + ret = append(ret, Assignment{ + val: providerIDS[randomIxP].SDKStakingValidator(), + ck: assignableIDS[randomIxC].TMProtoCryptoPublicKey(), + }) + } + return + } + + // Run a randomly simulated execution and test that desired properties hold + // Helper: run a randomly simulated scenario where a consumer chain is added + // (after key assignment actions are done), followed by a series of validator power updates + // and key assignments tx's. For each simulated 'block', the validator set replication + // properties and the pruning property are checked. + runRandomExecution := func() { + + k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + + // Create validator sets for the provider and consumer. These are used to check the validator set + // replication property. + providerValset := CreateValSet(providerIDS) + // NOTE: consumer must have space for provider identities because default key assignments are to provider keys + consumerValset := CreateValSet(assignableIDS) + // For each validator on the consumer, record the corresponding provider + // address as looked up on the provider using GetProviderAddrFromConsumerAddr + // at a given vscid. + // consumer consAddr -> vscid -> provider consAddr + historicSlashQueries := map[string]map[uint64]string{} + + // Sanity check that the validator set update is initialised to 0, for clarity. + require.Equal(t, k.GetValidatorSetUpdateId(ctx), uint64(0)) + + // Mock calls to GetLastValidatorPower to return directly from the providerValset + mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( + gomock.Any(), + gomock.Any(), + ).DoAndReturn(func(_ interface{}, valAddr sdk.ValAddress) int64 { + // When the mocked method is called, locate the appropriate validator + // in the provider valset and return its power. + for i, id := range providerIDS { + if id.SDKStakingValidator().GetOperator().Equals(valAddr) { + return providerValset.power[i] + } + } + panic("must find validator") + // This can be called 0 or more times per block depending on the random + // assignments that occur + }).AnyTimes() + + // This implements the assumption that all the provider IDS are added + // to the system at the beginning of the simulation. + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr( + gomock.Any(), + gomock.Any(), + ).DoAndReturn(func(_ interface{}, consP sdk.ConsAddress) (stakingtypes.Validator, bool) { + for _, id := range providerIDS { + if id.SDKConsAddress().Equals(consP) { + return id.SDKStakingValidator(), true + } + } + return stakingtypes.Validator{}, false + }).AnyTimes() + + // Helper: apply some updates to both the provider and consumer valsets + // and increment the provider vscid. + applyUpdatesAndIncrementVSCID := func(updates []abci.ValidatorUpdate) { + providerValset.apply(updates) + updates, err := k.ApplyKeyAssignmentToValUpdates(ctx, CHAINID, updates) + require.NoError(t, err) + consumerValset.apply(updates) + // Simulate the VSCID update in EndBlock + k.IncrementValidatorSetUpdateId(ctx) + } + + // Helper: apply some key assignment transactions to the system + applyAssignments := func(assignments []Assignment) { + for _, a := range assignments { + // ignore err return, it can be possible for an error to occur + _ = k.AssignConsumerKey(ctx, CHAINID, a.val, a.ck) + } + } + + // The consumer chain has not yet been registered + // Apply some randomly generated key assignments + applyAssignments(getAssignments()) + // And generate a random provider valset which, in the real system, will + // be put into the consumer genesis. + applyUpdatesAndIncrementVSCID(getStakingUpdates()) + + // Register the consumer chain + k.SetConsumerClientId(ctx, CHAINID, "") + + // Analogous to the last vscid received from the consumer in a maturity + // Used to check the correct pruning property + greatestPrunedVSCID := -1 + + // Simulate a number of 'blocks' + // Each block consists of a number of random key assignment tx's + // and a random set of validator power updates + for block := 0; block < NUM_BLOCKS_PER_EXECUTION; block++ { + + // Generate and apply assignments and power updates + applyAssignments(getAssignments()) + applyUpdatesAndIncrementVSCID(getStakingUpdates()) + + // Randomly fast forward the greatest pruned VSCID. This simulates + // delivery of maturity packets from the consumer chain. + prunedVscid := greatestPrunedVSCID + + // +1 and -1 because id was incremented (-1), (+1) to make upper bound inclusive + rand.Intn(int(k.GetValidatorSetUpdateId(ctx))+1-1-greatestPrunedVSCID) + k.PruneKeyAssignments(ctx, CHAINID, uint64(prunedVscid)) + greatestPrunedVSCID = prunedVscid + + /* + + Property: Validator Set Replication + Each validator set on the provider must be replicated on the consumer. + The property in the real system is somewhat weaker, because the consumer chain can + forward updates to tendermint in batches. + (See https://github.com/cosmos/ibc/blob/main/spec/app/ics-028-cross-chain-validation/system_model_and_properties.md#system-properties) + We test the stronger property, because we abstract over implementation of the consumer + chain. The stronger property implies the weaker property. + + */ + + // Check validator set replication forward direction + for i, idP := range providerValset.identities { + // For each active validator on the provider chain + if 0 < providerValset.power[i] { + // Get the assigned key + ck, found := k.GetValidatorConsumerPubKey(ctx, CHAINID, idP.SDKConsAddress()) + if !found { + // Use default if unassigned + ck = idP.TMProtoCryptoPublicKey() + } + consC := utils.TMCryptoPublicKeyToConsAddr(ck) + // Find the corresponding consumer validator (must always be found) + for j, idC := range consumerValset.identities { + if consC.Equals(idC.SDKConsAddress()) { + // Ensure powers are the same + require.Equal(t, providerValset.power[i], consumerValset.power[j]) + } + } + } + } + // Check validator set replication backward direction + for i := range consumerValset.identities { + // For each active validator on the consumer chain + consC := consumerValset.identities[i].SDKConsAddress() + if 0 < consumerValset.power[i] { + // Get the provider who assigned the key + consP := k.GetProviderAddrFromConsumerAddr(ctx, CHAINID, consC) + // Find the corresponding provider validator (must always be found) + for j, idP := range providerValset.identities { + if idP.SDKConsAddress().Equals(consP) { + // Ensure powers are the same + require.Equal(t, providerValset.power[j], consumerValset.power[i]) + } + } + } + } + + /* + Property: Pruning (bounded storage) + Check that all keys have been or will eventually be pruned. + */ + + require.True(t, checkCorrectPruningProperty(ctx, k, CHAINID)) + + /* + Property: Correct Consumer Initiated Slash Lookup + + Check that since the last pruning, it has never been possible to query + two different provider addresses from the same consumer address. + We know that the queried provider address was correct at least once, + from checking the validator set replication property. These two facts + together guarantee that the slash lookup is always correct. + */ + + // Build up the historicSlashQueries data structure + for i := range consumerValset.identities { + // For each active validator on the consumer chain + consC := consumerValset.identities[i].SDKConsAddress() + if 0 < consumerValset.power[i] { + // Get the provider who assigned the key + consP := k.GetProviderAddrFromConsumerAddr(ctx, CHAINID, consC) + + if _, found := historicSlashQueries[string(consC)]; !found { + historicSlashQueries[string(consC)] = map[uint64]string{} + } + + vscid := k.GetValidatorSetUpdateId(ctx) - 1 // -1 since it was incremented before + // Record the slash query result obtained at this block + historicSlashQueries[string(consC)][vscid] = string(consP) + } + } + + // Check that, for each address known the consumer at some block + // with vscid st. greatestPrunedVSCID < vscid, there were never + // conflicting slash query results. + for _, vscidToConsP := range historicSlashQueries { + seen := map[string]bool{} + for vscid, consP := range vscidToConsP { + if uint64(greatestPrunedVSCID) < vscid { + // The provider would have returned + seen[consP] = true + } + } + // No conflicts. + require.True(t, len(seen) < 2) + } + + } + ctrl.Finish() + } + + for i := 0; i < NUM_EXECUTIONS; i++ { + runRandomExecution() + } +} diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go new file mode 100644 index 0000000000..1147ed42f2 --- /dev/null +++ b/x/ccv/provider/keeper/msg_server.go @@ -0,0 +1,84 @@ +package keeper + +import ( + "context" + + cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/interchain-security/x/ccv/provider/types" + ccvtypes "github.com/cosmos/interchain-security/x/ccv/types" + tmstrings "github.com/tendermint/tendermint/libs/strings" +) + +type msgServer struct { + *Keeper +} + +// NewMsgServerImpl returns an implementation of the bank MsgServer interface +// for the provided Keeper. +func NewMsgServerImpl(keeper *Keeper) types.MsgServer { + return &msgServer{Keeper: keeper} +} + +var _ types.MsgServer = msgServer{} + +// CreateValidator defines a method for creating a new validator +func (k msgServer) AssignConsumerKey(goCtx context.Context, msg *types.MsgAssignConsumerKey) (*types.MsgAssignConsumerKeyResponse, error) { + ctx := sdk.UnwrapSDKContext(goCtx) + + // It is possible to assign keys for consumer chains that are not yet approved. + // TODO: In future, a mechanism will be added to limit assigning keys to chains + // which are approved or pending approval, only. + // Note that current attack potential is restricted because validators must sign + // the transaction, and the chainID size is limited. + + providerValidatorAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + return nil, err + } + + // validator must already be registered + validator, found := k.stakingKeeper.GetValidator(ctx, providerValidatorAddr) + if !found { + return nil, stakingtypes.ErrNoValidatorFound + } + + // make sure the consumer key is in the correct format + consumerSDKPublicKey, ok := msg.ConsumerKey.GetCachedValue().(cryptotypes.PubKey) + if !ok { + return nil, sdkerrors.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", consumerSDKPublicKey) + } + + // make sure the consumer key type is supported + cp := ctx.ConsensusParams() + if cp != nil && cp.Validator != nil { + if !tmstrings.StringInSlice(consumerSDKPublicKey.Type(), cp.Validator.PubKeyTypes) { + return nil, sdkerrors.Wrapf( + stakingtypes.ErrValidatorPubKeyTypeNotSupported, + "got: %s, expected: %s", consumerSDKPublicKey.Type(), cp.Validator.PubKeyTypes, + ) + } + } + + consumerTMPublicKey, err := cryptocodec.ToTmProtoPublicKey(consumerSDKPublicKey) + if err != nil { + return nil, err + } + + if err := k.Keeper.AssignConsumerKey(ctx, msg.ChainId, validator, consumerTMPublicKey); err != nil { + return nil, err + } + + ctx.EventManager().EmitEvents(sdk.Events{ + sdk.NewEvent( + ccvtypes.EventTypeAssignConsumerKey, + sdk.NewAttribute(ccvtypes.AttributeProviderValidatorAddress, msg.ProviderAddr), + sdk.NewAttribute(ccvtypes.AttributeConsumerConsensusPubKey, consumerSDKPublicKey.String()), + ), + }) + + return &types.MsgAssignConsumerKeyResponse{}, nil +} diff --git a/x/ccv/provider/keeper/proposal.go b/x/ccv/provider/keeper/proposal.go index d24629ba4f..05306c2e2e 100644 --- a/x/ccv/provider/keeper/proposal.go +++ b/x/ccv/provider/keeper/proposal.go @@ -16,6 +16,7 @@ import ( "github.com/cosmos/interchain-security/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/x/ccv/types" abci "github.com/tendermint/tendermint/abci/types" + tmtypes "github.com/tendermint/tendermint/types" consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" ) @@ -65,11 +66,20 @@ func (k Keeper) CreateConsumerClient(ctx sdk.Context, chainID string, clientState.TrustingPeriod = consumerUnbondingPeriod / time.Duration(k.GetTrustingPeriodFraction(ctx)) clientState.UnbondingPeriod = consumerUnbondingPeriod - // TODO: Allow for current validators to set different keys + consumerGen, validatorSetHash, err := k.MakeConsumerGenesis(ctx, chainID) + if err != nil { + return err + } + err = k.SetConsumerGenesis(ctx, chainID, consumerGen) + if err != nil { + return err + } + + // Create consensus state consensusState := ibctmtypes.NewConsensusState( ctx.BlockTime(), commitmenttypes.NewMerkleRoot([]byte(ibctmtypes.SentinelRoot)), - ctx.BlockHeader().NextValidatorsHash, + validatorSetHash, // use the hash of the updated initial valset ) clientID, err := k.clientKeeper.CreateClient(ctx, clientState, consensusState) @@ -78,15 +88,6 @@ func (k Keeper) CreateConsumerClient(ctx sdk.Context, chainID string, } k.SetConsumerClientId(ctx, chainID, clientID) - consumerGen, err := k.MakeConsumerGenesis(ctx) - if err != nil { - return err - } - err = k.SetConsumerGenesis(ctx, chainID, consumerGen) - if err != nil { - return err - } - // add the init timeout timestamp for this consumer chain ts := ctx.BlockTime().Add(k.GetParams(ctx).InitTimeoutPeriod) k.SetInitTimeoutTimestamp(ctx, chainID, uint64(ts.UnixNano())) @@ -146,6 +147,7 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, lockUbd, clos k.DeleteConsumerGenesis(ctx, chainID) k.DeleteLockUnbondingOnTimeout(ctx, chainID) k.DeleteInitTimeoutTimestamp(ctx, chainID) + k.DeleteKeyAssignments(ctx, chainID) // close channel and delete the mappings between chain ID and channel ID if channelID, found := k.GetChainToChannel(ctx, chainID); found { @@ -216,7 +218,7 @@ func (k Keeper) StopConsumerChain(ctx sdk.Context, chainID string, lockUbd, clos } // MakeConsumerGenesis constructs the consumer CCV module part of the genesis state. -func (k Keeper) MakeConsumerGenesis(ctx sdk.Context) (gen consumertypes.GenesisState, err error) { +func (k Keeper) MakeConsumerGenesis(ctx sdk.Context, chainID string) (gen consumertypes.GenesisState, nextValidatorsHash []byte, err error) { providerUnbondingPeriod := k.stakingKeeper.UnbondingTime(ctx) height := clienttypes.GetSelfHeight(ctx) @@ -231,7 +233,7 @@ func (k Keeper) MakeConsumerGenesis(ctx sdk.Context) (gen consumertypes.GenesisS consState, err := k.clientKeeper.GetSelfConsensusState(ctx, height) if err != nil { - return gen, sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "error %s getting self consensus state for: %s", err, height) + return gen, nil, sdkerrors.Wrapf(clienttypes.ErrConsensusStateNotFound, "error %s getting self consensus state for: %s", err, height) } gen = *consumertypes.DefaultGenesisState() @@ -274,9 +276,20 @@ func (k Keeper) MakeConsumerGenesis(ctx sdk.Context) (gen consumertypes.GenesisS }) } - gen.InitialValSet = updates + // apply key assignments to the initial valset + gen.InitialValSet, err = k.ApplyKeyAssignmentToValUpdates(ctx, chainID, updates) + if err != nil { + panic("unable to apply key assignments to the initial valset") + } + + // Get a hash of the consumer validator set from the update. + updatesAsValSet, err := tmtypes.PB2TM.ValidatorUpdates(gen.InitialValSet) + if err != nil { + panic("unable to create validator set from updates computed from key assignment in MakeConsumerGenesis") + } + hash := tmtypes.NewValidatorSet(updatesAsValSet).Hash() - return gen, nil + return gen, hash, nil } // SetPendingConsumerAdditionProp stores a pending proposal to create a consumer chain client diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index 215fc91a0b..fa68d06884 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -11,6 +11,7 @@ import ( ibctmtypes "github.com/cosmos/ibc-go/v3/modules/light-clients/07-tendermint/types" "github.com/golang/mock/gomock" abci "github.com/tendermint/tendermint/abci/types" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" "github.com/stretchr/testify/require" @@ -476,6 +477,32 @@ func testProviderStateIsCleaned(t *testing.T, ctx sdk.Context, providerKeeper pr return true // stop the iteration }) require.False(t, found) + + // test key assignment state is cleaned + found = false + providerKeeper.IterateValidatorConsumerPubKeys(ctx, expectedChainID, func(_ sdk.ConsAddress, _ tmprotocrypto.PublicKey) (stop bool) { + found = true + return true // stop the iteration + }) + require.False(t, found) + found = false + providerKeeper.IterateValidatorsByConsumerAddr(ctx, expectedChainID, func(_ sdk.ConsAddress, _ sdk.ConsAddress) (stop bool) { + found = true + return true // stop the iteration + }) + require.False(t, found) + found = false + providerKeeper.IterateKeyAssignmentReplacements(ctx, expectedChainID, func(_ sdk.ConsAddress, _ tmprotocrypto.PublicKey, _ int64) (stop bool) { + found = true + return true // stop the iteration + }) + require.False(t, found) + found = false + providerKeeper.IterateConsumerAddrsToPrune(ctx, expectedChainID, func(_ uint64, _ types.AddressList) (stop bool) { + found = true + return true // stop the iteration + }) + require.False(t, found) } // TestPendingConsumerRemovalPropDeletion tests the getting/setting @@ -651,7 +678,7 @@ func TestMakeConsumerGenesis(t *testing.T) { ctx = ctx.WithBlockHeight(5) // RevisionHeight obtained from ctx gomock.InOrder(testkeeper.GetMocksForMakeConsumerGenesis(ctx, &mocks, 1814400000000000)...) - actualGenesis, err := providerKeeper.MakeConsumerGenesis(ctx) + actualGenesis, _, err := providerKeeper.MakeConsumerGenesis(ctx, "testchain2") require.NoError(t, err) jsonString := `{"params":{"enabled":true, "blocks_per_distribution_transmission":1000, "ccv_timeout_period":2419200000000000, "transfer_timeout_period": 3600000000000, "consumer_redistribution_fraction":"0.75", "historical_entries":10000, "unbonding_period": 1728000000000000},"new_chain":true,"provider_client_state":{"chain_id":"testchain1","trust_level":{"numerator":1,"denominator":3},"trusting_period":907200000000000,"unbonding_period":1814400000000000,"max_clock_drift":10000000000,"frozen_height":{},"latest_height":{"revision_height":5},"proof_specs":[{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":33,"min_prefix_length":4,"max_prefix_length":12,"hash":1}},{"leaf_spec":{"hash":1,"prehash_value":1,"length":1,"prefix":"AA=="},"inner_spec":{"child_order":[0,1],"child_size":32,"min_prefix_length":1,"max_prefix_length":1,"hash":1}}],"upgrade_path":["upgrade","upgradedIBCState"],"allow_update_after_expiry":true,"allow_update_after_misbehaviour":true},"provider_consensus_state":{"timestamp":"2020-01-02T00:00:10Z","root":{"hash":"LpGpeyQVLUo9HpdsgJr12NP2eCICspcULiWa5u9udOA="},"next_validators_hash":"E30CE736441FB9101FADDAF7E578ABBE6DFDB67207112350A9A904D554E1F5BE"},"unbonding_sequences":null,"initial_val_set":[{"pub_key":{"type":"tendermint/PubKeyEd25519","value":"dcASx5/LIKZqagJWN0frOlFtcvz91frYmj/zmoZRWro="},"power":1}]}` diff --git a/x/ccv/provider/keeper/relay.go b/x/ccv/provider/keeper/relay.go index 2235941e4a..dec7d6fe6b 100644 --- a/x/ccv/provider/keeper/relay.go +++ b/x/ccv/provider/keeper/relay.go @@ -81,6 +81,9 @@ func (k Keeper) HandleVSCMaturedPacket(ctx sdk.Context, chainID string, data ccv // remove the VSC timeout timestamp for this chainID and vscID k.DeleteVscSendTimestamp(ctx, chainID, data.ValsetUpdateId) + + // prune previous consumer validator address that are no longer needed + k.PruneKeyAssignments(ctx, chainID, data.ValsetUpdateId) } // CompleteMaturedUnbondingOps attempts to complete all matured unbonding operations @@ -197,6 +200,12 @@ func (k Keeper) QueueVSCPackets(ctx sdk.Context) { valUpdates := k.stakingKeeper.GetValidatorUpdates(ctx) k.IterateConsumerChains(ctx, func(ctx sdk.Context, chainID, clientID string) (stop bool) { + // apply the key assignment to the validator updates + valUpdates, err := k.ApplyKeyAssignmentToValUpdates(ctx, chainID, valUpdates) + if err != nil { + panic(fmt.Sprintf("could not apply key assignment to validator updates for chain %s: %s", chainID, err.Error())) + } + // check whether there are changes in the validator set; // note that this also entails unbonding operations // w/o changes in the voting power of the validators in the validator set @@ -265,11 +274,12 @@ func (k Keeper) ValidateSlashPacket(ctx sdk.Context, chainID string, // HandleSlashPacket potentially slashes, jails and/or tombstones // a misbehaving validator according to infraction type. func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.SlashPacketData) { - - // Get the validator - consAddr := sdk.ConsAddress(data.Validator.Address) - // TODO: Key assignment will change the following line - validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr) + // the slash packet validator address may be known only on the consumer chain; + // in this case, it must be mapped back to the consensus address on the provider chain + consumerAddr := sdk.ConsAddress(data.Validator.Address) + providerAddr := k.GetProviderAddrFromConsumerAddr(ctx, chainID, consumerAddr) + // get the validator + validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr) // make sure the validator is not yet unbonded; // stakingKeeper.Slash() panics otherwise @@ -283,11 +293,11 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas } // tombstoned validators should not be slashed multiple times. - if k.slashingKeeper.IsTombstoned(ctx, consAddr) { + if k.slashingKeeper.IsTombstoned(ctx, providerAddr) { // Log and drop packet if validator is tombstoned. k.Logger(ctx).Info( "slash packet dropped because validator is already tombstoned", - "validator cons addr", consAddr, + "validator cons addr", providerAddr, ) return } @@ -312,19 +322,19 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas // then append the validator address to the slash ack for its chain id slashFraction = k.slashingKeeper.SlashFractionDowntime(ctx) jailTime = ctx.BlockTime().Add(k.slashingKeeper.DowntimeJailDuration(ctx)) - k.AppendSlashAck(ctx, chainID, consAddr.String()) + k.AppendSlashAck(ctx, chainID, providerAddr.String()) case stakingtypes.DoubleSign: // set double-signing slash fraction and infinite jail duration // then tombstone the validator slashFraction = k.slashingKeeper.SlashFractionDoubleSign(ctx) jailTime = evidencetypes.DoubleSignJailEndTime - k.slashingKeeper.Tombstone(ctx, consAddr) + k.slashingKeeper.Tombstone(ctx, providerAddr) } // slash validator k.stakingKeeper.Slash( ctx, - consAddr, + providerAddr, int64(infractionHeight), data.Validator.Power, slashFraction, @@ -333,15 +343,16 @@ func (k Keeper) HandleSlashPacket(ctx sdk.Context, chainID string, data ccv.Slas // jail validator if !validator.IsJailed() { - k.stakingKeeper.Jail(ctx, consAddr) + k.stakingKeeper.Jail(ctx, providerAddr) } - k.slashingKeeper.JailUntil(ctx, consAddr, jailTime) + k.slashingKeeper.JailUntil(ctx, providerAddr, jailTime) ctx.EventManager().EmitEvent( sdk.NewEvent( ccv.EventTypeExecuteConsumerChainSlash, sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName), - sdk.NewAttribute(ccv.AttributeValidatorAddress, consAddr.String()), + sdk.NewAttribute(ccv.AttributeValidatorAddress, providerAddr.String()), + sdk.NewAttribute(ccv.AttributeValidatorConsumerAddress, consumerAddr.String()), sdk.NewAttribute(ccv.AttributeInfractionType, data.Infraction.String()), sdk.NewAttribute(ccv.AttributeInfractionHeight, strconv.Itoa(int(infractionHeight))), sdk.NewAttribute(ccv.AttributeValSetUpdateID, strconv.Itoa(int(data.ValsetUpdateId))), diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index dca9eb0343..e904dab3d8 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -80,7 +80,7 @@ func (AppModuleBasic) RegisterGRPCGatewayRoutes(clientCtx client.Context, mux *r // GetTxCmd implements AppModuleBasic interface // TODO func (AppModuleBasic) GetTxCmd() *cobra.Command { - return nil + return cli.GetTxCmd() } // GetQueryCmd implements AppModuleBasic interface @@ -125,6 +125,7 @@ func (am AppModule) LegacyQuerierHandler(*codec.LegacyAmino) sdk.Querier { // RegisterServices registers module services. // TODO func (am AppModule) RegisterServices(cfg module.Configurator) { + providertypes.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) providertypes.RegisterQueryServer(cfg.QueryServer(), am.keeper) } diff --git a/x/ccv/provider/module_test.go b/x/ccv/provider/module_test.go index c8ab78de94..521b091652 100644 --- a/x/ccv/provider/module_test.go +++ b/x/ccv/provider/module_test.go @@ -102,7 +102,11 @@ func TestInitGenesis(t *testing.T) { nil, nil, nil, - nil, types.DefaultParams(), + nil, + types.DefaultParams(), + nil, + nil, + nil, ) cdc := keeperParams.Cdc diff --git a/x/ccv/provider/types/codec.go b/x/ccv/provider/types/codec.go index bb55872f19..e19308ba88 100644 --- a/x/ccv/provider/types/codec.go +++ b/x/ccv/provider/types/codec.go @@ -3,6 +3,8 @@ package types import ( "github.com/cosmos/cosmos-sdk/codec" codectypes "github.com/cosmos/cosmos-sdk/codec/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/msgservice" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" ) @@ -21,6 +23,11 @@ func RegisterInterfaces(registry codectypes.InterfaceRegistry) { (*govtypes.Content)(nil), &ConsumerRemovalProposal{}, ) + registry.RegisterImplementations( + (*sdk.Msg)(nil), + &MsgAssignConsumerKey{}, + ) + msgservice.RegisterMsgServiceDesc(registry, &_Msg_serviceDesc) } var ( diff --git a/x/ccv/provider/types/errors.go b/x/ccv/provider/types/errors.go index decd79474b..c243422093 100644 --- a/x/ccv/provider/types/errors.go +++ b/x/ccv/provider/types/errors.go @@ -10,4 +10,10 @@ var ( ErrInvalidConsumerRemovalProp = sdkerrors.Register(ModuleName, 2, "invalid consumer removal proposal") ErrUnknownConsumerChainId = sdkerrors.Register(ModuleName, 3, "no consumer chain with this chain id") ErrUnknownConsumerChannelId = sdkerrors.Register(ModuleName, 4, "no consumer chain with this channel id") + ErrInvalidConsumerConsensusPubKey = sdkerrors.Register(ModuleName, 5, "empty consumer consensus public key") + ErrBlankConsumerChainID = sdkerrors.Register(ModuleName, 6, "consumer chain id must not be blank") + ErrConsumerKeyNotFound = sdkerrors.Register(ModuleName, 7, "consumer key not found") + ErrNoValidatorConsumerAddress = sdkerrors.Register(ModuleName, 8, "error getting validator consumer address") + ErrNoValidatorProviderAddress = sdkerrors.Register(ModuleName, 9, "error getting validator provider address") + ErrConsumerKeyInUse = sdkerrors.Register(ModuleName, 10, "consumer key is already in use by a validator") ) diff --git a/x/ccv/provider/types/genesis.go b/x/ccv/provider/types/genesis.go index 47e5d51e33..5cecaab19f 100644 --- a/x/ccv/provider/types/genesis.go +++ b/x/ccv/provider/types/genesis.go @@ -18,6 +18,9 @@ func NewGenesisState( additionProposals []ConsumerAdditionProposal, removalProposals []ConsumerRemovalProposal, params Params, + validatorConsumerPubkeys []ValidatorConsumerPubKey, + validatorsByConsumerAddr []ValidatorByConsumerAddr, + consumerAddrsToPrune []ConsumerAddrsToPrune, ) *GenesisState { return &GenesisState{ ValsetUpdateId: vscID, @@ -28,6 +31,9 @@ func NewGenesisState( ConsumerAdditionProposals: additionProposals, ConsumerRemovalProposals: removalProposals, Params: params, + ValidatorConsumerPubkeys: validatorConsumerPubkeys, + ValidatorsByConsumerAddr: validatorsByConsumerAddr, + ConsumerAddrsToPrune: consumerAddrsToPrune, } } diff --git a/x/ccv/provider/types/genesis.pb.go b/x/ccv/provider/types/genesis.pb.go index e8f303082c..4e675f9b24 100644 --- a/x/ccv/provider/types/genesis.pb.go +++ b/x/ccv/provider/types/genesis.pb.go @@ -9,6 +9,7 @@ import ( types "github.com/cosmos/interchain-security/x/ccv/types" _ "github.com/gogo/protobuf/gogoproto" proto "github.com/gogo/protobuf/proto" + crypto "github.com/tendermint/tendermint/proto/tendermint/crypto" io "io" math "math" math_bits "math/bits" @@ -42,6 +43,12 @@ type GenesisState struct { // empty for a new chain ConsumerRemovalProposals []ConsumerRemovalProposal `protobuf:"bytes,7,rep,name=consumer_removal_proposals,json=consumerRemovalProposals,proto3" json:"consumer_removal_proposals"` Params Params `protobuf:"bytes,8,opt,name=params,proto3" json:"params"` + // empty for a new chain + ValidatorConsumerPubkeys []ValidatorConsumerPubKey `protobuf:"bytes,9,rep,name=validator_consumer_pubkeys,json=validatorConsumerPubkeys,proto3" json:"validator_consumer_pubkeys"` + // empty for a new chain + ValidatorsByConsumerAddr []ValidatorByConsumerAddr `protobuf:"bytes,10,rep,name=validators_by_consumer_addr,json=validatorsByConsumerAddr,proto3" json:"validators_by_consumer_addr"` + // empty for a new chain + ConsumerAddrsToPrune []ConsumerAddrsToPrune `protobuf:"bytes,11,rep,name=consumer_addrs_to_prune,json=consumerAddrsToPrune,proto3" json:"consumer_addrs_to_prune"` } func (m *GenesisState) Reset() { *m = GenesisState{} } @@ -133,6 +140,27 @@ func (m *GenesisState) GetParams() Params { return Params{} } +func (m *GenesisState) GetValidatorConsumerPubkeys() []ValidatorConsumerPubKey { + if m != nil { + return m.ValidatorConsumerPubkeys + } + return nil +} + +func (m *GenesisState) GetValidatorsByConsumerAddr() []ValidatorByConsumerAddr { + if m != nil { + return m.ValidatorsByConsumerAddr + } + return nil +} + +func (m *GenesisState) GetConsumerAddrsToPrune() []ConsumerAddrsToPrune { + if m != nil { + return m.ConsumerAddrsToPrune + } + return nil +} + // consumer chain type ConsumerState struct { // ChainID defines the chain ID for the consumer chain @@ -359,11 +387,200 @@ func (m *ValsetUpdateIdToHeight) GetHeight() uint64 { return 0 } +// Used to serialize the ValidatorConsumerPubKey index from key assignment +// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey +type ValidatorConsumerPubKey struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ProviderAddr []byte `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` + ConsumerKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"` +} + +func (m *ValidatorConsumerPubKey) Reset() { *m = ValidatorConsumerPubKey{} } +func (m *ValidatorConsumerPubKey) String() string { return proto.CompactTextString(m) } +func (*ValidatorConsumerPubKey) ProtoMessage() {} +func (*ValidatorConsumerPubKey) Descriptor() ([]byte, []int) { + return fileDescriptor_48411d9c7900d48e, []int{4} +} +func (m *ValidatorConsumerPubKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorConsumerPubKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorConsumerPubKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ValidatorConsumerPubKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorConsumerPubKey.Merge(m, src) +} +func (m *ValidatorConsumerPubKey) XXX_Size() int { + return m.Size() +} +func (m *ValidatorConsumerPubKey) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorConsumerPubKey.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorConsumerPubKey proto.InternalMessageInfo + +func (m *ValidatorConsumerPubKey) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ValidatorConsumerPubKey) GetProviderAddr() []byte { + if m != nil { + return m.ProviderAddr + } + return nil +} + +func (m *ValidatorConsumerPubKey) GetConsumerKey() *crypto.PublicKey { + if m != nil { + return m.ConsumerKey + } + return nil +} + +// Used to serialize the ValidatorConsumerAddr index from key assignment +// ValidatorByConsumerAddr: (chainID, consumerAddr consAddr) -> providerAddr consAddr +type ValidatorByConsumerAddr struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + ConsumerAddr []byte `protobuf:"bytes,2,opt,name=consumer_addr,json=consumerAddr,proto3" json:"consumer_addr,omitempty"` + ProviderAddr []byte `protobuf:"bytes,3,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty"` +} + +func (m *ValidatorByConsumerAddr) Reset() { *m = ValidatorByConsumerAddr{} } +func (m *ValidatorByConsumerAddr) String() string { return proto.CompactTextString(m) } +func (*ValidatorByConsumerAddr) ProtoMessage() {} +func (*ValidatorByConsumerAddr) Descriptor() ([]byte, []int) { + return fileDescriptor_48411d9c7900d48e, []int{5} +} +func (m *ValidatorByConsumerAddr) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ValidatorByConsumerAddr) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ValidatorByConsumerAddr.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ValidatorByConsumerAddr) XXX_Merge(src proto.Message) { + xxx_messageInfo_ValidatorByConsumerAddr.Merge(m, src) +} +func (m *ValidatorByConsumerAddr) XXX_Size() int { + return m.Size() +} +func (m *ValidatorByConsumerAddr) XXX_DiscardUnknown() { + xxx_messageInfo_ValidatorByConsumerAddr.DiscardUnknown(m) +} + +var xxx_messageInfo_ValidatorByConsumerAddr proto.InternalMessageInfo + +func (m *ValidatorByConsumerAddr) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ValidatorByConsumerAddr) GetConsumerAddr() []byte { + if m != nil { + return m.ConsumerAddr + } + return nil +} + +func (m *ValidatorByConsumerAddr) GetProviderAddr() []byte { + if m != nil { + return m.ProviderAddr + } + return nil +} + +// Used to serialize the ConsumerAddrsToPrune index from key assignment +// ConsumerAddrsToPrune: (chainID, vscID uint64) -> consumerAddrsToPrune [][]byte +type ConsumerAddrsToPrune struct { + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + VscId uint64 `protobuf:"varint,2,opt,name=vsc_id,json=vscId,proto3" json:"vsc_id,omitempty"` + ConsumerAddrs *AddressList `protobuf:"bytes,3,opt,name=consumer_addrs,json=consumerAddrs,proto3" json:"consumer_addrs,omitempty"` +} + +func (m *ConsumerAddrsToPrune) Reset() { *m = ConsumerAddrsToPrune{} } +func (m *ConsumerAddrsToPrune) String() string { return proto.CompactTextString(m) } +func (*ConsumerAddrsToPrune) ProtoMessage() {} +func (*ConsumerAddrsToPrune) Descriptor() ([]byte, []int) { + return fileDescriptor_48411d9c7900d48e, []int{6} +} +func (m *ConsumerAddrsToPrune) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *ConsumerAddrsToPrune) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_ConsumerAddrsToPrune.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *ConsumerAddrsToPrune) XXX_Merge(src proto.Message) { + xxx_messageInfo_ConsumerAddrsToPrune.Merge(m, src) +} +func (m *ConsumerAddrsToPrune) XXX_Size() int { + return m.Size() +} +func (m *ConsumerAddrsToPrune) XXX_DiscardUnknown() { + xxx_messageInfo_ConsumerAddrsToPrune.DiscardUnknown(m) +} + +var xxx_messageInfo_ConsumerAddrsToPrune proto.InternalMessageInfo + +func (m *ConsumerAddrsToPrune) GetChainId() string { + if m != nil { + return m.ChainId + } + return "" +} + +func (m *ConsumerAddrsToPrune) GetVscId() uint64 { + if m != nil { + return m.VscId + } + return 0 +} + +func (m *ConsumerAddrsToPrune) GetConsumerAddrs() *AddressList { + if m != nil { + return m.ConsumerAddrs + } + return nil +} + func init() { proto.RegisterType((*GenesisState)(nil), "interchain_security.ccv.provider.v1.GenesisState") proto.RegisterType((*ConsumerState)(nil), "interchain_security.ccv.provider.v1.ConsumerState") proto.RegisterType((*UnbondingOpIndex)(nil), "interchain_security.ccv.provider.v1.UnbondingOpIndex") proto.RegisterType((*ValsetUpdateIdToHeight)(nil), "interchain_security.ccv.provider.v1.ValsetUpdateIdToHeight") + proto.RegisterType((*ValidatorConsumerPubKey)(nil), "interchain_security.ccv.provider.v1.ValidatorConsumerPubKey") + proto.RegisterType((*ValidatorByConsumerAddr)(nil), "interchain_security.ccv.provider.v1.ValidatorByConsumerAddr") + proto.RegisterType((*ConsumerAddrsToPrune)(nil), "interchain_security.ccv.provider.v1.ConsumerAddrsToPrune") } func init() { @@ -371,57 +588,72 @@ func init() { } var fileDescriptor_48411d9c7900d48e = []byte{ - // 794 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x5d, 0x6f, 0xf3, 0x34, - 0x14, 0x6e, 0xd6, 0xd2, 0xb7, 0xf5, 0xfb, 0x6e, 0x14, 0x33, 0x55, 0x59, 0x5f, 0xd1, 0x55, 0x05, - 0x44, 0x25, 0x46, 0xa2, 0x14, 0x21, 0xc1, 0x80, 0x8b, 0x7d, 0x48, 0xd0, 0x0b, 0xc4, 0x94, 0x7d, - 0x5c, 0xec, 0x26, 0x72, 0x1d, 0xab, 0x35, 0x4d, 0xec, 0x28, 0x76, 0xc2, 0x26, 0x84, 0x84, 0xc4, - 0x1f, 0xe0, 0x0f, 0x21, 0x6e, 0x77, 0xb9, 0x4b, 0xae, 0x26, 0xb4, 0xfd, 0x03, 0x7e, 0x01, 0x8a, - 0xe3, 0x76, 0x69, 0xd5, 0x8e, 0xf6, 0x2e, 0x39, 0x8f, 0x9f, 0xe7, 0x3c, 0x3e, 0x3e, 0x3e, 0x06, - 0x0e, 0x65, 0x92, 0xc4, 0x78, 0x8c, 0x28, 0xf3, 0x04, 0xc1, 0x49, 0x4c, 0xe5, 0xad, 0x8d, 0x71, - 0x6a, 0x47, 0x31, 0x4f, 0xa9, 0x4f, 0x62, 0x3b, 0x75, 0xec, 0x11, 0x61, 0x44, 0x50, 0x61, 0x45, - 0x31, 0x97, 0x1c, 0x7e, 0xb8, 0x84, 0x62, 0x61, 0x9c, 0x5a, 0x53, 0x8a, 0x95, 0x3a, 0xad, 0xdd, - 0x11, 0x1f, 0x71, 0xb5, 0xde, 0xce, 0xbe, 0x72, 0x6a, 0xeb, 0xa3, 0x55, 0xd9, 0x52, 0xc7, 0xd6, - 0x0a, 0x92, 0xb7, 0xfa, 0xeb, 0x78, 0x9a, 0x25, 0xfb, 0x1f, 0x0e, 0xe6, 0x4c, 0x24, 0x61, 0xce, - 0x99, 0x7e, 0x6b, 0x8e, 0xb3, 0x0e, 0x67, 0x6e, 0xef, 0xdd, 0xbf, 0xaa, 0xe0, 0xcd, 0x77, 0x79, - 0xe4, 0x5c, 0x22, 0x49, 0x60, 0x0f, 0x34, 0x52, 0x14, 0x08, 0x22, 0xbd, 0x24, 0xf2, 0x91, 0x24, - 0x1e, 0xf5, 0x4d, 0xa3, 0x63, 0xf4, 0x2a, 0xee, 0x4e, 0x1e, 0xbf, 0x54, 0xe1, 0x81, 0x0f, 0x7f, - 0x01, 0xef, 0x4e, 0x75, 0x3d, 0x91, 0x71, 0x85, 0xb9, 0xd5, 0x29, 0xf7, 0x5e, 0xf7, 0xfb, 0xd6, - 0x1a, 0x05, 0xb5, 0x4e, 0x34, 0x57, 0xa5, 0x3d, 0x6e, 0xdf, 0x3d, 0xec, 0x97, 0xfe, 0x7d, 0xd8, - 0x6f, 0xde, 0xa2, 0x30, 0x38, 0xec, 0x2e, 0x08, 0x77, 0xdd, 0x1d, 0x5c, 0x5c, 0x2e, 0xa0, 0x0b, - 0xb6, 0x13, 0x36, 0xe4, 0xcc, 0xa7, 0x6c, 0xe4, 0xf1, 0x48, 0x98, 0x65, 0x95, 0xfa, 0x93, 0x95, - 0xa9, 0x53, 0xc7, 0xba, 0x9c, 0x12, 0x7e, 0x8c, 0x8e, 0x2b, 0x59, 0x3e, 0xf7, 0x4d, 0xf2, 0x1c, - 0x12, 0x10, 0x81, 0xdd, 0x10, 0xc9, 0x24, 0x26, 0xde, 0xbc, 0x74, 0xa5, 0x63, 0xf4, 0x5e, 0xf7, - 0xed, 0x97, 0xa4, 0x7f, 0x50, 0x3c, 0xbf, 0x90, 0x41, 0xb8, 0x30, 0x17, 0x2b, 0xc6, 0xe0, 0xaf, - 0xa0, 0xb5, 0x58, 0x5d, 0x4f, 0x72, 0x6f, 0x4c, 0xe8, 0x68, 0x2c, 0xcd, 0x77, 0xd4, 0x1e, 0xbe, - 0x5e, 0xab, 0x7c, 0x57, 0x73, 0x87, 0x71, 0xc1, 0xbf, 0x57, 0x12, 0x7a, 0x5f, 0xcd, 0x74, 0x29, - 0x0a, 0x7f, 0x37, 0xc0, 0xdb, 0x59, 0x69, 0x91, 0xef, 0x53, 0x49, 0x39, 0xf3, 0xa2, 0x98, 0x47, - 0x5c, 0xa0, 0x40, 0x98, 0x55, 0x65, 0xe0, 0xdb, 0x8d, 0xce, 0xef, 0x48, 0xcb, 0x9c, 0x69, 0x15, - 0x6d, 0x61, 0x0f, 0xaf, 0xc0, 0x05, 0xfc, 0xcd, 0x00, 0xad, 0x99, 0x8b, 0x98, 0x84, 0x3c, 0x45, - 0x41, 0xc1, 0xc4, 0x2b, 0x65, 0xe2, 0x9b, 0x8d, 0x4c, 0xb8, 0xb9, 0xca, 0x82, 0x07, 0x13, 0x2f, - 0x87, 0x05, 0x1c, 0x80, 0x6a, 0x84, 0x62, 0x14, 0x0a, 0xb3, 0xa6, 0x0e, 0xf7, 0xd3, 0xb5, 0xb2, - 0x9d, 0x29, 0x8a, 0x16, 0xd7, 0x02, 0xdd, 0x3f, 0x2b, 0x60, 0x7b, 0xae, 0x97, 0xe1, 0x1e, 0xa8, - 0xe5, 0x42, 0xfa, 0xea, 0xd4, 0xdd, 0x57, 0xea, 0x7f, 0xe0, 0xc3, 0x0f, 0x00, 0xc0, 0x63, 0xc4, - 0x18, 0x09, 0x32, 0x70, 0x4b, 0x81, 0x75, 0x1d, 0x19, 0xf8, 0xf0, 0x2d, 0xa8, 0xe3, 0x80, 0x12, - 0x26, 0x33, 0xb4, 0xac, 0xd0, 0x5a, 0x1e, 0x18, 0xf8, 0xf0, 0x63, 0xb0, 0x43, 0x19, 0x95, 0x14, - 0x05, 0xd3, 0x7e, 0xa9, 0xa8, 0x7b, 0xb9, 0xad, 0xa3, 0xfa, 0x8c, 0xbf, 0x02, 0x7b, 0x01, 0xc7, - 0x93, 0x62, 0x0f, 0x33, 0x4f, 0xd2, 0x90, 0xf0, 0x24, 0xeb, 0x30, 0xa3, 0x57, 0x73, 0x9b, 0xd9, - 0x82, 0xe7, 0xbe, 0x64, 0x17, 0x39, 0x0a, 0x87, 0xa0, 0x31, 0x3b, 0x17, 0x3d, 0x26, 0xcc, 0xaa, - 0xaa, 0x8f, 0xb3, 0xb2, 0x3e, 0xb3, 0x11, 0x94, 0x3a, 0x56, 0x71, 0x90, 0xe8, 0x2a, 0xcd, 0x46, - 0x84, 0xc6, 0xa0, 0x04, 0xcd, 0x88, 0xe4, 0xbe, 0xf4, 0x4d, 0xc8, 0xb6, 0x3f, 0x22, 0xd3, 0x73, - 0xff, 0xf2, 0xa5, 0x6b, 0x76, 0x85, 0x02, 0xea, 0x23, 0xc9, 0xe3, 0x73, 0x22, 0x4f, 0x14, 0xed, - 0x0c, 0xe1, 0x09, 0x91, 0xa7, 0x48, 0x22, 0x9d, 0x70, 0x57, 0xab, 0xe7, 0xf7, 0x23, 0x5f, 0x24, - 0xe0, 0x01, 0x80, 0x22, 0x40, 0x62, 0xec, 0xf9, 0xfc, 0x67, 0x96, 0x15, 0xc3, 0x43, 0x78, 0x62, - 0xd6, 0x3a, 0xe5, 0x5e, 0xdd, 0x6d, 0x28, 0xe4, 0x54, 0x03, 0x47, 0x78, 0x02, 0x27, 0xe0, 0xfd, - 0xb9, 0x09, 0xe0, 0x51, 0xe6, 0x93, 0x1b, 0xb3, 0xae, 0x0c, 0x7e, 0xb1, 0x56, 0xab, 0x14, 0x6e, - 0xfd, 0x20, 0x23, 0x6b, 0x77, 0xef, 0x15, 0x07, 0x8e, 0x02, 0xba, 0x3f, 0x81, 0xc6, 0xe2, 0xe2, - 0x0d, 0x86, 0xf0, 0x01, 0x80, 0x45, 0xab, 0xda, 0x69, 0x36, 0x87, 0x2b, 0x6e, 0x23, 0x59, 0xd0, - 0xed, 0x5e, 0x83, 0xe6, 0xf2, 0xb9, 0xb1, 0x41, 0xc6, 0x26, 0xa8, 0xea, 0xf6, 0xdb, 0x52, 0xb8, - 0xfe, 0x3b, 0xbe, 0xb8, 0x7b, 0x6c, 0x1b, 0xf7, 0x8f, 0x6d, 0xe3, 0x9f, 0xc7, 0xb6, 0xf1, 0xc7, - 0x53, 0xbb, 0x74, 0xff, 0xd4, 0x2e, 0xfd, 0xfd, 0xd4, 0x2e, 0x5d, 0x1f, 0x8e, 0xa8, 0x1c, 0x27, - 0x43, 0x0b, 0xf3, 0xd0, 0xc6, 0x5c, 0x84, 0x5c, 0xd8, 0xcf, 0x25, 0xfc, 0x6c, 0xf6, 0x50, 0xdd, - 0xcc, 0x3f, 0x89, 0xf2, 0x36, 0x22, 0x62, 0x58, 0x55, 0xcf, 0xd4, 0xe7, 0xff, 0x05, 0x00, 0x00, - 0xff, 0xff, 0xb9, 0x12, 0x17, 0x90, 0xd7, 0x07, 0x00, 0x00, + // 1036 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x56, 0xdd, 0x8e, 0xdb, 0x44, + 0x14, 0x5e, 0xef, 0xa6, 0xe9, 0x66, 0xf6, 0x87, 0x30, 0x2c, 0xa9, 0x37, 0x5b, 0xd2, 0x55, 0x0a, + 0x22, 0x12, 0xc5, 0x26, 0x41, 0x48, 0xb4, 0x80, 0x50, 0xb7, 0x95, 0x20, 0x5a, 0x10, 0x91, 0xbb, + 0x2d, 0x52, 0x6f, 0xac, 0xc9, 0x78, 0x94, 0x0c, 0x71, 0x3c, 0x96, 0x67, 0x6c, 0x6a, 0x21, 0x10, + 0x88, 0x17, 0xe0, 0x9a, 0x3b, 0x1e, 0x04, 0xae, 0x7b, 0xd9, 0x4b, 0xae, 0x2a, 0xb4, 0xfb, 0x06, + 0x3c, 0x01, 0xf2, 0x78, 0xec, 0xb5, 0xb3, 0x49, 0x48, 0x7a, 0x97, 0xcc, 0x37, 0xe7, 0x7c, 0xdf, + 0x39, 0x33, 0xe7, 0xf3, 0x80, 0x2e, 0xf5, 0x04, 0x09, 0xf0, 0x18, 0x51, 0xcf, 0xe6, 0x04, 0x87, + 0x01, 0x15, 0xb1, 0x89, 0x71, 0x64, 0xfa, 0x01, 0x8b, 0xa8, 0x43, 0x02, 0x33, 0xea, 0x9a, 0x23, + 0xe2, 0x11, 0x4e, 0xb9, 0xe1, 0x07, 0x4c, 0x30, 0x78, 0x7b, 0x4e, 0x88, 0x81, 0x71, 0x64, 0x64, + 0x21, 0x46, 0xd4, 0x6d, 0x1e, 0x8c, 0xd8, 0x88, 0xc9, 0xfd, 0x66, 0xf2, 0x2b, 0x0d, 0x6d, 0xbe, + 0xbd, 0x88, 0x2d, 0xea, 0x9a, 0x2a, 0x83, 0x60, 0xcd, 0xde, 0x2a, 0x9a, 0x72, 0xb2, 0xff, 0x89, + 0xc1, 0xcc, 0xe3, 0xe1, 0x34, 0x8d, 0xc9, 0x7e, 0xab, 0x98, 0xee, 0x2a, 0x31, 0xa5, 0xda, 0x9b, + 0x37, 0x05, 0xf1, 0x1c, 0x12, 0x4c, 0xa9, 0x27, 0x4c, 0x1c, 0xc4, 0xbe, 0x60, 0xe6, 0x84, 0xc4, + 0x0a, 0x6d, 0xff, 0x55, 0x03, 0xbb, 0x5f, 0xa4, 0xfb, 0x1f, 0x09, 0x24, 0x08, 0xec, 0x80, 0x7a, + 0x84, 0x5c, 0x4e, 0x84, 0x1d, 0xfa, 0x0e, 0x12, 0xc4, 0xa6, 0x8e, 0xae, 0x1d, 0x6b, 0x9d, 0x8a, + 0xb5, 0x9f, 0xae, 0x3f, 0x96, 0xcb, 0x7d, 0x07, 0xfe, 0x00, 0x5e, 0xcb, 0x58, 0x6d, 0x9e, 0xc4, + 0x72, 0x7d, 0xf3, 0x78, 0xab, 0xb3, 0xd3, 0xeb, 0x19, 0x2b, 0xb4, 0xdb, 0x78, 0xa0, 0x62, 0x25, + 0xed, 0x49, 0xeb, 0xf9, 0xcb, 0x5b, 0x1b, 0xff, 0xbe, 0xbc, 0xd5, 0x88, 0xd1, 0xd4, 0xbd, 0xd7, + 0x9e, 0x49, 0xdc, 0xb6, 0xf6, 0x71, 0x71, 0x3b, 0x87, 0x16, 0xd8, 0x0b, 0xbd, 0x21, 0xf3, 0x1c, + 0xea, 0x8d, 0x6c, 0xe6, 0x73, 0x7d, 0x4b, 0x52, 0xbf, 0xbb, 0x90, 0x3a, 0xea, 0x1a, 0x8f, 0xb3, + 0x80, 0x6f, 0xfc, 0x93, 0x4a, 0xc2, 0x67, 0xed, 0x86, 0x97, 0x4b, 0x1c, 0x22, 0x70, 0x30, 0x45, + 0x22, 0x0c, 0x88, 0x5d, 0x4e, 0x5d, 0x39, 0xd6, 0x3a, 0x3b, 0x3d, 0x73, 0x59, 0xea, 0xaf, 0x65, + 0x9c, 0x53, 0x60, 0xe0, 0x16, 0x4c, 0x93, 0x15, 0xd7, 0xe0, 0x8f, 0xa0, 0x39, 0xdb, 0x5d, 0x5b, + 0x30, 0x7b, 0x4c, 0xe8, 0x68, 0x2c, 0xf4, 0x6b, 0xb2, 0x86, 0x4f, 0x56, 0x6a, 0xdf, 0x93, 0xd2, + 0x61, 0x9c, 0xb1, 0x2f, 0x65, 0x0a, 0x55, 0x57, 0x23, 0x9a, 0x8b, 0xc2, 0x5f, 0x35, 0x70, 0x94, + 0xb7, 0x16, 0x39, 0x0e, 0x15, 0x94, 0x79, 0xb6, 0x1f, 0x30, 0x9f, 0x71, 0xe4, 0x72, 0xbd, 0x2a, + 0x05, 0x7c, 0xb6, 0xd6, 0xf9, 0xdd, 0x57, 0x69, 0x06, 0x2a, 0x8b, 0x92, 0x70, 0x88, 0x17, 0xe0, + 0x1c, 0xfe, 0xac, 0x81, 0x66, 0xae, 0x22, 0x20, 0x53, 0x16, 0x21, 0xb7, 0x20, 0xe2, 0xba, 0x14, + 0xf1, 0xe9, 0x5a, 0x22, 0xac, 0x34, 0xcb, 0x8c, 0x06, 0x1d, 0xcf, 0x87, 0x39, 0xec, 0x83, 0xaa, + 0x8f, 0x02, 0x34, 0xe5, 0xfa, 0xb6, 0x3c, 0xdc, 0xf7, 0x56, 0x62, 0x1b, 0xc8, 0x10, 0x95, 0x5c, + 0x25, 0x90, 0xd5, 0x44, 0xc8, 0xa5, 0x0e, 0x12, 0x2c, 0xb0, 0xf3, 0xba, 0xfc, 0x70, 0x98, 0x8c, + 0x99, 0x5e, 0x5b, 0xa3, 0x9a, 0x27, 0x59, 0x9a, 0xac, 0xac, 0x41, 0x38, 0x3c, 0x25, 0x71, 0x56, + 0x4d, 0x34, 0x07, 0x4e, 0x38, 0xe0, 0x2f, 0x1a, 0x38, 0xca, 0x41, 0x6e, 0x0f, 0x63, 0xbb, 0x78, + 0xc8, 0x81, 0x0e, 0x5e, 0x45, 0xc3, 0x49, 0x5c, 0x38, 0xe1, 0xe0, 0x8a, 0x06, 0x5e, 0xc6, 0x61, + 0x04, 0x6e, 0x94, 0x48, 0x79, 0x72, 0xaf, 0xfd, 0x20, 0xf4, 0x88, 0xbe, 0x23, 0xe9, 0xef, 0xae, + 0x7b, 0xab, 0x02, 0x7e, 0xc6, 0x06, 0x49, 0x02, 0xc5, 0x7d, 0x80, 0xe7, 0x60, 0xed, 0x3f, 0x2b, + 0x60, 0xaf, 0x64, 0x25, 0xf0, 0x10, 0x6c, 0xa7, 0x24, 0xca, 0xb9, 0x6a, 0xd6, 0x75, 0xf9, 0xbf, + 0xef, 0xc0, 0xb7, 0x00, 0xc0, 0x63, 0xe4, 0x79, 0xc4, 0x4d, 0xc0, 0x4d, 0x09, 0xd6, 0xd4, 0x4a, + 0xdf, 0x81, 0x47, 0xa0, 0x86, 0x5d, 0x4a, 0x3c, 0x91, 0xa0, 0x5b, 0x12, 0xdd, 0x4e, 0x17, 0xfa, + 0x0e, 0x7c, 0x07, 0xec, 0x53, 0x8f, 0x0a, 0x8a, 0xdc, 0x6c, 0x5c, 0x2b, 0xd2, 0x16, 0xf7, 0xd4, + 0xaa, 0x1a, 0xb1, 0xbb, 0xe0, 0xd0, 0x65, 0x78, 0x52, 0xb4, 0x10, 0xcf, 0x16, 0x74, 0x4a, 0x58, + 0x98, 0x0c, 0xb8, 0xd6, 0xd9, 0xb6, 0x1a, 0xc9, 0x86, 0x4b, 0x5b, 0xf0, 0xce, 0x52, 0x14, 0x0e, + 0x41, 0x3d, 0x6f, 0xa1, 0xf2, 0x70, 0xbd, 0x2a, 0xaf, 0x67, 0x77, 0x61, 0xef, 0xf2, 0xef, 0x43, + 0xd4, 0x35, 0x8a, 0x3e, 0xae, 0x7a, 0x96, 0x3b, 0xb4, 0xc2, 0xa0, 0x00, 0x0d, 0x9f, 0xa4, 0xba, + 0x94, 0x11, 0x25, 0xe5, 0x8f, 0x48, 0x36, 0x76, 0x1f, 0x2f, 0x73, 0xb9, 0xfc, 0x6e, 0x3c, 0x22, + 0xe2, 0x81, 0x0c, 0x1b, 0x20, 0x3c, 0x21, 0xe2, 0x21, 0x12, 0x28, 0x3b, 0x24, 0x95, 0x3d, 0xb5, + 0xa7, 0x74, 0x13, 0x87, 0x77, 0x00, 0xe4, 0x2e, 0xe2, 0x63, 0xdb, 0x61, 0xdf, 0x7b, 0x49, 0x33, + 0x6c, 0x84, 0x27, 0xfa, 0xf6, 0xf1, 0x56, 0xa7, 0x66, 0xd5, 0x25, 0xf2, 0x50, 0x01, 0xf7, 0xf1, + 0x04, 0x4e, 0xc0, 0x1b, 0x25, 0x03, 0xb6, 0xa9, 0xe7, 0x90, 0x67, 0x6a, 0x92, 0x3e, 0x5a, 0xe9, + 0x1a, 0x15, 0x4c, 0xb7, 0x9f, 0x04, 0x2b, 0x75, 0xaf, 0x17, 0xfd, 0x5e, 0x02, 0xed, 0xef, 0x40, + 0x7d, 0x76, 0xf3, 0x1a, 0xdf, 0xc0, 0x3b, 0x00, 0x16, 0xa5, 0x2a, 0xa5, 0xc9, 0x67, 0xb0, 0x62, + 0xd5, 0xc3, 0x99, 0xbc, 0xed, 0xa7, 0xa0, 0x31, 0xdf, 0xb6, 0xd7, 0x60, 0x6c, 0x80, 0xaa, 0xba, + 0x7e, 0x9b, 0x12, 0x57, 0xff, 0xda, 0xbf, 0x6b, 0xe0, 0xc6, 0x02, 0xff, 0x58, 0x36, 0x11, 0xb7, + 0xc1, 0x5e, 0xd6, 0xb7, 0xd4, 0x2b, 0x92, 0xac, 0xbb, 0xd6, 0x6e, 0xb6, 0x28, 0x67, 0xfb, 0x73, + 0xb0, 0x9b, 0x5f, 0xcc, 0x09, 0x89, 0xe5, 0x68, 0xec, 0xf4, 0x6e, 0x1a, 0x97, 0x2f, 0x0b, 0x23, + 0x7d, 0x59, 0x18, 0x83, 0x70, 0xe8, 0x52, 0x7c, 0x4a, 0x62, 0x6b, 0x27, 0x8b, 0x38, 0x25, 0x71, + 0xfb, 0xa7, 0x82, 0xb6, 0x19, 0xdf, 0x58, 0xae, 0xad, 0xec, 0x63, 0x4a, 0x5b, 0xd1, 0x07, 0xae, + 0x16, 0xb0, 0x75, 0xb5, 0x80, 0xf6, 0x1f, 0x1a, 0x38, 0x98, 0xe7, 0x2c, 0xcb, 0xd8, 0xdf, 0x04, + 0xd5, 0x88, 0xe3, 0xcc, 0x27, 0x2a, 0xd6, 0xb5, 0x88, 0xe3, 0xbe, 0x03, 0xbf, 0x05, 0xfb, 0x65, + 0x9f, 0x53, 0xdd, 0xf8, 0x60, 0xa5, 0x7b, 0x99, 0x90, 0x13, 0xce, 0xbf, 0xa2, 0x5c, 0x58, 0x7b, + 0x25, 0x3f, 0x3b, 0x39, 0x7b, 0x7e, 0xde, 0xd2, 0x5e, 0x9c, 0xb7, 0xb4, 0x7f, 0xce, 0x5b, 0xda, + 0x6f, 0x17, 0xad, 0x8d, 0x17, 0x17, 0xad, 0x8d, 0xbf, 0x2f, 0x5a, 0x1b, 0x4f, 0xef, 0x8d, 0xa8, + 0x18, 0x87, 0x43, 0x03, 0xb3, 0xa9, 0x89, 0x19, 0x9f, 0x32, 0x6e, 0x5e, 0x72, 0xbd, 0x9f, 0x3f, + 0x03, 0x9f, 0x95, 0x1f, 0x9c, 0x22, 0xf6, 0x09, 0x1f, 0x56, 0xe5, 0x33, 0xef, 0xc3, 0xff, 0x02, + 0x00, 0x00, 0xff, 0xff, 0x79, 0x53, 0xf9, 0x6c, 0x35, 0x0b, 0x00, 0x00, } func (m *GenesisState) Marshal() (dAtA []byte, err error) { @@ -444,6 +676,48 @@ func (m *GenesisState) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.ConsumerAddrsToPrune) > 0 { + for iNdEx := len(m.ConsumerAddrsToPrune) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ConsumerAddrsToPrune[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x5a + } + } + if len(m.ValidatorsByConsumerAddr) > 0 { + for iNdEx := len(m.ValidatorsByConsumerAddr) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ValidatorsByConsumerAddr[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x52 + } + } + if len(m.ValidatorConsumerPubkeys) > 0 { + for iNdEx := len(m.ValidatorConsumerPubkeys) - 1; iNdEx >= 0; iNdEx-- { + { + size, err := m.ValidatorConsumerPubkeys[iNdEx].MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x4a + } + } { size, err := m.Params.MarshalToSizedBuffer(dAtA[:i]) if err != nil { @@ -729,68 +1003,226 @@ func (m *ValsetUpdateIdToHeight) MarshalToSizedBuffer(dAtA []byte) (int, error) return len(dAtA) - i, nil } -func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { - offset -= sovGenesis(v) - base := offset - for v >= 1<<7 { - dAtA[offset] = uint8(v&0x7f | 0x80) - v >>= 7 - offset++ +func (m *ValidatorConsumerPubKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err } - dAtA[offset] = uint8(v) - return base + return dAtA[:n], nil } -func (m *GenesisState) Size() (n int) { - if m == nil { - return 0 - } + +func (m *ValidatorConsumerPubKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorConsumerPubKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i var l int _ = l - if m.ValsetUpdateId != 0 { - n += 1 + sovGenesis(uint64(m.ValsetUpdateId)) - } - if len(m.ConsumerStates) > 0 { - for _, e := range m.ConsumerStates { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if len(m.UnbondingOps) > 0 { - for _, e := range m.UnbondingOps { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - } - if m.MatureUnbondingOps != nil { - l = m.MatureUnbondingOps.Size() - n += 1 + l + sovGenesis(uint64(l)) - } - if len(m.ValsetUpdateIdToHeight) > 0 { - for _, e := range m.ValsetUpdateIdToHeight { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) + if m.ConsumerKey != nil { + { + size, err := m.ConsumerKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) } + i-- + dAtA[i] = 0x1a } - if len(m.ConsumerAdditionProposals) > 0 { - for _, e := range m.ConsumerAdditionProposals { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0x12 } - if len(m.ConsumerRemovalProposals) > 0 { - for _, e := range m.ConsumerRemovalProposals { - l = e.Size() - n += 1 + l + sovGenesis(uint64(l)) - } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa } - l = m.Params.Size() - n += 1 + l + sovGenesis(uint64(l)) - return n + return len(dAtA) - i, nil } -func (m *ConsumerState) Size() (n int) { - if m == nil { - return 0 +func (m *ValidatorByConsumerAddr) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ValidatorByConsumerAddr) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ValidatorByConsumerAddr) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0x1a + } + if len(m.ConsumerAddr) > 0 { + i -= len(m.ConsumerAddr) + copy(dAtA[i:], m.ConsumerAddr) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ConsumerAddr))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *ConsumerAddrsToPrune) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *ConsumerAddrsToPrune) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *ConsumerAddrsToPrune) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ConsumerAddrs != nil { + { + size, err := m.ConsumerAddrs.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintGenesis(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if m.VscId != 0 { + i = encodeVarintGenesis(dAtA, i, uint64(m.VscId)) + i-- + dAtA[i] = 0x10 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintGenesis(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func encodeVarintGenesis(dAtA []byte, offset int, v uint64) int { + offset -= sovGenesis(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *GenesisState) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if m.ValsetUpdateId != 0 { + n += 1 + sovGenesis(uint64(m.ValsetUpdateId)) + } + if len(m.ConsumerStates) > 0 { + for _, e := range m.ConsumerStates { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.UnbondingOps) > 0 { + for _, e := range m.UnbondingOps { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if m.MatureUnbondingOps != nil { + l = m.MatureUnbondingOps.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + if len(m.ValsetUpdateIdToHeight) > 0 { + for _, e := range m.ValsetUpdateIdToHeight { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ConsumerAdditionProposals) > 0 { + for _, e := range m.ConsumerAdditionProposals { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ConsumerRemovalProposals) > 0 { + for _, e := range m.ConsumerRemovalProposals { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + l = m.Params.Size() + n += 1 + l + sovGenesis(uint64(l)) + if len(m.ValidatorConsumerPubkeys) > 0 { + for _, e := range m.ValidatorConsumerPubkeys { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ValidatorsByConsumerAddr) > 0 { + for _, e := range m.ValidatorsByConsumerAddr { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + if len(m.ConsumerAddrsToPrune) > 0 { + for _, e := range m.ConsumerAddrsToPrune { + l = e.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + } + return n +} + +func (m *ConsumerState) Size() (n int) { + if m == nil { + return 0 } var l int _ = l @@ -869,6 +1301,68 @@ func (m *ValsetUpdateIdToHeight) Size() (n int) { return n } +func (m *ValidatorConsumerPubKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.ConsumerKey != nil { + l = m.ConsumerKey.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *ValidatorByConsumerAddr) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ConsumerAddr) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + +func (m *ConsumerAddrsToPrune) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovGenesis(uint64(l)) + } + if m.VscId != 0 { + n += 1 + sovGenesis(uint64(m.VscId)) + } + if m.ConsumerAddrs != nil { + l = m.ConsumerAddrs.Size() + n += 1 + l + sovGenesis(uint64(l)) + } + return n +} + func sovGenesis(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -1162,61 +1656,11 @@ func (m *GenesisState) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex - default: - iNdEx = preIndex - skippy, err := skipGenesis(dAtA[iNdEx:]) - if err != nil { - return err - } - if (skippy < 0) || (iNdEx+skippy) < 0 { - return ErrInvalidLengthGenesis - } - if (iNdEx + skippy) > l { - return io.ErrUnexpectedEOF - } - iNdEx += skippy - } - } - - if iNdEx > l { - return io.ErrUnexpectedEOF - } - return nil -} -func (m *ConsumerState) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { - preIndex := iNdEx - var wire uint64 - for shift := uint(0); ; shift += 7 { - if shift >= 64 { - return ErrIntOverflowGenesis - } - if iNdEx >= l { - return io.ErrUnexpectedEOF - } - b := dAtA[iNdEx] - iNdEx++ - wire |= uint64(b&0x7F) << shift - if b < 0x80 { - break - } - } - fieldNum := int32(wire >> 3) - wireType := int(wire & 0x7) - if wireType == 4 { - return fmt.Errorf("proto: ConsumerState: wiretype end group for non-group") - } - if fieldNum <= 0 { - return fmt.Errorf("proto: ConsumerState: illegal tag %d (wire type %d)", fieldNum, wire) - } - switch fieldNum { - case 1: + case 9: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorConsumerPubkeys", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -1226,29 +1670,31 @@ func (m *ConsumerState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { return ErrInvalidLengthGenesis } - postIndex := iNdEx + intStringLen + postIndex := iNdEx + msglen if postIndex < 0 { return ErrInvalidLengthGenesis } if postIndex > l { return io.ErrUnexpectedEOF } - m.ChainId = string(dAtA[iNdEx:postIndex]) + m.ValidatorConsumerPubkeys = append(m.ValidatorConsumerPubkeys, ValidatorConsumerPubKey{}) + if err := m.ValidatorConsumerPubkeys[len(m.ValidatorConsumerPubkeys)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } iNdEx = postIndex - case 2: + case 10: if wireType != 2 { - return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + return fmt.Errorf("proto: wrong wireType = %d for field ValidatorsByConsumerAddr", wireType) } - var stringLen uint64 + var msglen int for shift := uint(0); ; shift += 7 { if shift >= 64 { return ErrIntOverflowGenesis @@ -1258,13 +1704,163 @@ func (m *ConsumerState) Unmarshal(dAtA []byte) error { } b := dAtA[iNdEx] iNdEx++ - stringLen |= uint64(b&0x7F) << shift + msglen |= int(b&0x7F) << shift if b < 0x80 { break } } - intStringLen := int(stringLen) - if intStringLen < 0 { + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ValidatorsByConsumerAddr = append(m.ValidatorsByConsumerAddr, ValidatorByConsumerAddr{}) + if err := m.ValidatorsByConsumerAddr[len(m.ValidatorsByConsumerAddr)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + case 11: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddrsToPrune", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerAddrsToPrune = append(m.ConsumerAddrsToPrune, ConsumerAddrsToPrune{}) + if err := m.ConsumerAddrsToPrune[len(m.ConsumerAddrsToPrune)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConsumerState) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ConsumerState: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerState: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChannelId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { return ErrInvalidLengthGenesis } postIndex := iNdEx + intStringLen @@ -1734,6 +2330,445 @@ func (m *ValsetUpdateIdToHeight) Unmarshal(dAtA []byte) error { } return nil } +func (m *ValidatorConsumerPubKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ValidatorConsumerPubKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorConsumerPubKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = append(m.ProviderAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ProviderAddr == nil { + m.ProviderAddr = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ConsumerKey == nil { + m.ConsumerKey = &crypto.PublicKey{} + } + if err := m.ConsumerKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ValidatorByConsumerAddr) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ValidatorByConsumerAddr: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ValidatorByConsumerAddr: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerAddr = append(m.ConsumerAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ConsumerAddr == nil { + m.ConsumerAddr = []byte{} + } + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = append(m.ProviderAddr[:0], dAtA[iNdEx:postIndex]...) + if m.ProviderAddr == nil { + m.ProviderAddr = []byte{} + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *ConsumerAddrsToPrune) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: ConsumerAddrsToPrune: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: ConsumerAddrsToPrune: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field VscId", wireType) + } + m.VscId = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.VscId |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddrs", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowGenesis + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthGenesis + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthGenesis + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ConsumerAddrs == nil { + m.ConsumerAddrs = &AddressList{} + } + if err := m.ConsumerAddrs.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipGenesis(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthGenesis + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipGenesis(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index 50096529d0..b17252e479 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -35,6 +35,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), true, }, @@ -54,6 +57,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), true, }, @@ -70,6 +76,9 @@ func TestValidateGenesisState(t *testing.T) { types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), 3, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400), + nil, + nil, + nil, ), true, }, @@ -86,6 +95,9 @@ func TestValidateGenesisState(t *testing.T) { types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), 3, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400), + nil, + nil, + nil, ), false, }, @@ -102,6 +114,9 @@ func TestValidateGenesisState(t *testing.T) { types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), 3, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400), + nil, + nil, + nil, ), false, }, @@ -118,6 +133,9 @@ func TestValidateGenesisState(t *testing.T) { types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), 3, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", 400), + nil, + nil, + nil, ), false, }, @@ -140,6 +158,9 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -162,6 +183,9 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -184,6 +208,34 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, + ), + false, + }, + { + "invalid params, zero init timeout", + types.NewGenesisState( + 0, + nil, + []types.ConsumerState{{ChainId: "chainid-1", ChannelId: "channelid", ClientId: "client-id"}}, + nil, + nil, + nil, + nil, + types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}, true, false), + types.DefaultTrustingPeriodFraction, + ccv.DefaultCCVTimeoutPeriod, + 0, // 0 init timeout here + types.DefaultVscTimeoutPeriod, + types.DefaultSlashMeterReplenishPeriod, + types.DefaultSlashMeterReplenishFraction, + types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -206,6 +258,9 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -228,6 +283,9 @@ func TestValidateGenesisState(t *testing.T) { 0, // 0 slash meter replenish period here types.DefaultSlashMeterReplenishFraction, types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -250,6 +308,9 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, "1.15", types.DefaultMaxPendingSlashPackets), + nil, + nil, + nil, ), false, }, @@ -272,6 +333,9 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultSlashMeterReplenishPeriod, "1.15", -1), + nil, + nil, + nil, ), false, }, @@ -286,6 +350,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -300,6 +367,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -314,6 +384,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -328,6 +401,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -343,6 +419,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -359,6 +438,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -375,6 +457,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -394,6 +479,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -409,6 +497,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, @@ -424,6 +515,9 @@ func TestValidateGenesisState(t *testing.T) { nil, nil, types.DefaultParams(), + nil, + nil, + nil, ), false, }, diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 5ddee21d00..d1373acde7 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -95,6 +95,20 @@ const ( // LockUnbondingOnTimeoutBytePrefix is the byte prefix that will store the consumer chain id which unbonding operations are locked on CCV channel timeout LockUnbondingOnTimeoutBytePrefix + + // ConsumerValidatorsBytePrefix is the byte prefix that will store the validator assigned keys for every consumer chain + ConsumerValidatorsBytePrefix + + // ValidatorsByConsumerAddrBytePrefix is the byte prefix that will store the mapping from validator addresses + // on consumer chains to validator addresses on the provider chain + ValidatorsByConsumerAddrBytePrefix + + // KeyAssignmentReplacementsBytePrefix is the byte prefix that will store the key assignments that need to be replaced in the current block + KeyAssignmentReplacementsBytePrefix + + // ConsumerAddrsToPruneBytePrefix is the byte prefix that will store the mapping from VSC ids + // to consumer validators addresses needed for pruning + ConsumerAddrsToPruneBytePrefix ) // PortKey returns the key to the port ID in the store @@ -134,36 +148,36 @@ func InitTimeoutTimestampKey(chainID string) []byte { // PendingCAPKey returns the key under which a pending consumer addition proposal is stored func PendingCAPKey(timestamp time.Time, chainID string) []byte { - return tsAndChainIdKey(PendingCAPBytePrefix, timestamp, chainID) + return TsAndChainIdKey(PendingCAPBytePrefix, timestamp, chainID) } // ParsePendingCAPKey returns the time and chain ID for a pending consumer addition proposal key // or an error if unparsable func ParsePendingCAPKey(bz []byte) (time.Time, string, error) { - return parseTsAndChainIdKey(PendingCAPBytePrefix, bz) + return ParseTsAndChainIdKey(PendingCAPBytePrefix, bz) } // PendingCRPKey returns the key under which pending consumer removal proposals are stored func PendingCRPKey(timestamp time.Time, chainID string) []byte { - return tsAndChainIdKey(PendingCRPBytePrefix, timestamp, chainID) + return TsAndChainIdKey(PendingCRPBytePrefix, timestamp, chainID) } // ParsePendingCRPKey returns the time and chain ID for a pending consumer removal proposal key or an error if unparseable func ParsePendingCRPKey(bz []byte) (time.Time, string, error) { - return parseTsAndChainIdKey(PendingCRPBytePrefix, bz) + return ParseTsAndChainIdKey(PendingCRPBytePrefix, bz) } // UnbondingOpIndexKey returns an unbonding op index key // Note: chainId is hashed to a fixed length sequence of bytes here to prevent // injection attack between chainIDs. func UnbondingOpIndexKey(chainID string, vscID uint64) []byte { - return chainIdAndVscIdKey(UnbondingOpIndexBytePrefix, chainID, vscID) + return ChainIdAndVscIdKey(UnbondingOpIndexBytePrefix, chainID, vscID) } // ParseUnbondingOpIndexKey parses an unbonding op index key for VSC ID // Removes the prefix + chainID from index key and returns only the key part. func ParseUnbondingOpIndexKey(key []byte) (string, uint64, error) { - return parseChainIdAndVscIdKey(UnbondingOpIndexBytePrefix, key) + return ParseChainIdAndVscIdKey(UnbondingOpIndexBytePrefix, key) } // UnbondingOpKey returns the key that stores a record of all the ids of consumer chains that @@ -206,13 +220,13 @@ func PendingVSCsKey(chainID string) []byte { // VscSendingTimestampKey returns the key under which the // sending timestamp of the VSCPacket with vsc ID is stored func VscSendingTimestampKey(chainID string, vscID uint64) []byte { - return chainIdAndVscIdKey(VscSendTimestampBytePrefix, chainID, vscID) + return ChainIdAndVscIdKey(VscSendTimestampBytePrefix, chainID, vscID) } // ParseVscTimeoutTimestampKey returns chain ID and vsc ID // for a VscSendingTimestampKey or an error if unparsable func ParseVscSendingTimestampKey(bz []byte) (string, uint64, error) { - return parseChainIdAndVscIdKey(VscSendTimestampBytePrefix, bz) + return ParseChainIdAndVscIdKey(VscSendTimestampBytePrefix, bz) } // LockUnbondingOnTimeoutKey returns the key that will store the consumer chain id which unbonding operations are locked @@ -221,6 +235,30 @@ func LockUnbondingOnTimeoutKey(chainID string) []byte { return append([]byte{LockUnbondingOnTimeoutBytePrefix}, []byte(chainID)...) } +// ConsumerValidatorsKey returns the key under which the +// validator assigned keys for every consumer chain are stored +func ConsumerValidatorsKey(chainID string, addr sdk.ConsAddress) []byte { + return ChainIdAndConsAddrKey(ConsumerValidatorsBytePrefix, chainID, addr) +} + +// ValidatorsByConsumerAddrKey returns the key under which the mapping from validator addresses +// on consumer chains to validator addresses on the provider chain is stored +func ValidatorsByConsumerAddrKey(chainID string, addr sdk.ConsAddress) []byte { + return ChainIdAndConsAddrKey(ValidatorsByConsumerAddrBytePrefix, chainID, addr) +} + +// KeyAssignmentReplacementsKey returns the key under which the +// key assignments that need to be replaced in the current block are stored +func KeyAssignmentReplacementsKey(chainID string, addr sdk.ConsAddress) []byte { + return ChainIdAndConsAddrKey(KeyAssignmentReplacementsBytePrefix, chainID, addr) +} + +// ConsumerAddrsToPruneKey returns the key under which the +// mapping from VSC ids to consumer validators addresses is stored +func ConsumerAddrsToPruneKey(chainID string, vscID uint64) []byte { + return ChainIdAndVscIdKey(ConsumerAddrsToPruneBytePrefix, chainID, vscID) +} + // AppendMany appends a variable number of byte slices together func AppendMany(byteses ...[]byte) (out []byte) { for _, bytes := range byteses { @@ -229,9 +267,9 @@ func AppendMany(byteses ...[]byte) (out []byte) { return out } -// tsAndChainIdKey returns the key with the following format: +// TsAndChainIdKey returns the key with the following format: // bytePrefix | len(timestamp) | timestamp | chainID -func tsAndChainIdKey(prefix byte, timestamp time.Time, chainID string) []byte { +func TsAndChainIdKey(prefix byte, timestamp time.Time, chainID string) []byte { timeBz := sdk.FormatTimeBytes(timestamp) timeBzL := len(timeBz) @@ -247,8 +285,8 @@ func tsAndChainIdKey(prefix byte, timestamp time.Time, chainID string) []byte { ) } -// parseTsAndChainIdKey returns the time and chain ID for a TsAndChainId key -func parseTsAndChainIdKey(prefix byte, bz []byte) (time.Time, string, error) { +// ParseTsAndChainIdKey returns the time and chain ID for a TsAndChainId key +func ParseTsAndChainIdKey(prefix byte, bz []byte) (time.Time, string, error) { expectedPrefix := []byte{prefix} prefixL := len(expectedPrefix) if prefix := bz[:prefixL]; !bytes.Equal(prefix, expectedPrefix) { @@ -265,9 +303,9 @@ func parseTsAndChainIdKey(prefix byte, bz []byte) (time.Time, string, error) { return timestamp, chainID, nil } -// chainIdAndTsKey returns the key with the following format: +// ChainIdAndTsKey returns the key with the following format: // bytePrefix | len(chainID) | chainID | timestamp -func chainIdAndTsKey(prefix byte, chainID string, timestamp time.Time) []byte { +func ChainIdAndTsKey(prefix byte, chainID string, timestamp time.Time) []byte { partialKey := ChainIdWithLenKey(prefix, chainID) timeBz := sdk.FormatTimeBytes(timestamp) return AppendMany( @@ -278,7 +316,7 @@ func chainIdAndTsKey(prefix byte, chainID string, timestamp time.Time) []byte { ) } -// chainIdWithLenKey returns the key with the following format: +// ChainIdWithLenKey returns the key with the following format: // bytePrefix | len(chainID) | chainID func ChainIdWithLenKey(prefix byte, chainID string) []byte { chainIdL := len(chainID) @@ -292,8 +330,8 @@ func ChainIdWithLenKey(prefix byte, chainID string) []byte { ) } -// parseChainIdAndTsKey returns the chain ID and time for a ChainIdAndTs key -func parseChainIdAndTsKey(prefix byte, bz []byte) (string, time.Time, error) { +// ParseChainIdAndTsKey returns the chain ID and time for a ChainIdAndTs key +func ParseChainIdAndTsKey(prefix byte, bz []byte) (string, time.Time, error) { expectedPrefix := []byte{prefix} prefixL := len(expectedPrefix) if prefix := bz[:prefixL]; !bytes.Equal(prefix, expectedPrefix) { @@ -308,9 +346,9 @@ func parseChainIdAndTsKey(prefix byte, bz []byte) (string, time.Time, error) { return chainID, timestamp, nil } -// chainIdAndVscIdKey returns the key with the following format: +// ChainIdAndVscIdKey returns the key with the following format: // bytePrefix | len(chainID) | chainID | vscID -func chainIdAndVscIdKey(prefix byte, chainID string, vscID uint64) []byte { +func ChainIdAndVscIdKey(prefix byte, chainID string, vscID uint64) []byte { partialKey := ChainIdWithLenKey(prefix, chainID) return AppendMany( // Append the partialKey @@ -320,8 +358,8 @@ func chainIdAndVscIdKey(prefix byte, chainID string, vscID uint64) []byte { ) } -// parseChainIdAndVscIdKey returns the chain ID and vsc ID for a ChainIdAndVscId key -func parseChainIdAndVscIdKey(prefix byte, bz []byte) (string, uint64, error) { +// ParseChainIdAndVscIdKey returns the chain ID and vsc ID for a ChainIdAndVscId key +func ParseChainIdAndVscIdKey(prefix byte, bz []byte) (string, uint64, error) { expectedPrefix := []byte{prefix} prefixL := len(expectedPrefix) if prefix := bz[:prefixL]; !bytes.Equal(prefix, expectedPrefix) { @@ -332,3 +370,28 @@ func parseChainIdAndVscIdKey(prefix byte, bz []byte) (string, uint64, error) { vscID := sdk.BigEndianToUint64(bz[prefixL+8+int(chainIdL):]) return chainID, vscID, nil } + +// ChainIdAndConsAddrKey returns the key with the following format: +// bytePrefix | len(chainID) | chainID | ConsAddress +func ChainIdAndConsAddrKey(prefix byte, chainID string, addr sdk.ConsAddress) []byte { + partialKey := ChainIdWithLenKey(prefix, chainID) + return AppendMany( + // Append the partialKey + partialKey, + // Append the addr bytes + addr, + ) +} + +// ParseChainIdAndConsAddrKey returns the chain ID and ConsAddress for a ChainIdAndConsAddrKey key +func ParseChainIdAndConsAddrKey(prefix byte, bz []byte) (string, sdk.ConsAddress, error) { + expectedPrefix := []byte{prefix} + prefixL := len(expectedPrefix) + if prefix := bz[:prefixL]; !bytes.Equal(prefix, expectedPrefix) { + return "", nil, fmt.Errorf("invalid prefix; expected: %X, got: %X", expectedPrefix, prefix) + } + chainIdL := sdk.BigEndianToUint64(bz[prefixL : prefixL+8]) + chainID := string(bz[prefixL+8 : prefixL+8+int(chainIdL)]) + addr := bz[prefixL+8+int(chainIdL):] + return chainID, addr, nil +} diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 8152ecf01a..cb8d9723e6 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -1,10 +1,12 @@ -package types +package types_test import ( "testing" "time" sdk "github.com/cosmos/cosmos-sdk/types" + testkeeper "github.com/cosmos/interchain-security/testutil/keeper" + "github.com/cosmos/interchain-security/x/ccv/provider/types" "github.com/stretchr/testify/require" ) @@ -37,24 +39,28 @@ func getSingleByteKeys() [][]byte { keys := make([][]byte, 32) i := 0 - keys[i], i = PortKey(), i+1 - keys[i], i = MaturedUnbondingOpsKey(), i+1 - keys[i], i = ValidatorSetUpdateIdKey(), i+1 - keys[i], i = []byte{ChainToChannelBytePrefix}, i+1 - keys[i], i = []byte{ChannelToChainBytePrefix}, i+1 - keys[i], i = []byte{ChainToClientBytePrefix}, i+1 - keys[i], i = []byte{InitTimeoutTimestampBytePrefix}, i+1 - keys[i], i = []byte{PendingCAPBytePrefix}, i+1 - keys[i], i = []byte{PendingCRPBytePrefix}, i+1 - keys[i], i = []byte{UnbondingOpBytePrefix}, i+1 - keys[i], i = []byte{UnbondingOpIndexBytePrefix}, i+1 - keys[i], i = []byte{ValsetUpdateBlockHeightBytePrefix}, i+1 - keys[i], i = []byte{ConsumerGenesisBytePrefix}, i+1 - keys[i], i = []byte{SlashAcksBytePrefix}, i+1 - keys[i], i = []byte{InitChainHeightBytePrefix}, i+1 - keys[i], i = []byte{PendingVSCsBytePrefix}, i+1 - keys[i], i = []byte{VscSendTimestampBytePrefix}, i+1 - keys[i], i = []byte{LockUnbondingOnTimeoutBytePrefix}, i+1 + keys[i], i = types.PortKey(), i+1 + keys[i], i = types.MaturedUnbondingOpsKey(), i+1 + keys[i], i = types.ValidatorSetUpdateIdKey(), i+1 + keys[i], i = []byte{types.ChainToChannelBytePrefix}, i+1 + keys[i], i = []byte{types.ChannelToChainBytePrefix}, i+1 + keys[i], i = []byte{types.ChainToClientBytePrefix}, i+1 + keys[i], i = []byte{types.InitTimeoutTimestampBytePrefix}, i+1 + keys[i], i = []byte{types.PendingCAPBytePrefix}, i+1 + keys[i], i = []byte{types.PendingCRPBytePrefix}, i+1 + keys[i], i = []byte{types.UnbondingOpBytePrefix}, i+1 + keys[i], i = []byte{types.UnbondingOpIndexBytePrefix}, i+1 + keys[i], i = []byte{types.ValsetUpdateBlockHeightBytePrefix}, i+1 + keys[i], i = []byte{types.ConsumerGenesisBytePrefix}, i+1 + keys[i], i = []byte{types.SlashAcksBytePrefix}, i+1 + keys[i], i = []byte{types.InitChainHeightBytePrefix}, i+1 + keys[i], i = []byte{types.PendingVSCsBytePrefix}, i+1 + keys[i], i = []byte{types.VscSendTimestampBytePrefix}, i+1 + keys[i], i = []byte{types.LockUnbondingOnTimeoutBytePrefix}, i+1 + keys[i], i = []byte{types.ConsumerValidatorsBytePrefix}, i+1 + keys[i], i = []byte{types.ValidatorsByConsumerAddrBytePrefix}, i+1 + keys[i], i = []byte{types.KeyAssignmentReplacementsBytePrefix}, i+1 + keys[i], i = []byte{types.ConsumerAddrsToPruneBytePrefix}, i+1 return keys[:i] } @@ -73,12 +79,12 @@ func TestTsAndChainIdKeyAndParse(t *testing.T) { } for _, test := range tests { - key := tsAndChainIdKey(test.prefix, test.timestamp, test.chainID) + key := types.TsAndChainIdKey(test.prefix, test.timestamp, test.chainID) require.NotEmpty(t, key) // Expected bytes = prefix + time length + time bytes + length of chainID expectedLen := 1 + 8 + len(sdk.FormatTimeBytes(time.Time{})) + len(test.chainID) require.Equal(t, expectedLen, len(key)) - parsedTime, parsedID, err := parseTsAndChainIdKey(test.prefix, key) + parsedTime, parsedID, err := types.ParseTsAndChainIdKey(test.prefix, key) require.Equal(t, test.timestamp.UTC(), parsedTime.UTC()) require.Equal(t, test.chainID, parsedID) require.NoError(t, err) @@ -99,12 +105,12 @@ func TestChainIdAndTsKeyAndParse(t *testing.T) { } for _, test := range tests { - key := chainIdAndTsKey(test.prefix, test.chainID, test.timestamp) + key := types.ChainIdAndTsKey(test.prefix, test.chainID, test.timestamp) require.NotEmpty(t, key) // Expected bytes = prefix + chainID length + chainID + time bytes expectedLen := 1 + 8 + len(test.chainID) + len(sdk.FormatTimeBytes(time.Time{})) require.Equal(t, expectedLen, len(key)) - parsedID, parsedTime, err := parseChainIdAndTsKey(test.prefix, key) + parsedID, parsedTime, err := types.ParseChainIdAndTsKey(test.prefix, key) require.Equal(t, test.chainID, parsedID) require.Equal(t, test.timestamp.UTC(), parsedTime.UTC()) require.NoError(t, err) @@ -124,43 +130,75 @@ func TestChainIdAndVscIdAndParse(t *testing.T) { } for _, test := range tests { - key := chainIdAndVscIdKey(test.prefix, test.chainID, test.vscID) + key := types.ChainIdAndVscIdKey(test.prefix, test.chainID, test.vscID) require.NotEmpty(t, key) // Expected bytes = prefix + chainID length + chainID + vscId bytes expectedLen := 1 + 8 + len(test.chainID) + 8 require.Equal(t, expectedLen, len(key)) - parsedID, parsedVscID, err := parseChainIdAndVscIdKey(test.prefix, key) + parsedID, parsedVscID, err := types.ParseChainIdAndVscIdKey(test.prefix, key) require.Equal(t, test.chainID, parsedID) require.Equal(t, test.vscID, parsedVscID) require.NoError(t, err) } } +// Tests the construction and parsing of ChainIdAndConsAddr keys +func TestChainIdAndConsAddrAndParse(t *testing.T) { + pubKey1, err := testkeeper.GenPubKey() + require.NoError(t, err) + pubKey2, err := testkeeper.GenPubKey() + require.NoError(t, err) + pubKey3, err := testkeeper.GenPubKey() + require.NoError(t, err) + + tests := []struct { + prefix byte + chainID string + addr sdk.ConsAddress + }{ + {prefix: 0x01, chainID: "1", addr: sdk.ConsAddress(pubKey1.Address())}, + {prefix: 0x02, chainID: "some other ID", addr: sdk.ConsAddress(pubKey2.Address())}, + {prefix: 0x03, chainID: "some other other chain ID", addr: sdk.ConsAddress(pubKey3.Address())}, + } + + for _, test := range tests { + key := types.ChainIdAndConsAddrKey(test.prefix, test.chainID, test.addr) + require.NotEmpty(t, key) + // Expected bytes = prefix + chainID length + chainID + consAddr bytes + expectedLen := 1 + 8 + len(test.chainID) + len(test.addr) + require.Equal(t, expectedLen, len(key)) + parsedID, parsedConsAddr, err := types.ParseChainIdAndConsAddrKey(test.prefix, key) + require.Equal(t, test.chainID, parsedID) + require.Equal(t, test.addr, parsedConsAddr) + require.NoError(t, err) + } +} + // Test key packing functions with the format func TestKeysWithPrefixAndId(t *testing.T) { funcs := []func(string) []byte{ - ChainToChannelKey, - ChannelToChainKey, - ChainToClientKey, - InitTimeoutTimestampKey, - ConsumerGenesisKey, - SlashAcksKey, - InitChainHeightKey, - PendingVSCsKey, - LockUnbondingOnTimeoutKey, + types.ChainToChannelKey, + types.ChannelToChainKey, + types.ChainToClientKey, + types.InitTimeoutTimestampKey, + types.ConsumerGenesisKey, + types.SlashAcksKey, + types.InitChainHeightKey, + types.PendingVSCsKey, + types.LockUnbondingOnTimeoutKey, } expectedBytePrefixes := []byte{ - ChainToChannelBytePrefix, - ChannelToChainBytePrefix, - ChainToClientBytePrefix, - InitTimeoutTimestampBytePrefix, - ConsumerGenesisBytePrefix, - SlashAcksBytePrefix, - InitChainHeightBytePrefix, - PendingVSCsBytePrefix, - LockUnbondingOnTimeoutBytePrefix, + types.ChainToChannelBytePrefix, + types.ChannelToChainBytePrefix, + types.ChainToClientBytePrefix, + types.InitTimeoutTimestampBytePrefix, + types.ConsumerGenesisBytePrefix, + types.SlashAcksBytePrefix, + types.InitChainHeightBytePrefix, + types.PendingVSCsBytePrefix, + types.LockUnbondingOnTimeoutBytePrefix, } tests := []struct { @@ -183,13 +221,13 @@ func TestKeysWithPrefixAndId(t *testing.T) { func TestKeysWithUint64Payload(t *testing.T) { funcs := []func(uint64) []byte{ - UnbondingOpKey, - ValsetUpdateBlockHeightKey, + types.UnbondingOpKey, + types.ValsetUpdateBlockHeightKey, } expectedBytePrefixes := []byte{ - UnbondingOpBytePrefix, - ValsetUpdateBlockHeightBytePrefix, + types.UnbondingOpBytePrefix, + types.ValsetUpdateBlockHeightBytePrefix, } tests := []struct { diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go new file mode 100644 index 0000000000..7ed1f8152c --- /dev/null +++ b/x/ccv/provider/types/msg.go @@ -0,0 +1,92 @@ +package types + +import ( + "strings" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" + sdk "github.com/cosmos/cosmos-sdk/types" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +// provider message types +const ( + TypeMsgAssignConsumerKey = "assign_consumer_key" +) + +var ( + _ sdk.Msg = &MsgAssignConsumerKey{} + _ codectypes.UnpackInterfacesMessage = (*MsgAssignConsumerKey)(nil) +) + +// NewMsgAssignConsumerKey creates a new MsgAssignConsumerKey instance. +// Delegator address and validator address are the same. +func NewMsgAssignConsumerKey(chainID string, providerValidatorAddress sdk.ValAddress, + consumerConsensusPubKey cryptotypes.PubKey) (*MsgAssignConsumerKey, error) { + var keyAsAny *codectypes.Any + if consumerConsensusPubKey != nil { + var err error + if keyAsAny, err = codectypes.NewAnyWithValue(consumerConsensusPubKey); err != nil { + return nil, err + } + } + return &MsgAssignConsumerKey{ + ChainId: chainID, + ProviderAddr: providerValidatorAddress.String(), + ConsumerKey: keyAsAny, + }, nil +} + +// Route implements the sdk.Msg interface. +func (msg MsgAssignConsumerKey) Route() string { return RouterKey } + +// Type implements the sdk.Msg interface. +func (msg MsgAssignConsumerKey) Type() string { + return TypeMsgAssignConsumerKey +} + +// GetSigners implements the sdk.Msg interface. It returns the address(es) that +// must sign over msg.GetSignBytes(). +// If the validator address is not same as delegator's, then the validator must +// sign the msg as well. +func (msg MsgAssignConsumerKey) GetSigners() []sdk.AccAddress { + valAddr, err := sdk.ValAddressFromBech32(msg.ProviderAddr) + if err != nil { + panic(err) + } + return []sdk.AccAddress{valAddr.Bytes()} +} + +// GetSignBytes returns the message bytes to sign over. +func (msg MsgAssignConsumerKey) GetSignBytes() []byte { + bz := ModuleCdc.MustMarshalJSON(&msg) + return sdk.MustSortJSON(bz) +} + +// ValidateBasic implements the sdk.Msg interface. +func (msg MsgAssignConsumerKey) ValidateBasic() error { + if strings.TrimSpace(msg.ChainId) == "" { + return ErrBlankConsumerChainID + } + // It is possible to assign keys for consumer chains that are not yet approved. + // This can only be done by a signing validator, but it is still sensible + // to limit the chainID size to prevent abuse. + // TODO: In future, a mechanism will be added to limit assigning keys to chains + // which are approved or pending approval, only. + if 128 < len(msg.ChainId) { + return ErrBlankConsumerChainID + } + if msg.ProviderAddr == "" { + return stakingtypes.ErrEmptyValidatorAddr + } + if msg.ConsumerKey == nil { + return ErrInvalidConsumerConsensusPubKey + } + return nil +} + +// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces +func (msg MsgAssignConsumerKey) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error { + var pubKey cryptotypes.PubKey + return unpacker.UnpackAny(msg.ConsumerKey, &pubKey) +} diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index a3fb286d40..ef8b91d9e4 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -469,6 +469,51 @@ func (m *ConsumerRemovalProposals) GetPending() []*ConsumerRemovalProposal { return nil } +// AddressList contains a list of consensus addresses +type AddressList struct { + Addresses [][]byte `protobuf:"bytes,1,rep,name=addresses,proto3" json:"addresses,omitempty"` +} + +func (m *AddressList) Reset() { *m = AddressList{} } +func (m *AddressList) String() string { return proto.CompactTextString(m) } +func (*AddressList) ProtoMessage() {} +func (*AddressList) Descriptor() ([]byte, []int) { + return fileDescriptor_f22ec409a72b7b72, []int{7} +} +func (m *AddressList) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *AddressList) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_AddressList.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *AddressList) XXX_Merge(src proto.Message) { + xxx_messageInfo_AddressList.Merge(m, src) +} +func (m *AddressList) XXX_Size() int { + return m.Size() +} +func (m *AddressList) XXX_DiscardUnknown() { + xxx_messageInfo_AddressList.DiscardUnknown(m) +} + +var xxx_messageInfo_AddressList proto.InternalMessageInfo + +func (m *AddressList) GetAddresses() [][]byte { + if m != nil { + return m.Addresses + } + return nil +} + func init() { proto.RegisterType((*ConsumerAdditionProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposal") proto.RegisterType((*ConsumerRemovalProposal)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposal") @@ -477,6 +522,7 @@ func init() { proto.RegisterType((*SlashAcks)(nil), "interchain_security.ccv.provider.v1.SlashAcks") proto.RegisterType((*ConsumerAdditionProposals)(nil), "interchain_security.ccv.provider.v1.ConsumerAdditionProposals") proto.RegisterType((*ConsumerRemovalProposals)(nil), "interchain_security.ccv.provider.v1.ConsumerRemovalProposals") + proto.RegisterType((*AddressList)(nil), "interchain_security.ccv.provider.v1.AddressList") } func init() { @@ -484,62 +530,63 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 872 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0xcf, 0x73, 0xdb, 0x44, - 0x14, 0xb6, 0xb0, 0x13, 0xdb, 0xeb, 0x52, 0xe8, 0xb6, 0x13, 0xe4, 0xd0, 0xb1, 0x8d, 0xb9, 0x98, - 0x61, 0x90, 0x26, 0xee, 0x85, 0x76, 0xe0, 0x90, 0x84, 0x29, 0xe1, 0xd0, 0xc1, 0x55, 0x02, 0xcc, - 0x70, 0xd1, 0xac, 0x57, 0x2f, 0xd6, 0x4e, 0x24, 0xad, 0x66, 0x77, 0x25, 0x92, 0x3b, 0x07, 0x8e, - 0x3d, 0xf6, 0xd8, 0xff, 0x80, 0x7f, 0xa3, 0xc7, 0x1e, 0x39, 0x01, 0x93, 0xfc, 0x15, 0xdc, 0x98, - 0xdd, 0x95, 0xec, 0xc4, 0x24, 0x33, 0xc9, 0x81, 0x9b, 0xf6, 0x7d, 0xdf, 0xfb, 0xde, 0x7b, 0xfa, - 0xf6, 0x07, 0x9a, 0xb2, 0x4c, 0x81, 0xa0, 0x31, 0x61, 0x59, 0x28, 0x81, 0x16, 0x82, 0xa9, 0x33, - 0x9f, 0xd2, 0xd2, 0xcf, 0x05, 0x2f, 0x59, 0x04, 0xc2, 0x2f, 0x77, 0x96, 0xdf, 0x5e, 0x2e, 0xb8, - 0xe2, 0xf8, 0xd3, 0x6b, 0x72, 0x3c, 0x4a, 0x4b, 0x6f, 0xc9, 0x2b, 0x77, 0xb6, 0x1f, 0x2d, 0xf8, - 0x82, 0x1b, 0xbe, 0xaf, 0xbf, 0x6c, 0xea, 0xf6, 0x70, 0xc1, 0xf9, 0x22, 0x01, 0xdf, 0xac, 0xe6, - 0xc5, 0xb1, 0xaf, 0x58, 0x0a, 0x52, 0x91, 0x34, 0xaf, 0x08, 0x83, 0x75, 0x42, 0x54, 0x08, 0xa2, - 0x18, 0xcf, 0x6a, 0x01, 0x36, 0xa7, 0x3e, 0xe5, 0x02, 0x7c, 0x9a, 0x30, 0xc8, 0x94, 0x6e, 0xcf, - 0x7e, 0x55, 0x04, 0x5f, 0x13, 0x12, 0xb6, 0x88, 0x95, 0x0d, 0x4b, 0x5f, 0x41, 0x16, 0x81, 0x48, - 0x99, 0x25, 0xaf, 0x56, 0x36, 0x61, 0xfc, 0x6b, 0x13, 0xb9, 0xfb, 0x3c, 0x93, 0x45, 0x0a, 0x62, - 0x37, 0x8a, 0x98, 0x2e, 0x36, 0x13, 0x3c, 0xe7, 0x92, 0x24, 0xf8, 0x11, 0xda, 0x50, 0x4c, 0x25, - 0xe0, 0x3a, 0x23, 0x67, 0xd2, 0x0d, 0xec, 0x02, 0x8f, 0x50, 0x2f, 0x02, 0x49, 0x05, 0xcb, 0x35, - 0xd9, 0x7d, 0xcf, 0x60, 0x97, 0x43, 0xb8, 0x8f, 0x3a, 0xf6, 0xff, 0xb0, 0xc8, 0x6d, 0x1a, 0xb8, - 0x6d, 0xd6, 0xdf, 0x45, 0xf8, 0x5b, 0x74, 0x9f, 0x65, 0x4c, 0x31, 0x92, 0x84, 0x31, 0xe8, 0x3e, - 0xdd, 0xd6, 0xc8, 0x99, 0xf4, 0xa6, 0xdb, 0x1e, 0x9b, 0x53, 0x4f, 0x8f, 0xe6, 0x55, 0x03, 0x95, - 0x3b, 0xde, 0x81, 0x61, 0xec, 0xb5, 0xde, 0xfe, 0x39, 0x6c, 0x04, 0xef, 0x57, 0x79, 0x36, 0x88, - 0x3f, 0x41, 0xf7, 0x16, 0x90, 0x81, 0x64, 0x32, 0x8c, 0x89, 0x8c, 0xdd, 0x8d, 0x91, 0x33, 0xb9, - 0x17, 0xf4, 0xaa, 0xd8, 0x01, 0x91, 0x31, 0x1e, 0xa2, 0xde, 0x9c, 0x65, 0x44, 0x9c, 0x59, 0xc6, - 0xa6, 0x61, 0x20, 0x1b, 0x32, 0x84, 0x7d, 0x84, 0x64, 0x4e, 0x7e, 0xc9, 0x42, 0xed, 0x83, 0xdb, - 0xae, 0x1a, 0xb1, 0x1e, 0x78, 0xb5, 0x07, 0xde, 0x51, 0x6d, 0xd2, 0x5e, 0x47, 0x37, 0xf2, 0xea, - 0xaf, 0xa1, 0x13, 0x74, 0x4d, 0x9e, 0x46, 0xf0, 0x53, 0xd4, 0x4f, 0x38, 0x3d, 0x09, 0x8b, 0x6c, - 0xce, 0xb3, 0x88, 0x65, 0x8b, 0x90, 0x5b, 0x41, 0x5e, 0x28, 0xb7, 0x33, 0x72, 0x26, 0x9d, 0x60, - 0x4b, 0x13, 0x7e, 0xa8, 0xf1, 0xef, 0x4d, 0x1e, 0x2f, 0xd4, 0xb3, 0xce, 0x6f, 0x6f, 0x86, 0x8d, - 0xd7, 0x6f, 0x86, 0x8d, 0xf1, 0xef, 0x0e, 0xfa, 0xa8, 0xb6, 0x21, 0x80, 0x94, 0x97, 0x24, 0xf9, - 0x3f, 0x5d, 0xd8, 0x45, 0x5d, 0xa9, 0x78, 0x6e, 0xe7, 0x6e, 0xdd, 0x61, 0xee, 0x8e, 0x4e, 0xd3, - 0xc0, 0xf8, 0x9f, 0x16, 0xda, 0x9c, 0x11, 0x41, 0x52, 0x89, 0x8f, 0xd0, 0x07, 0x0a, 0xd2, 0x3c, - 0x21, 0x0a, 0x42, 0x6b, 0x9e, 0x69, 0xb5, 0x37, 0xfd, 0xdc, 0x98, 0x7a, 0x79, 0x3b, 0x7a, 0x97, - 0x36, 0x60, 0xb9, 0xe3, 0xed, 0x9b, 0xe8, 0xa1, 0x22, 0x0a, 0x82, 0xfb, 0xb5, 0x86, 0x0d, 0xe2, - 0x2f, 0x91, 0xab, 0x44, 0x21, 0x95, 0xfe, 0xa3, 0x39, 0x08, 0xc6, 0xa3, 0xf0, 0x58, 0x10, 0xba, - 0x9c, 0xb6, 0x19, 0x6c, 0xd5, 0xf8, 0xcc, 0xc0, 0xcf, 0x2b, 0x14, 0xbf, 0x44, 0x98, 0xd2, 0xb2, - 0xf6, 0xa0, 0x4a, 0x36, 0xbf, 0xa0, 0x37, 0xed, 0xff, 0x67, 0xcc, 0x6f, 0xaa, 0x23, 0x66, 0xa7, - 0x7c, 0xad, 0xa7, 0xfc, 0x90, 0xd2, 0xb2, 0xf2, 0xc8, 0x4a, 0xe3, 0x43, 0xf4, 0x50, 0x6f, 0xbf, - 0x75, 0xcd, 0xd6, 0xed, 0x35, 0x1f, 0xe8, 0xfc, 0xab, 0xa2, 0x2f, 0x11, 0x2e, 0x25, 0x5d, 0xd7, - 0xdc, 0xb8, 0x43, 0x9f, 0xa5, 0xa4, 0x57, 0x25, 0x23, 0xf4, 0x58, 0x26, 0x44, 0xc6, 0x61, 0x0a, - 0x0a, 0x44, 0x28, 0x20, 0x4f, 0x20, 0x63, 0x32, 0xae, 0xc5, 0x37, 0x6f, 0x2f, 0xde, 0x37, 0x42, - 0x2f, 0xb4, 0x4e, 0x50, 0xcb, 0x54, 0x55, 0xf6, 0xd1, 0xe0, 0xfa, 0x2a, 0x4b, 0x83, 0xda, 0x66, - 0xbf, 0x7d, 0x7c, 0x8d, 0xc4, 0xd2, 0xa5, 0xa7, 0xa8, 0x9f, 0x92, 0xd3, 0x30, 0x07, 0x7b, 0x68, - 0xac, 0x60, 0x4e, 0xe8, 0x09, 0x28, 0x69, 0xce, 0x4d, 0x33, 0xd8, 0x4a, 0xc9, 0xe9, 0xcc, 0xe2, - 0x87, 0x1a, 0x9e, 0x59, 0x74, 0x3c, 0x47, 0x0f, 0x0e, 0x48, 0x16, 0xc9, 0x98, 0x9c, 0xc0, 0x0b, - 0x50, 0x24, 0x22, 0x8a, 0xe0, 0x27, 0x68, 0xab, 0xbe, 0x81, 0xc3, 0x63, 0x80, 0x30, 0xe7, 0x3c, - 0x09, 0x49, 0x14, 0x89, 0xea, 0xdc, 0x3c, 0xac, 0xd1, 0xe7, 0x00, 0x33, 0xce, 0x93, 0xdd, 0x28, - 0x12, 0xd8, 0x45, 0xed, 0x12, 0x84, 0x5c, 0x9d, 0xa0, 0x7a, 0x39, 0xfe, 0x0c, 0x75, 0x4d, 0xcd, - 0x5d, 0x7a, 0x22, 0xf1, 0x63, 0xd4, 0xd5, 0x4a, 0x20, 0x25, 0x48, 0xd7, 0x19, 0x35, 0x27, 0xdd, - 0x60, 0x15, 0x18, 0x2b, 0xd4, 0xbf, 0xe9, 0x0a, 0x95, 0xf8, 0x27, 0xd4, 0xae, 0x46, 0x34, 0x89, - 0xbd, 0xe9, 0xd7, 0xde, 0x2d, 0x1e, 0x10, 0xef, 0x26, 0xc1, 0xa0, 0x56, 0x1b, 0x8b, 0xd5, 0xc5, - 0xbd, 0x76, 0x63, 0x48, 0xfc, 0xe3, 0x7a, 0xd1, 0xaf, 0xee, 0x54, 0x74, 0x4d, 0x6f, 0x59, 0x73, - 0xef, 0xe8, 0xed, 0xf9, 0xc0, 0x79, 0x77, 0x3e, 0x70, 0xfe, 0x3e, 0x1f, 0x38, 0xaf, 0x2e, 0x06, - 0x8d, 0x77, 0x17, 0x83, 0xc6, 0x1f, 0x17, 0x83, 0xc6, 0xcf, 0xcf, 0x16, 0x4c, 0xc5, 0xc5, 0xdc, - 0xa3, 0x3c, 0xf5, 0x29, 0x97, 0x29, 0x97, 0xfe, 0xaa, 0xe2, 0x17, 0xcb, 0xb7, 0xf5, 0xf4, 0xea, - 0xeb, 0xaa, 0xce, 0x72, 0x90, 0xf3, 0x4d, 0xb3, 0x0d, 0x9f, 0xfc, 0x1b, 0x00, 0x00, 0xff, 0xff, - 0xf3, 0xd5, 0x5b, 0x4e, 0x8e, 0x07, 0x00, 0x00, + // 888 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x55, 0x41, 0x6f, 0xdb, 0x36, + 0x14, 0xb6, 0x66, 0x27, 0xb6, 0xe9, 0xac, 0x5b, 0xd9, 0x22, 0x93, 0xb3, 0xc2, 0xf6, 0xbc, 0x8b, + 0x87, 0x62, 0x12, 0xe2, 0x5e, 0xd6, 0x62, 0x3b, 0x38, 0x19, 0xba, 0x0c, 0x58, 0x31, 0x57, 0xc9, + 0x36, 0x60, 0x17, 0x81, 0xa6, 0x5e, 0x2c, 0x22, 0x92, 0x28, 0x90, 0xb4, 0x96, 0xdc, 0x77, 0xd8, + 0xb1, 0xc7, 0x1e, 0xfb, 0x0f, 0xf6, 0x37, 0x7a, 0xec, 0x71, 0xa7, 0x6d, 0x48, 0x7e, 0xc5, 0x6e, + 0x03, 0x49, 0xc9, 0x4e, 0xdc, 0x14, 0x48, 0x0e, 0xbd, 0x89, 0xef, 0xfb, 0xde, 0xf7, 0xde, 0xe3, + 0x47, 0x52, 0x68, 0xcc, 0x32, 0x05, 0x82, 0xc6, 0x84, 0x65, 0xa1, 0x04, 0xba, 0x10, 0x4c, 0x9d, + 0xf9, 0x94, 0x16, 0x7e, 0x2e, 0x78, 0xc1, 0x22, 0x10, 0x7e, 0xb1, 0xbb, 0xfc, 0xf6, 0x72, 0xc1, + 0x15, 0xc7, 0x9f, 0x5f, 0x93, 0xe3, 0x51, 0x5a, 0x78, 0x4b, 0x5e, 0xb1, 0xbb, 0x73, 0x7f, 0xce, + 0xe7, 0xdc, 0xf0, 0x7d, 0xfd, 0x65, 0x53, 0x77, 0xfa, 0x73, 0xce, 0xe7, 0x09, 0xf8, 0x66, 0x35, + 0x5b, 0x1c, 0xfb, 0x8a, 0xa5, 0x20, 0x15, 0x49, 0xf3, 0x92, 0xd0, 0x5b, 0x27, 0x44, 0x0b, 0x41, + 0x14, 0xe3, 0x59, 0x25, 0xc0, 0x66, 0xd4, 0xa7, 0x5c, 0x80, 0x4f, 0x13, 0x06, 0x99, 0xd2, 0xed, + 0xd9, 0xaf, 0x92, 0xe0, 0x6b, 0x42, 0xc2, 0xe6, 0xb1, 0xb2, 0x61, 0xe9, 0x2b, 0xc8, 0x22, 0x10, + 0x29, 0xb3, 0xe4, 0xd5, 0xca, 0x26, 0x0c, 0x7f, 0xaf, 0x23, 0x77, 0x9f, 0x67, 0x72, 0x91, 0x82, + 0x98, 0x44, 0x11, 0xd3, 0xc5, 0xa6, 0x82, 0xe7, 0x5c, 0x92, 0x04, 0xdf, 0x47, 0x1b, 0x8a, 0xa9, + 0x04, 0x5c, 0x67, 0xe0, 0x8c, 0xda, 0x81, 0x5d, 0xe0, 0x01, 0xea, 0x44, 0x20, 0xa9, 0x60, 0xb9, + 0x26, 0xbb, 0x1f, 0x18, 0xec, 0x72, 0x08, 0x77, 0x51, 0xcb, 0xee, 0x0f, 0x8b, 0xdc, 0xba, 0x81, + 0x9b, 0x66, 0xfd, 0x7d, 0x84, 0xbf, 0x43, 0x77, 0x58, 0xc6, 0x14, 0x23, 0x49, 0x18, 0x83, 0xee, + 0xd3, 0x6d, 0x0c, 0x9c, 0x51, 0x67, 0xbc, 0xe3, 0xb1, 0x19, 0xf5, 0xf4, 0x68, 0x5e, 0x39, 0x50, + 0xb1, 0xeb, 0x1d, 0x18, 0xc6, 0x5e, 0xe3, 0xf5, 0xdf, 0xfd, 0x5a, 0xf0, 0x61, 0x99, 0x67, 0x83, + 0xf8, 0x33, 0xb4, 0x35, 0x87, 0x0c, 0x24, 0x93, 0x61, 0x4c, 0x64, 0xec, 0x6e, 0x0c, 0x9c, 0xd1, + 0x56, 0xd0, 0x29, 0x63, 0x07, 0x44, 0xc6, 0xb8, 0x8f, 0x3a, 0x33, 0x96, 0x11, 0x71, 0x66, 0x19, + 0x9b, 0x86, 0x81, 0x6c, 0xc8, 0x10, 0xf6, 0x11, 0x92, 0x39, 0xf9, 0x2d, 0x0b, 0xb5, 0x0f, 0x6e, + 0xb3, 0x6c, 0xc4, 0x7a, 0xe0, 0x55, 0x1e, 0x78, 0x47, 0x95, 0x49, 0x7b, 0x2d, 0xdd, 0xc8, 0x8b, + 0x7f, 0xfa, 0x4e, 0xd0, 0x36, 0x79, 0x1a, 0xc1, 0x8f, 0x51, 0x37, 0xe1, 0xf4, 0x24, 0x5c, 0x64, + 0x33, 0x9e, 0x45, 0x2c, 0x9b, 0x87, 0xdc, 0x0a, 0xf2, 0x85, 0x72, 0x5b, 0x03, 0x67, 0xd4, 0x0a, + 0xb6, 0x35, 0xe1, 0xa7, 0x0a, 0xff, 0xd1, 0xe4, 0xf1, 0x85, 0x7a, 0xd2, 0xfa, 0xe3, 0x55, 0xbf, + 0xf6, 0xf2, 0x55, 0xbf, 0x36, 0xfc, 0xd3, 0x41, 0x9f, 0x54, 0x36, 0x04, 0x90, 0xf2, 0x82, 0x24, + 0xef, 0xd3, 0x85, 0x09, 0x6a, 0x4b, 0xc5, 0x73, 0x3b, 0x77, 0xe3, 0x16, 0x73, 0xb7, 0x74, 0x9a, + 0x06, 0x86, 0xff, 0x35, 0xd0, 0xe6, 0x94, 0x08, 0x92, 0x4a, 0x7c, 0x84, 0x3e, 0x52, 0x90, 0xe6, + 0x09, 0x51, 0x10, 0x5a, 0xf3, 0x4c, 0xab, 0x9d, 0xf1, 0x43, 0x63, 0xea, 0xe5, 0xe3, 0xe8, 0x5d, + 0x3a, 0x80, 0xc5, 0xae, 0xb7, 0x6f, 0xa2, 0x87, 0x8a, 0x28, 0x08, 0xee, 0x54, 0x1a, 0x36, 0x88, + 0xbf, 0x42, 0xae, 0x12, 0x0b, 0xa9, 0xf4, 0x8e, 0xe6, 0x20, 0x18, 0x8f, 0xc2, 0x63, 0x41, 0xe8, + 0x72, 0xda, 0x7a, 0xb0, 0x5d, 0xe1, 0x53, 0x03, 0x3f, 0x2d, 0x51, 0xfc, 0x1c, 0x61, 0x4a, 0x8b, + 0xca, 0x83, 0x32, 0xd9, 0x6c, 0x41, 0x67, 0xdc, 0x7d, 0x6b, 0xcc, 0x6f, 0xcb, 0x2b, 0x66, 0xa7, + 0x7c, 0xa9, 0xa7, 0xfc, 0x98, 0xd2, 0xa2, 0xf4, 0xc8, 0x4a, 0xe3, 0x43, 0x74, 0x4f, 0x1f, 0xbf, + 0x75, 0xcd, 0xc6, 0xcd, 0x35, 0xef, 0xea, 0xfc, 0xab, 0xa2, 0xcf, 0x11, 0x2e, 0x24, 0x5d, 0xd7, + 0xdc, 0xb8, 0x45, 0x9f, 0x85, 0xa4, 0x57, 0x25, 0x23, 0xf4, 0x40, 0x26, 0x44, 0xc6, 0x61, 0x0a, + 0x0a, 0x44, 0x28, 0x20, 0x4f, 0x20, 0x63, 0x32, 0xae, 0xc4, 0x37, 0x6f, 0x2e, 0xde, 0x35, 0x42, + 0xcf, 0xb4, 0x4e, 0x50, 0xc9, 0x94, 0x55, 0xf6, 0x51, 0xef, 0xfa, 0x2a, 0x4b, 0x83, 0x9a, 0xe6, + 0xbc, 0x7d, 0x7a, 0x8d, 0xc4, 0xd2, 0xa5, 0xc7, 0xa8, 0x9b, 0x92, 0xd3, 0x30, 0x07, 0x7b, 0x69, + 0xac, 0x60, 0x4e, 0xe8, 0x09, 0x28, 0x69, 0xee, 0x4d, 0x3d, 0xd8, 0x4e, 0xc9, 0xe9, 0xd4, 0xe2, + 0x87, 0x1a, 0x9e, 0x5a, 0x74, 0x38, 0x43, 0x77, 0x0f, 0x48, 0x16, 0xc9, 0x98, 0x9c, 0xc0, 0x33, + 0x50, 0x24, 0x22, 0x8a, 0xe0, 0x47, 0x68, 0xbb, 0x7a, 0x81, 0xc3, 0x63, 0x80, 0x30, 0xe7, 0x3c, + 0x09, 0x49, 0x14, 0x89, 0xf2, 0xde, 0xdc, 0xab, 0xd0, 0xa7, 0x00, 0x53, 0xce, 0x93, 0x49, 0x14, + 0x09, 0xec, 0xa2, 0x66, 0x01, 0x42, 0xae, 0x6e, 0x50, 0xb5, 0x1c, 0x7e, 0x81, 0xda, 0xa6, 0xe6, + 0x84, 0x9e, 0x48, 0xfc, 0x00, 0xb5, 0xb5, 0x12, 0x48, 0x09, 0xd2, 0x75, 0x06, 0xf5, 0x51, 0x3b, + 0x58, 0x05, 0x86, 0x0a, 0x75, 0xdf, 0xf5, 0x84, 0x4a, 0xfc, 0x0b, 0x6a, 0x96, 0x23, 0x9a, 0xc4, + 0xce, 0xf8, 0x1b, 0xef, 0x06, 0x3f, 0x10, 0xef, 0x5d, 0x82, 0x41, 0xa5, 0x36, 0x14, 0xab, 0x87, + 0x7b, 0xed, 0xc5, 0x90, 0xf8, 0xe7, 0xf5, 0xa2, 0x5f, 0xdf, 0xaa, 0xe8, 0x9a, 0xde, 0xaa, 0xe6, + 0x43, 0xd4, 0x99, 0xd8, 0xb1, 0x7f, 0x60, 0x52, 0xbd, 0xbd, 0x2d, 0x5b, 0x97, 0xb6, 0x65, 0xef, + 0xe8, 0xf5, 0x79, 0xcf, 0x79, 0x73, 0xde, 0x73, 0xfe, 0x3d, 0xef, 0x39, 0x2f, 0x2e, 0x7a, 0xb5, + 0x37, 0x17, 0xbd, 0xda, 0x5f, 0x17, 0xbd, 0xda, 0xaf, 0x4f, 0xe6, 0x4c, 0xc5, 0x8b, 0x99, 0x47, + 0x79, 0xea, 0x53, 0x2e, 0x53, 0x2e, 0xfd, 0x55, 0x7b, 0x5f, 0x2e, 0x7f, 0xc4, 0xa7, 0x57, 0x7f, + 0xc5, 0xea, 0x2c, 0x07, 0x39, 0xdb, 0x34, 0x67, 0xf6, 0xd1, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, + 0x3c, 0x25, 0xc0, 0xb7, 0xbb, 0x07, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -907,6 +954,38 @@ func (m *ConsumerRemovalProposals) MarshalToSizedBuffer(dAtA []byte) (int, error return len(dAtA) - i, nil } +func (m *AddressList) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *AddressList) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *AddressList) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.Addresses) > 0 { + for iNdEx := len(m.Addresses) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Addresses[iNdEx]) + copy(dAtA[i:], m.Addresses[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Addresses[iNdEx]))) + i-- + dAtA[i] = 0xa + } + } + return len(dAtA) - i, nil +} + func encodeVarintProvider(dAtA []byte, offset int, v uint64) int { offset -= sovProvider(v) base := offset @@ -1070,6 +1149,21 @@ func (m *ConsumerRemovalProposals) Size() (n int) { return n } +func (m *AddressList) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + if len(m.Addresses) > 0 { + for _, b := range m.Addresses { + l = len(b) + n += 1 + l + sovProvider(uint64(l)) + } + } + return n +} + func sovProvider(x uint64) (n int) { return (math_bits.Len64(x|1) + 6) / 7 } @@ -2207,6 +2301,88 @@ func (m *ConsumerRemovalProposals) Unmarshal(dAtA []byte) error { } return nil } +func (m *AddressList) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: AddressList: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: AddressList: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Addresses", wireType) + } + var byteLen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + byteLen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if byteLen < 0 { + return ErrInvalidLengthProvider + } + postIndex := iNdEx + byteLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Addresses = append(m.Addresses, make([]byte, postIndex-iNdEx)) + copy(m.Addresses[len(m.Addresses)-1], dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipProvider(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthProvider + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipProvider(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 93a054de8c..13fde6d8a5 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -418,6 +418,176 @@ func (m *Chain) GetClientId() string { return "" } +type QueryValidatorConsumerAddrRequest struct { + // The id of the consumer chain + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // The consensus address of the validator on the provider chain + ProviderAddress string `protobuf:"bytes,2,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"address"` +} + +func (m *QueryValidatorConsumerAddrRequest) Reset() { *m = QueryValidatorConsumerAddrRequest{} } +func (m *QueryValidatorConsumerAddrRequest) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorConsumerAddrRequest) ProtoMessage() {} +func (*QueryValidatorConsumerAddrRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{9} +} +func (m *QueryValidatorConsumerAddrRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorConsumerAddrRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorConsumerAddrRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorConsumerAddrRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorConsumerAddrRequest.Merge(m, src) +} +func (m *QueryValidatorConsumerAddrRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorConsumerAddrRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorConsumerAddrRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorConsumerAddrRequest proto.InternalMessageInfo + +type QueryValidatorConsumerAddrResponse struct { + // The address of the validator on the consumer chain + ConsumerAddress string `protobuf:"bytes,1,opt,name=consumer_address,json=consumerAddress,proto3" json:"consumer_address,omitempty"` +} + +func (m *QueryValidatorConsumerAddrResponse) Reset() { *m = QueryValidatorConsumerAddrResponse{} } +func (m *QueryValidatorConsumerAddrResponse) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorConsumerAddrResponse) ProtoMessage() {} +func (*QueryValidatorConsumerAddrResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{10} +} +func (m *QueryValidatorConsumerAddrResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorConsumerAddrResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorConsumerAddrResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorConsumerAddrResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorConsumerAddrResponse.Merge(m, src) +} +func (m *QueryValidatorConsumerAddrResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorConsumerAddrResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorConsumerAddrResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorConsumerAddrResponse proto.InternalMessageInfo + +func (m *QueryValidatorConsumerAddrResponse) GetConsumerAddress() string { + if m != nil { + return m.ConsumerAddress + } + return "" +} + +type QueryValidatorProviderAddrRequest struct { + // The id of the provider chain + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // The consensus address of the validator on the consumer chain + ConsumerAddress string `protobuf:"bytes,2,opt,name=consumer_address,json=consumerAddress,proto3" json:"consumer_address,omitempty" yaml:"address"` +} + +func (m *QueryValidatorProviderAddrRequest) Reset() { *m = QueryValidatorProviderAddrRequest{} } +func (m *QueryValidatorProviderAddrRequest) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorProviderAddrRequest) ProtoMessage() {} +func (*QueryValidatorProviderAddrRequest) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{11} +} +func (m *QueryValidatorProviderAddrRequest) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorProviderAddrRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorProviderAddrRequest.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorProviderAddrRequest) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorProviderAddrRequest.Merge(m, src) +} +func (m *QueryValidatorProviderAddrRequest) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorProviderAddrRequest) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorProviderAddrRequest.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorProviderAddrRequest proto.InternalMessageInfo + +type QueryValidatorProviderAddrResponse struct { + // The address of the validator on the provider chain + ProviderAddress string `protobuf:"bytes,1,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty"` +} + +func (m *QueryValidatorProviderAddrResponse) Reset() { *m = QueryValidatorProviderAddrResponse{} } +func (m *QueryValidatorProviderAddrResponse) String() string { return proto.CompactTextString(m) } +func (*QueryValidatorProviderAddrResponse) ProtoMessage() {} +func (*QueryValidatorProviderAddrResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_422512d7b7586cd7, []int{12} +} +func (m *QueryValidatorProviderAddrResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *QueryValidatorProviderAddrResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_QueryValidatorProviderAddrResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *QueryValidatorProviderAddrResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_QueryValidatorProviderAddrResponse.Merge(m, src) +} +func (m *QueryValidatorProviderAddrResponse) XXX_Size() int { + return m.Size() +} +func (m *QueryValidatorProviderAddrResponse) XXX_DiscardUnknown() { + xxx_messageInfo_QueryValidatorProviderAddrResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_QueryValidatorProviderAddrResponse proto.InternalMessageInfo + +func (m *QueryValidatorProviderAddrResponse) GetProviderAddress() string { + if m != nil { + return m.ProviderAddress + } + return "" +} + func init() { proto.RegisterType((*QueryConsumerGenesisRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisRequest") proto.RegisterType((*QueryConsumerGenesisResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerGenesisResponse") @@ -428,6 +598,10 @@ func init() { proto.RegisterType((*QueryConsumerChainStopProposalsRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainStopProposalsRequest") proto.RegisterType((*QueryConsumerChainStopProposalsResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainStopProposalsResponse") proto.RegisterType((*Chain)(nil), "interchain_security.ccv.provider.v1.Chain") + proto.RegisterType((*QueryValidatorConsumerAddrRequest)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerAddrRequest") + proto.RegisterType((*QueryValidatorConsumerAddrResponse)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerAddrResponse") + proto.RegisterType((*QueryValidatorProviderAddrRequest)(nil), "interchain_security.ccv.provider.v1.QueryValidatorProviderAddrRequest") + proto.RegisterType((*QueryValidatorProviderAddrResponse)(nil), "interchain_security.ccv.provider.v1.QueryValidatorProviderAddrResponse") } func init() { @@ -435,46 +609,57 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 620 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x95, 0xcf, 0x6f, 0xd3, 0x3e, - 0x18, 0xc6, 0xeb, 0x7e, 0xbf, 0xfb, 0x51, 0x0f, 0x2e, 0x66, 0x12, 0x25, 0xab, 0xc2, 0x14, 0x24, - 0x28, 0x48, 0x24, 0x4a, 0x77, 0x01, 0xa4, 0xd1, 0x1f, 0x13, 0x1a, 0x13, 0x43, 0x82, 0x8e, 0x13, - 0x20, 0x55, 0x59, 0x62, 0x65, 0x96, 0xda, 0x38, 0x8b, 0xdd, 0x88, 0x0a, 0x38, 0xc0, 0x01, 0x71, - 0x44, 0xe2, 0x7f, 0x42, 0x3b, 0x4e, 0xda, 0x85, 0x13, 0x42, 0x2d, 0xff, 0x06, 0x12, 0x8a, 0xe3, - 0xa4, 0x2b, 0x4d, 0xb7, 0xb6, 0xec, 0x96, 0xda, 0x79, 0x9f, 0xf7, 0xf3, 0xbc, 0xf5, 0xe3, 0x40, - 0x83, 0x78, 0x1c, 0x07, 0xf6, 0x81, 0x45, 0xbc, 0x16, 0xc3, 0x76, 0x37, 0x20, 0xbc, 0x67, 0xd8, - 0x76, 0x68, 0xf8, 0x01, 0x0d, 0x89, 0x83, 0x03, 0x23, 0x34, 0x8d, 0xc3, 0x2e, 0x0e, 0x7a, 0xba, - 0x1f, 0x50, 0x4e, 0xd1, 0x8d, 0x8c, 0x02, 0xdd, 0xb6, 0x43, 0x3d, 0x29, 0xd0, 0x43, 0x53, 0x29, - 0xb9, 0x94, 0xba, 0x6d, 0x6c, 0x58, 0x3e, 0x31, 0x2c, 0xcf, 0xa3, 0xdc, 0xe2, 0x84, 0x7a, 0x2c, - 0x96, 0x50, 0x56, 0x5d, 0xea, 0x52, 0xf1, 0x68, 0x44, 0x4f, 0x72, 0xd5, 0x9c, 0x44, 0x62, 0x53, - 0x8f, 0x75, 0x3b, 0x31, 0x89, 0x8b, 0x3d, 0xcc, 0x48, 0x22, 0x54, 0x99, 0x06, 0x3e, 0xe5, 0x12, - 0x35, 0xda, 0x3d, 0xb8, 0xf6, 0x3c, 0xb2, 0xb3, 0x25, 0x55, 0xb7, 0x63, 0xc5, 0x26, 0x3e, 0xec, - 0x62, 0xc6, 0xd1, 0x35, 0xb8, 0x1c, 0xeb, 0x11, 0xa7, 0x08, 0xd6, 0x41, 0xb9, 0xd0, 0x5c, 0x12, - 0xbf, 0x77, 0x1c, 0xed, 0x1d, 0x2c, 0x65, 0x57, 0x32, 0x9f, 0x7a, 0x0c, 0xa3, 0xd7, 0xf0, 0xb2, - 0xc4, 0x6b, 0x31, 0x6e, 0x71, 0x2c, 0xea, 0x57, 0x2a, 0xa6, 0x3e, 0x69, 0x62, 0x89, 0x31, 0x3d, - 0x34, 0x75, 0x29, 0xb6, 0x17, 0x15, 0x36, 0xfe, 0x3f, 0xfa, 0x71, 0x3d, 0xd7, 0xbc, 0xe4, 0x9e, - 0x5a, 0xd3, 0x4a, 0x50, 0x19, 0xe9, 0xbe, 0x15, 0xe9, 0x25, 0xd8, 0x9a, 0xf5, 0x97, 0xab, 0x64, - 0x57, 0xa2, 0x35, 0xe0, 0xa2, 0xe8, 0xcf, 0x8a, 0x60, 0xfd, 0xbf, 0xf2, 0x4a, 0xe5, 0x8e, 0x3e, - 0xc5, 0xbf, 0xa8, 0x0b, 0x91, 0xa6, 0xac, 0xd4, 0x6e, 0xc3, 0x5b, 0xe3, 0x2d, 0xf6, 0xb8, 0x15, - 0xf0, 0x67, 0x01, 0xf5, 0x29, 0xb3, 0xda, 0x29, 0xcd, 0x67, 0x00, 0xcb, 0xe7, 0xbf, 0x9b, 0x8e, - 0xad, 0xe0, 0x27, 0x8b, 0x72, 0x64, 0x0f, 0xa7, 0xc3, 0x93, 0xe2, 0x75, 0xc7, 0x21, 0xd1, 0xf1, - 0x1a, 0x4a, 0x0f, 0x05, 0xb5, 0x32, 0xbc, 0x99, 0x45, 0x42, 0xfd, 0x31, 0xe8, 0x4f, 0x20, 0xdb, - 0xe0, 0xc8, 0xab, 0x92, 0xf9, 0xd5, 0x38, 0xf3, 0xe6, 0x4c, 0xcc, 0x4d, 0xdc, 0xa1, 0xa1, 0xd5, - 0xce, 0x44, 0xae, 0xc2, 0x05, 0xd1, 0xfa, 0x8c, 0xb3, 0x88, 0xd6, 0x60, 0xc1, 0x6e, 0x13, 0xec, - 0xf1, 0x68, 0x2f, 0x2f, 0xf6, 0x96, 0xe3, 0x85, 0x1d, 0xa7, 0xf2, 0x6d, 0x09, 0x2e, 0x08, 0x27, - 0xa8, 0x0f, 0xe0, 0x6a, 0xd6, 0x99, 0x45, 0xb5, 0xa9, 0x68, 0xcf, 0x08, 0x8a, 0x52, 0xff, 0x07, - 0x85, 0x78, 0x8a, 0xda, 0xa3, 0x8f, 0x27, 0xbf, 0xbe, 0xe6, 0xab, 0x68, 0xf3, 0xfc, 0x4b, 0x28, - 0x89, 0x4a, 0x4b, 0x66, 0xc2, 0x78, 0x9b, 0x4c, 0xe6, 0x3d, 0x3a, 0x01, 0xf0, 0x4a, 0xc6, 0xe1, - 0x47, 0xd5, 0xd9, 0x09, 0x47, 0x42, 0xa5, 0xd4, 0xe6, 0x17, 0x90, 0x0e, 0xef, 0x0b, 0x87, 0x1b, - 0xc8, 0x9c, 0xc1, 0x61, 0x1c, 0x37, 0xf4, 0x21, 0x0f, 0x8b, 0x13, 0x32, 0xc4, 0xd0, 0xee, 0x9c, - 0x64, 0x99, 0x71, 0x55, 0x9e, 0x5e, 0x90, 0x9a, 0x34, 0xfd, 0x58, 0x98, 0x6e, 0xa0, 0xda, 0xac, - 0xa6, 0xa3, 0x6b, 0x33, 0xe0, 0xad, 0x34, 0x09, 0xe8, 0x37, 0x80, 0x57, 0xb3, 0x23, 0xc9, 0xd0, - 0x93, 0xb9, 0xa1, 0xc7, 0xb3, 0xaf, 0xec, 0x5e, 0x8c, 0x98, 0x1c, 0xc0, 0xb6, 0x18, 0x40, 0x1d, - 0x55, 0xe7, 0x18, 0x00, 0xf5, 0x87, 0xfe, 0x1b, 0x2f, 0x8e, 0xfa, 0x2a, 0x38, 0xee, 0xab, 0xe0, - 0x67, 0x5f, 0x05, 0x5f, 0x06, 0x6a, 0xee, 0x78, 0xa0, 0xe6, 0xbe, 0x0f, 0xd4, 0xdc, 0xcb, 0x07, - 0x2e, 0xe1, 0x07, 0xdd, 0x7d, 0xdd, 0xa6, 0x1d, 0xc3, 0xa6, 0xac, 0x43, 0xd9, 0xa9, 0x5e, 0x77, - 0xd3, 0x5e, 0x6f, 0x46, 0xbb, 0xf1, 0x9e, 0x8f, 0xd9, 0xfe, 0xa2, 0xf8, 0x10, 0x6e, 0xfc, 0x09, - 0x00, 0x00, 0xff, 0xff, 0xc5, 0x68, 0x22, 0xa9, 0xfb, 0x07, 0x00, 0x00, + // 795 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x96, 0xc1, 0x4f, 0xd4, 0x4a, + 0x1c, 0xc7, 0xb7, 0xbc, 0x07, 0x0f, 0x86, 0xf7, 0x1e, 0x64, 0x24, 0x11, 0x0b, 0xd9, 0xc5, 0x9a, + 0xe8, 0x62, 0x62, 0x9b, 0x5d, 0x2e, 0x82, 0xc1, 0x65, 0x97, 0x28, 0x12, 0x31, 0xe2, 0x62, 0x3c, + 0xa8, 0xc9, 0xa6, 0xb4, 0x93, 0xa5, 0xc9, 0x6e, 0xa7, 0x74, 0x66, 0x37, 0x6e, 0xd4, 0x83, 0x1e, + 0x94, 0xa3, 0x89, 0xff, 0x00, 0x7f, 0x80, 0x7f, 0x08, 0x47, 0x12, 0x2e, 0x9e, 0x88, 0x59, 0x3c, + 0x78, 0x34, 0xde, 0x4d, 0x4c, 0xa7, 0xd3, 0xd2, 0xd2, 0xb2, 0x74, 0x0b, 0xb7, 0x65, 0x66, 0x7e, + 0xdf, 0xdf, 0xf7, 0xf3, 0xeb, 0xf0, 0x6d, 0x81, 0x62, 0x98, 0x14, 0xd9, 0xda, 0x96, 0x6a, 0x98, + 0x35, 0x82, 0xb4, 0x96, 0x6d, 0xd0, 0x8e, 0xa2, 0x69, 0x6d, 0xc5, 0xb2, 0x71, 0xdb, 0xd0, 0x91, + 0xad, 0xb4, 0x0b, 0xca, 0x76, 0x0b, 0xd9, 0x1d, 0xd9, 0xb2, 0x31, 0xc5, 0xf0, 0x5a, 0x4c, 0x81, + 0xac, 0x69, 0x6d, 0xd9, 0x2b, 0x90, 0xdb, 0x05, 0x71, 0xba, 0x8e, 0x71, 0xbd, 0x81, 0x14, 0xd5, + 0x32, 0x14, 0xd5, 0x34, 0x31, 0x55, 0xa9, 0x81, 0x4d, 0xe2, 0x4a, 0x88, 0x13, 0x75, 0x5c, 0xc7, + 0xec, 0xa7, 0xe2, 0xfc, 0xe2, 0xab, 0x85, 0xd3, 0x9c, 0x68, 0xd8, 0x24, 0xad, 0xa6, 0xeb, 0xa4, + 0x8e, 0x4c, 0x44, 0x0c, 0x4f, 0xa8, 0x98, 0xc4, 0xbc, 0xef, 0x8b, 0xd5, 0x48, 0xb7, 0xc1, 0xd4, + 0x13, 0x07, 0x67, 0x99, 0xab, 0xae, 0xb8, 0x8a, 0x55, 0xb4, 0xdd, 0x42, 0x84, 0xc2, 0x2b, 0x60, + 0xd8, 0xd5, 0x33, 0xf4, 0x49, 0x61, 0x46, 0xc8, 0x8f, 0x54, 0xff, 0x61, 0x7f, 0xaf, 0xea, 0xd2, + 0x1b, 0x30, 0x1d, 0x5f, 0x49, 0x2c, 0x6c, 0x12, 0x04, 0x5f, 0x82, 0xff, 0xb8, 0xbd, 0x1a, 0xa1, + 0x2a, 0x45, 0xac, 0x7e, 0xb4, 0x58, 0x90, 0x4f, 0x9b, 0x98, 0x07, 0x26, 0xb7, 0x0b, 0x32, 0x17, + 0xdb, 0x70, 0x0a, 0x2b, 0x7f, 0xef, 0x1d, 0xe6, 0x32, 0xd5, 0x7f, 0xeb, 0x81, 0x35, 0x69, 0x1a, + 0x88, 0xa1, 0xee, 0xcb, 0x8e, 0x9e, 0x67, 0x5b, 0x52, 0x4f, 0x50, 0x79, 0xbb, 0xdc, 0x5a, 0x05, + 0x0c, 0xb1, 0xfe, 0x64, 0x52, 0x98, 0xf9, 0x2b, 0x3f, 0x5a, 0xbc, 0x29, 0x27, 0x78, 0x8a, 0x32, + 0x13, 0xa9, 0xf2, 0x4a, 0x69, 0x16, 0xdc, 0x88, 0xb6, 0xd8, 0xa0, 0xaa, 0x4d, 0xd7, 0x6d, 0x6c, + 0x61, 0xa2, 0x36, 0x7c, 0x37, 0x3b, 0x02, 0xc8, 0x9f, 0x7d, 0xd6, 0x1f, 0xdb, 0x88, 0xe5, 0x2d, + 0xf2, 0x91, 0xdd, 0x4d, 0x66, 0x8f, 0x8b, 0x97, 0x75, 0xdd, 0x70, 0xae, 0xd7, 0xb1, 0xf4, 0xb1, + 0xa0, 0x94, 0x07, 0xd7, 0xe3, 0x9c, 0x60, 0x2b, 0x62, 0xfa, 0x83, 0x10, 0x0f, 0x18, 0x3a, 0xca, + 0x3d, 0xbf, 0x88, 0x7a, 0x5e, 0xec, 0xcb, 0x73, 0x15, 0x35, 0x71, 0x5b, 0x6d, 0xc4, 0x5a, 0x2e, + 0x81, 0x41, 0xd6, 0xba, 0xc7, 0x5d, 0x84, 0x53, 0x60, 0x44, 0x6b, 0x18, 0xc8, 0xa4, 0xce, 0xde, + 0x00, 0xdb, 0x1b, 0x76, 0x17, 0x56, 0x75, 0xe9, 0xa3, 0x00, 0xae, 0x32, 0x92, 0x67, 0x6a, 0xc3, + 0xd0, 0x55, 0x8a, 0xed, 0xc0, 0xa8, 0xec, 0xb3, 0x6f, 0x3a, 0x5c, 0x04, 0xe3, 0x9e, 0xe9, 0x9a, + 0xaa, 0xeb, 0x36, 0x22, 0xc4, 0x6d, 0x52, 0x81, 0xbf, 0x0e, 0x73, 0xff, 0x77, 0xd4, 0x66, 0x63, + 0x41, 0xe2, 0x1b, 0x52, 0x75, 0xcc, 0x3b, 0x5b, 0x76, 0x57, 0x16, 0x86, 0x77, 0x76, 0x73, 0x99, + 0x1f, 0xbb, 0xb9, 0x8c, 0xf4, 0x18, 0x48, 0xbd, 0x8c, 0xf0, 0x69, 0xce, 0x82, 0x71, 0xef, 0x5f, + 0xc1, 0x6f, 0xe7, 0x3a, 0x1a, 0xd3, 0x02, 0xe7, 0x9d, 0x66, 0x51, 0xb4, 0xf5, 0x40, 0xf3, 0x64, + 0x68, 0x91, 0x5e, 0x3d, 0xd0, 0x4e, 0xf4, 0xef, 0x85, 0x16, 0x36, 0x72, 0x8c, 0x16, 0x99, 0x24, + 0x47, 0x3b, 0x31, 0xb5, 0xe2, 0x97, 0x51, 0x30, 0xc8, 0x14, 0x61, 0x57, 0x00, 0x13, 0x71, 0x49, + 0x03, 0x97, 0x12, 0xdd, 0xb1, 0x1e, 0xf1, 0x26, 0x96, 0xcf, 0xa1, 0xe0, 0x22, 0x49, 0xf7, 0xde, + 0x1f, 0x7c, 0xff, 0x3c, 0x50, 0x82, 0x8b, 0x67, 0xbf, 0x3a, 0xfc, 0x49, 0xf3, 0x24, 0x53, 0x5e, + 0x7b, 0x8f, 0xe5, 0x2d, 0x3c, 0x10, 0xc0, 0xa5, 0x98, 0xc8, 0x82, 0xa5, 0xfe, 0x1d, 0x86, 0xa2, + 0x50, 0x5c, 0x4a, 0x2f, 0xc0, 0x09, 0xe7, 0x19, 0xe1, 0x1c, 0x2c, 0xf4, 0x41, 0xe8, 0x86, 0x24, + 0x7c, 0x37, 0x00, 0x26, 0x4f, 0x49, 0x3e, 0x02, 0xd7, 0x52, 0x3a, 0x8b, 0x0d, 0x59, 0xf1, 0xd1, + 0x05, 0xa9, 0x71, 0xe8, 0x07, 0x0c, 0xba, 0x02, 0x97, 0xfa, 0x85, 0x76, 0x5e, 0x76, 0x36, 0xad, + 0xf9, 0xf9, 0x05, 0x7f, 0x0b, 0xe0, 0x72, 0x7c, 0x90, 0x12, 0xf8, 0x30, 0xb5, 0xe9, 0x68, 0x62, + 0x8b, 0x6b, 0x17, 0x23, 0xc6, 0x07, 0xb0, 0xc2, 0x06, 0x50, 0x86, 0xa5, 0x14, 0x03, 0xc0, 0x56, + 0x80, 0xff, 0xa7, 0xc0, 0x5f, 0xd5, 0xb1, 0xa9, 0x07, 0xef, 0x27, 0x77, 0xdd, 0x2b, 0xbf, 0xc5, + 0x95, 0x73, 0xeb, 0x70, 0xf0, 0x32, 0x03, 0xbf, 0x03, 0xe7, 0x13, 0x7c, 0x0b, 0x7a, 0x42, 0xb5, + 0x50, 0x88, 0xc6, 0x20, 0x07, 0xd3, 0x30, 0x15, 0x72, 0x4c, 0xae, 0xa7, 0x42, 0x8e, 0x8b, 0xe5, + 0x74, 0xc8, 0xa1, 0x20, 0xaf, 0x3c, 0xdd, 0xeb, 0x66, 0x85, 0xfd, 0x6e, 0x56, 0xf8, 0xd6, 0xcd, + 0x0a, 0x9f, 0x8e, 0xb2, 0x99, 0xfd, 0xa3, 0x6c, 0xe6, 0xeb, 0x51, 0x36, 0xf3, 0x7c, 0xa1, 0x6e, + 0xd0, 0xad, 0xd6, 0xa6, 0xac, 0xe1, 0xa6, 0xa2, 0x61, 0xd2, 0xc4, 0x24, 0xd0, 0xe5, 0x96, 0xdf, + 0xe5, 0x55, 0xb8, 0x0f, 0xed, 0x58, 0x88, 0x6c, 0x0e, 0xb1, 0x8f, 0xd4, 0xb9, 0x3f, 0x01, 0x00, + 0x00, 0xff, 0xff, 0xb0, 0x31, 0x40, 0x03, 0x97, 0x0b, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -499,6 +684,12 @@ type QueryClient interface { QueryConsumerChainStarts(ctx context.Context, in *QueryConsumerChainStartProposalsRequest, opts ...grpc.CallOption) (*QueryConsumerChainStartProposalsResponse, error) // QueryConsumerChainStops queries consumer chain stop proposals. QueryConsumerChainStops(ctx context.Context, in *QueryConsumerChainStopProposalsRequest, opts ...grpc.CallOption) (*QueryConsumerChainStopProposalsResponse, error) + // QueryValidatorConsumerAddr queries the address + // assigned by a validator for a consumer chain. + QueryValidatorConsumerAddr(ctx context.Context, in *QueryValidatorConsumerAddrRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerAddrResponse, error) + // QueryProviderAddr returns the provider chain validator + // given a consumer chain validator address + QueryValidatorProviderAddr(ctx context.Context, in *QueryValidatorProviderAddrRequest, opts ...grpc.CallOption) (*QueryValidatorProviderAddrResponse, error) } type queryClient struct { @@ -545,6 +736,24 @@ func (c *queryClient) QueryConsumerChainStops(ctx context.Context, in *QueryCons return out, nil } +func (c *queryClient) QueryValidatorConsumerAddr(ctx context.Context, in *QueryValidatorConsumerAddrRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerAddrResponse, error) { + out := new(QueryValidatorConsumerAddrResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryValidatorConsumerAddr", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *queryClient) QueryValidatorProviderAddr(ctx context.Context, in *QueryValidatorProviderAddrRequest, opts ...grpc.CallOption) (*QueryValidatorProviderAddrResponse, error) { + out := new(QueryValidatorProviderAddrResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryValidatorProviderAddr", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // QueryServer is the server API for Query service. type QueryServer interface { // ConsumerGenesis queries the genesis state needed to start a consumer chain @@ -557,6 +766,12 @@ type QueryServer interface { QueryConsumerChainStarts(context.Context, *QueryConsumerChainStartProposalsRequest) (*QueryConsumerChainStartProposalsResponse, error) // QueryConsumerChainStops queries consumer chain stop proposals. QueryConsumerChainStops(context.Context, *QueryConsumerChainStopProposalsRequest) (*QueryConsumerChainStopProposalsResponse, error) + // QueryValidatorConsumerAddr queries the address + // assigned by a validator for a consumer chain. + QueryValidatorConsumerAddr(context.Context, *QueryValidatorConsumerAddrRequest) (*QueryValidatorConsumerAddrResponse, error) + // QueryProviderAddr returns the provider chain validator + // given a consumer chain validator address + QueryValidatorProviderAddr(context.Context, *QueryValidatorProviderAddrRequest) (*QueryValidatorProviderAddrResponse, error) } // UnimplementedQueryServer can be embedded to have forward compatible implementations. @@ -575,6 +790,12 @@ func (*UnimplementedQueryServer) QueryConsumerChainStarts(ctx context.Context, r func (*UnimplementedQueryServer) QueryConsumerChainStops(ctx context.Context, req *QueryConsumerChainStopProposalsRequest) (*QueryConsumerChainStopProposalsResponse, error) { return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerChainStops not implemented") } +func (*UnimplementedQueryServer) QueryValidatorConsumerAddr(ctx context.Context, req *QueryValidatorConsumerAddrRequest) (*QueryValidatorConsumerAddrResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryValidatorConsumerAddr not implemented") +} +func (*UnimplementedQueryServer) QueryValidatorProviderAddr(ctx context.Context, req *QueryValidatorProviderAddrRequest) (*QueryValidatorProviderAddrResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method QueryValidatorProviderAddr not implemented") +} func RegisterQueryServer(s grpc1.Server, srv QueryServer) { s.RegisterService(&_Query_serviceDesc, srv) @@ -652,6 +873,42 @@ func _Query_QueryConsumerChainStops_Handler(srv interface{}, ctx context.Context return interceptor(ctx, in, info, handler) } +func _Query_QueryValidatorConsumerAddr_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryValidatorConsumerAddrRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryValidatorConsumerAddr(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryValidatorConsumerAddr", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryValidatorConsumerAddr(ctx, req.(*QueryValidatorConsumerAddrRequest)) + } + return interceptor(ctx, in, info, handler) +} + +func _Query_QueryValidatorProviderAddr_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(QueryValidatorProviderAddrRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(QueryServer).QueryValidatorProviderAddr(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryValidatorProviderAddr", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(QueryServer).QueryValidatorProviderAddr(ctx, req.(*QueryValidatorProviderAddrRequest)) + } + return interceptor(ctx, in, info, handler) +} + var _Query_serviceDesc = grpc.ServiceDesc{ ServiceName: "interchain_security.ccv.provider.v1.Query", HandlerType: (*QueryServer)(nil), @@ -672,6 +929,14 @@ var _Query_serviceDesc = grpc.ServiceDesc{ MethodName: "QueryConsumerChainStops", Handler: _Query_QueryConsumerChainStops_Handler, }, + { + MethodName: "QueryValidatorConsumerAddr", + Handler: _Query_QueryValidatorConsumerAddr_Handler, + }, + { + MethodName: "QueryValidatorProviderAddr", + Handler: _Query_QueryValidatorProviderAddr_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "interchain_security/ccv/provider/v1/query.proto", @@ -953,6 +1218,140 @@ func (m *Chain) MarshalToSizedBuffer(dAtA []byte) (int, error) { return len(dAtA) - i, nil } +func (m *QueryValidatorConsumerAddrRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorConsumerAddrRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorConsumerAddrRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddress) > 0 { + i -= len(m.ProviderAddress) + copy(dAtA[i:], m.ProviderAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ProviderAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorConsumerAddrResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorConsumerAddrResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorConsumerAddrResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsumerAddress) > 0 { + i -= len(m.ConsumerAddress) + copy(dAtA[i:], m.ConsumerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorProviderAddrRequest) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorProviderAddrRequest) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorProviderAddrRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ConsumerAddress) > 0 { + i -= len(m.ConsumerAddress) + copy(dAtA[i:], m.ConsumerAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ConsumerAddress))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *QueryValidatorProviderAddrResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *QueryValidatorProviderAddrResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *QueryValidatorProviderAddrResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if len(m.ProviderAddress) > 0 { + i -= len(m.ProviderAddress) + copy(dAtA[i:], m.ProviderAddress) + i = encodeVarintQuery(dAtA, i, uint64(len(m.ProviderAddress))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + func encodeVarintQuery(dAtA []byte, offset int, v uint64) int { offset -= sovQuery(v) base := offset @@ -1073,16 +1472,76 @@ func (m *Chain) Size() (n int) { return n } -func sovQuery(x uint64) (n int) { - return (math_bits.Len64(x|1) + 6) / 7 -} -func sozQuery(x uint64) (n int) { - return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) -} -func (m *QueryConsumerGenesisRequest) Unmarshal(dAtA []byte) error { - l := len(dAtA) - iNdEx := 0 - for iNdEx < l { +func (m *QueryValidatorConsumerAddrRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ProviderAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryValidatorConsumerAddrResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ConsumerAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryValidatorProviderAddrRequest) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + l = len(m.ConsumerAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func (m *QueryValidatorProviderAddrResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ProviderAddress) + if l > 0 { + n += 1 + l + sovQuery(uint64(l)) + } + return n +} + +func sovQuery(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozQuery(x uint64) (n int) { + return sovQuery(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *QueryConsumerGenesisRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { preIndex := iNdEx var wire uint64 for shift := uint(0); ; shift += 7 { @@ -1764,6 +2223,398 @@ func (m *Chain) Unmarshal(dAtA []byte) error { } return nil } +func (m *QueryValidatorConsumerAddrRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorConsumerAddrRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorConsumerAddrRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryValidatorConsumerAddrResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorConsumerAddrResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorConsumerAddrResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryValidatorProviderAddrRequest) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorProviderAddrRequest: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorProviderAddrRequest: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ConsumerAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *QueryValidatorProviderAddrResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: QueryValidatorProviderAddrResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: QueryValidatorProviderAddrResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddress = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipQuery(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthQuery + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} func skipQuery(dAtA []byte) (n int, err error) { l := len(dAtA) iNdEx := 0 diff --git a/x/ccv/provider/types/query.pb.gw.go b/x/ccv/provider/types/query.pb.gw.go index 2d660f5508..855a14fa37 100644 --- a/x/ccv/provider/types/query.pb.gw.go +++ b/x/ccv/provider/types/query.pb.gw.go @@ -141,6 +141,78 @@ func local_request_Query_QueryConsumerChainStops_0(ctx context.Context, marshale } +var ( + filter_Query_QueryValidatorConsumerAddr_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QueryValidatorConsumerAddr_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorConsumerAddrRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerAddr_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QueryValidatorConsumerAddr(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryValidatorConsumerAddr_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorConsumerAddrRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorConsumerAddr_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QueryValidatorConsumerAddr(ctx, &protoReq) + return msg, metadata, err + +} + +var ( + filter_Query_QueryValidatorProviderAddr_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)} +) + +func request_Query_QueryValidatorProviderAddr_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorProviderAddrRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorProviderAddr_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := client.QueryValidatorProviderAddr(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD)) + return msg, metadata, err + +} + +func local_request_Query_QueryValidatorProviderAddr_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { + var protoReq QueryValidatorProviderAddrRequest + var metadata runtime.ServerMetadata + + if err := req.ParseForm(); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Query_QueryValidatorProviderAddr_0); err != nil { + return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err) + } + + msg, err := server.QueryValidatorProviderAddr(ctx, &protoReq) + return msg, metadata, err + +} + // RegisterQueryHandlerServer registers the http handlers for service Query to "mux". // UnaryRPC :call QueryServer directly. // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906. @@ -239,6 +311,52 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv }) + mux.Handle("GET", pattern_Query_QueryValidatorConsumerAddr_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryValidatorConsumerAddr_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorConsumerAddr_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryValidatorProviderAddr_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + var stream runtime.ServerTransportStream + ctx = grpc.NewContextWithServerTransportStream(ctx, &stream) + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := local_request_Query_QueryValidatorProviderAddr_0(rctx, inboundMarshaler, server, req, pathParams) + md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer()) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorProviderAddr_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -360,6 +478,46 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie }) + mux.Handle("GET", pattern_Query_QueryValidatorConsumerAddr_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryValidatorConsumerAddr_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorConsumerAddr_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + + mux.Handle("GET", pattern_Query_QueryValidatorProviderAddr_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { + ctx, cancel := context.WithCancel(req.Context()) + defer cancel() + inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req) + rctx, err := runtime.AnnotateContext(ctx, mux, req) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + resp, md, err := request_Query_QueryValidatorProviderAddr_0(rctx, inboundMarshaler, client, req, pathParams) + ctx = runtime.NewServerMetadataContext(ctx, md) + if err != nil { + runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err) + return + } + + forward_Query_QueryValidatorProviderAddr_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...) + + }) + return nil } @@ -371,6 +529,10 @@ var ( pattern_Query_QueryConsumerChainStarts_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chain_start_proposals"}, "", runtime.AssumeColonVerbOpt(false))) pattern_Query_QueryConsumerChainStops_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "consumer_chain_stop_proposals"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryValidatorConsumerAddr_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "validator_consumer_addr"}, "", runtime.AssumeColonVerbOpt(false))) + + pattern_Query_QueryValidatorProviderAddr_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3}, []string{"interchain_security", "ccv", "provider", "validator_provider_addr"}, "", runtime.AssumeColonVerbOpt(false))) ) var ( @@ -381,4 +543,8 @@ var ( forward_Query_QueryConsumerChainStarts_0 = runtime.ForwardResponseMessage forward_Query_QueryConsumerChainStops_0 = runtime.ForwardResponseMessage + + forward_Query_QueryValidatorConsumerAddr_0 = runtime.ForwardResponseMessage + + forward_Query_QueryValidatorProviderAddr_0 = runtime.ForwardResponseMessage ) diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go new file mode 100644 index 0000000000..fcf29bb203 --- /dev/null +++ b/x/ccv/provider/types/tx.pb.go @@ -0,0 +1,633 @@ +// Code generated by protoc-gen-gogo. DO NOT EDIT. +// source: interchain_security/ccv/provider/v1/tx.proto + +package types + +import ( + context "context" + fmt "fmt" + types "github.com/cosmos/cosmos-sdk/codec/types" + _ "github.com/gogo/protobuf/gogoproto" + grpc1 "github.com/gogo/protobuf/grpc" + proto "github.com/gogo/protobuf/proto" + _ "github.com/regen-network/cosmos-proto" + _ "google.golang.org/genproto/googleapis/api/annotations" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + io "io" + math "math" + math_bits "math/bits" +) + +// Reference imports to suppress errors if they are not otherwise used. +var _ = proto.Marshal +var _ = fmt.Errorf +var _ = math.Inf + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the proto package it is being compiled against. +// A compilation error at this line likely means your copy of the +// proto package needs to be updated. +const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package + +type MsgAssignConsumerKey struct { + // The chain id of the consumer chain to assign a consensus public key to + ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"` + // The validator address on the provider + ProviderAddr string `protobuf:"bytes,2,opt,name=provider_addr,json=providerAddr,proto3" json:"provider_addr,omitempty" yaml:"address"` + // The consensus public key to use on the consumer + ConsumerKey *types.Any `protobuf:"bytes,3,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"` +} + +func (m *MsgAssignConsumerKey) Reset() { *m = MsgAssignConsumerKey{} } +func (m *MsgAssignConsumerKey) String() string { return proto.CompactTextString(m) } +func (*MsgAssignConsumerKey) ProtoMessage() {} +func (*MsgAssignConsumerKey) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{0} +} +func (m *MsgAssignConsumerKey) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAssignConsumerKey) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAssignConsumerKey.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAssignConsumerKey) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssignConsumerKey.Merge(m, src) +} +func (m *MsgAssignConsumerKey) XXX_Size() int { + return m.Size() +} +func (m *MsgAssignConsumerKey) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssignConsumerKey.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAssignConsumerKey proto.InternalMessageInfo + +type MsgAssignConsumerKeyResponse struct { +} + +func (m *MsgAssignConsumerKeyResponse) Reset() { *m = MsgAssignConsumerKeyResponse{} } +func (m *MsgAssignConsumerKeyResponse) String() string { return proto.CompactTextString(m) } +func (*MsgAssignConsumerKeyResponse) ProtoMessage() {} +func (*MsgAssignConsumerKeyResponse) Descriptor() ([]byte, []int) { + return fileDescriptor_43221a4391e9fbf4, []int{1} +} +func (m *MsgAssignConsumerKeyResponse) XXX_Unmarshal(b []byte) error { + return m.Unmarshal(b) +} +func (m *MsgAssignConsumerKeyResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) { + if deterministic { + return xxx_messageInfo_MsgAssignConsumerKeyResponse.Marshal(b, m, deterministic) + } else { + b = b[:cap(b)] + n, err := m.MarshalToSizedBuffer(b) + if err != nil { + return nil, err + } + return b[:n], nil + } +} +func (m *MsgAssignConsumerKeyResponse) XXX_Merge(src proto.Message) { + xxx_messageInfo_MsgAssignConsumerKeyResponse.Merge(m, src) +} +func (m *MsgAssignConsumerKeyResponse) XXX_Size() int { + return m.Size() +} +func (m *MsgAssignConsumerKeyResponse) XXX_DiscardUnknown() { + xxx_messageInfo_MsgAssignConsumerKeyResponse.DiscardUnknown(m) +} + +var xxx_messageInfo_MsgAssignConsumerKeyResponse proto.InternalMessageInfo + +func init() { + proto.RegisterType((*MsgAssignConsumerKey)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKey") + proto.RegisterType((*MsgAssignConsumerKeyResponse)(nil), "interchain_security.ccv.provider.v1.MsgAssignConsumerKeyResponse") +} + +func init() { + proto.RegisterFile("interchain_security/ccv/provider/v1/tx.proto", fileDescriptor_43221a4391e9fbf4) +} + +var fileDescriptor_43221a4391e9fbf4 = []byte{ + // 406 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x92, 0xbd, 0x8e, 0xd3, 0x40, + 0x10, 0xc7, 0xbd, 0x9c, 0x04, 0xc7, 0xde, 0x81, 0x84, 0xe5, 0xc2, 0x17, 0x9d, 0x9c, 0x93, 0x69, + 0xae, 0xe0, 0x76, 0x75, 0xa1, 0x40, 0xa4, 0x73, 0xa8, 0x50, 0x14, 0x09, 0x2c, 0x2a, 0x1a, 0xcb, + 0x5e, 0x2f, 0x9b, 0x15, 0xf1, 0xae, 0xb5, 0xbb, 0xb6, 0xb2, 0x6f, 0x40, 0x09, 0x25, 0x5d, 0x1e, + 0x82, 0x77, 0x00, 0x51, 0xa5, 0xa4, 0x42, 0x28, 0x69, 0xa8, 0x79, 0x02, 0x14, 0x7f, 0x10, 0x21, + 0x52, 0xa0, 0xeb, 0x66, 0xe6, 0x3f, 0x3b, 0xf3, 0x9b, 0x9d, 0x81, 0x8f, 0xb8, 0x30, 0x54, 0x91, + 0x79, 0xca, 0x45, 0xa2, 0x29, 0xa9, 0x14, 0x37, 0x16, 0x13, 0x52, 0xe3, 0x52, 0xc9, 0x9a, 0xe7, + 0x54, 0xe1, 0xfa, 0x1a, 0x9b, 0x25, 0x2a, 0x95, 0x34, 0xd2, 0x7d, 0x78, 0x20, 0x1b, 0x11, 0x52, + 0xa3, 0x3e, 0x1b, 0xd5, 0xd7, 0x83, 0x73, 0x26, 0x25, 0x5b, 0x50, 0x9c, 0x96, 0x1c, 0xa7, 0x42, + 0x48, 0x93, 0x1a, 0x2e, 0x85, 0x6e, 0x4b, 0x0c, 0x3c, 0x26, 0x99, 0x6c, 0x4c, 0xbc, 0xb3, 0xba, + 0xe8, 0x19, 0x91, 0xba, 0x90, 0x3a, 0x69, 0x85, 0xd6, 0xe9, 0xa5, 0xae, 0x5c, 0xe3, 0x65, 0xd5, + 0x1b, 0x9c, 0x0a, 0xdb, 0x4a, 0xe1, 0x67, 0x00, 0xbd, 0x99, 0x66, 0x91, 0xd6, 0x9c, 0x89, 0x67, + 0x52, 0xe8, 0xaa, 0xa0, 0x6a, 0x4a, 0xad, 0x7b, 0x06, 0x8f, 0x5b, 0x48, 0x9e, 0xfb, 0xe0, 0x02, + 0x5c, 0xde, 0x8d, 0xef, 0x34, 0xfe, 0xf3, 0xdc, 0x7d, 0x02, 0xef, 0xf5, 0xb0, 0x49, 0x9a, 0xe7, + 0xca, 0xbf, 0xb5, 0xd3, 0x27, 0xee, 0xaf, 0xef, 0xc3, 0xfb, 0x36, 0x2d, 0x16, 0xe3, 0x70, 0x17, + 0xa5, 0x5a, 0x87, 0xf1, 0x69, 0x9f, 0x18, 0xe5, 0xb9, 0x72, 0x5f, 0xc2, 0x53, 0xd2, 0xb5, 0x48, + 0xde, 0x52, 0xeb, 0x1f, 0x5d, 0x80, 0xcb, 0x93, 0x91, 0x87, 0x5a, 0x3c, 0xd4, 0xe3, 0xa1, 0x48, + 0xd8, 0x89, 0xff, 0xf5, 0xd3, 0x95, 0xd7, 0x4d, 0x41, 0x94, 0x2d, 0x8d, 0x44, 0x2f, 0xaa, 0x6c, + 0x4a, 0x6d, 0x7c, 0x42, 0xf6, 0x98, 0xe3, 0xe3, 0x77, 0xab, 0xa1, 0xf3, 0x73, 0x35, 0x74, 0xc2, + 0x00, 0x9e, 0x1f, 0x1a, 0x24, 0xa6, 0xba, 0x94, 0x42, 0xd3, 0xd1, 0x47, 0x00, 0x8f, 0x66, 0x9a, + 0xb9, 0x1f, 0x00, 0x7c, 0xf0, 0xef, 0xb8, 0x4f, 0xd1, 0x7f, 0xec, 0x05, 0x1d, 0x6a, 0x30, 0x88, + 0x6e, 0xfc, 0xb4, 0x67, 0x9b, 0xbc, 0xfa, 0xb2, 0x09, 0xc0, 0x7a, 0x13, 0x80, 0x1f, 0x9b, 0x00, + 0xbc, 0xdf, 0x06, 0xce, 0x7a, 0x1b, 0x38, 0xdf, 0xb6, 0x81, 0xf3, 0x7a, 0xcc, 0xb8, 0x99, 0x57, + 0x19, 0x22, 0xb2, 0xe8, 0x76, 0x8a, 0xf7, 0xdd, 0xae, 0xfe, 0x9c, 0xdb, 0xf2, 0xef, 0x83, 0x33, + 0xb6, 0xa4, 0x3a, 0xbb, 0xdd, 0x7c, 0xe8, 0xe3, 0xdf, 0x01, 0x00, 0x00, 0xff, 0xff, 0x78, 0xcb, + 0x05, 0x85, 0xa1, 0x02, 0x00, 0x00, +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConn + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion4 + +// MsgClient is the client API for Msg service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type MsgClient interface { + AssignConsumerKey(ctx context.Context, in *MsgAssignConsumerKey, opts ...grpc.CallOption) (*MsgAssignConsumerKeyResponse, error) +} + +type msgClient struct { + cc grpc1.ClientConn +} + +func NewMsgClient(cc grpc1.ClientConn) MsgClient { + return &msgClient{cc} +} + +func (c *msgClient) AssignConsumerKey(ctx context.Context, in *MsgAssignConsumerKey, opts ...grpc.CallOption) (*MsgAssignConsumerKeyResponse, error) { + out := new(MsgAssignConsumerKeyResponse) + err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Msg/AssignConsumerKey", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// MsgServer is the server API for Msg service. +type MsgServer interface { + AssignConsumerKey(context.Context, *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) +} + +// UnimplementedMsgServer can be embedded to have forward compatible implementations. +type UnimplementedMsgServer struct { +} + +func (*UnimplementedMsgServer) AssignConsumerKey(ctx context.Context, req *MsgAssignConsumerKey) (*MsgAssignConsumerKeyResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method AssignConsumerKey not implemented") +} + +func RegisterMsgServer(s grpc1.Server, srv MsgServer) { + s.RegisterService(&_Msg_serviceDesc, srv) +} + +func _Msg_AssignConsumerKey_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(MsgAssignConsumerKey) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(MsgServer).AssignConsumerKey(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/interchain_security.ccv.provider.v1.Msg/AssignConsumerKey", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(MsgServer).AssignConsumerKey(ctx, req.(*MsgAssignConsumerKey)) + } + return interceptor(ctx, in, info, handler) +} + +var _Msg_serviceDesc = grpc.ServiceDesc{ + ServiceName: "interchain_security.ccv.provider.v1.Msg", + HandlerType: (*MsgServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "AssignConsumerKey", + Handler: _Msg_AssignConsumerKey_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "interchain_security/ccv/provider/v1/tx.proto", +} + +func (m *MsgAssignConsumerKey) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAssignConsumerKey) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAssignConsumerKey) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + if m.ConsumerKey != nil { + { + size, err := m.ConsumerKey.MarshalToSizedBuffer(dAtA[:i]) + if err != nil { + return 0, err + } + i -= size + i = encodeVarintTx(dAtA, i, uint64(size)) + } + i-- + dAtA[i] = 0x1a + } + if len(m.ProviderAddr) > 0 { + i -= len(m.ProviderAddr) + copy(dAtA[i:], m.ProviderAddr) + i = encodeVarintTx(dAtA, i, uint64(len(m.ProviderAddr))) + i-- + dAtA[i] = 0x12 + } + if len(m.ChainId) > 0 { + i -= len(m.ChainId) + copy(dAtA[i:], m.ChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.ChainId))) + i-- + dAtA[i] = 0xa + } + return len(dAtA) - i, nil +} + +func (m *MsgAssignConsumerKeyResponse) Marshal() (dAtA []byte, err error) { + size := m.Size() + dAtA = make([]byte, size) + n, err := m.MarshalToSizedBuffer(dAtA[:size]) + if err != nil { + return nil, err + } + return dAtA[:n], nil +} + +func (m *MsgAssignConsumerKeyResponse) MarshalTo(dAtA []byte) (int, error) { + size := m.Size() + return m.MarshalToSizedBuffer(dAtA[:size]) +} + +func (m *MsgAssignConsumerKeyResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) { + i := len(dAtA) + _ = i + var l int + _ = l + return len(dAtA) - i, nil +} + +func encodeVarintTx(dAtA []byte, offset int, v uint64) int { + offset -= sovTx(v) + base := offset + for v >= 1<<7 { + dAtA[offset] = uint8(v&0x7f | 0x80) + v >>= 7 + offset++ + } + dAtA[offset] = uint8(v) + return base +} +func (m *MsgAssignConsumerKey) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + l = len(m.ChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + l = len(m.ProviderAddr) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } + if m.ConsumerKey != nil { + l = m.ConsumerKey.Size() + n += 1 + l + sovTx(uint64(l)) + } + return n +} + +func (m *MsgAssignConsumerKeyResponse) Size() (n int) { + if m == nil { + return 0 + } + var l int + _ = l + return n +} + +func sovTx(x uint64) (n int) { + return (math_bits.Len64(x|1) + 6) / 7 +} +func sozTx(x uint64) (n int) { + return sovTx(uint64((x << 1) ^ uint64((int64(x) >> 63)))) +} +func (m *MsgAssignConsumerKey) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAssignConsumerKey: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAssignConsumerKey: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + case 1: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 2: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddr", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.ProviderAddr = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex + case 3: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field ConsumerKey", wireType) + } + var msglen int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + msglen |= int(b&0x7F) << shift + if b < 0x80 { + break + } + } + if msglen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + msglen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + if m.ConsumerKey == nil { + m.ConsumerKey = &types.Any{} + } + if err := m.ConsumerKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil { + return err + } + iNdEx = postIndex + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func (m *MsgAssignConsumerKeyResponse) Unmarshal(dAtA []byte) error { + l := len(dAtA) + iNdEx := 0 + for iNdEx < l { + preIndex := iNdEx + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + fieldNum := int32(wire >> 3) + wireType := int(wire & 0x7) + if wireType == 4 { + return fmt.Errorf("proto: MsgAssignConsumerKeyResponse: wiretype end group for non-group") + } + if fieldNum <= 0 { + return fmt.Errorf("proto: MsgAssignConsumerKeyResponse: illegal tag %d (wire type %d)", fieldNum, wire) + } + switch fieldNum { + default: + iNdEx = preIndex + skippy, err := skipTx(dAtA[iNdEx:]) + if err != nil { + return err + } + if (skippy < 0) || (iNdEx+skippy) < 0 { + return ErrInvalidLengthTx + } + if (iNdEx + skippy) > l { + return io.ErrUnexpectedEOF + } + iNdEx += skippy + } + } + + if iNdEx > l { + return io.ErrUnexpectedEOF + } + return nil +} +func skipTx(dAtA []byte) (n int, err error) { + l := len(dAtA) + iNdEx := 0 + depth := 0 + for iNdEx < l { + var wire uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + wire |= (uint64(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + wireType := int(wire & 0x7) + switch wireType { + case 0: + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + iNdEx++ + if dAtA[iNdEx-1] < 0x80 { + break + } + } + case 1: + iNdEx += 8 + case 2: + var length int + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return 0, ErrIntOverflowTx + } + if iNdEx >= l { + return 0, io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + length |= (int(b) & 0x7F) << shift + if b < 0x80 { + break + } + } + if length < 0 { + return 0, ErrInvalidLengthTx + } + iNdEx += length + case 3: + depth++ + case 4: + if depth == 0 { + return 0, ErrUnexpectedEndOfGroupTx + } + depth-- + case 5: + iNdEx += 4 + default: + return 0, fmt.Errorf("proto: illegal wireType %d", wireType) + } + if iNdEx < 0 { + return 0, ErrInvalidLengthTx + } + if depth == 0 { + return iNdEx, nil + } + } + return 0, io.ErrUnexpectedEOF +} + +var ( + ErrInvalidLengthTx = fmt.Errorf("proto: negative length found during unmarshaling") + ErrIntOverflowTx = fmt.Errorf("proto: integer overflow") + ErrUnexpectedEndOfGroupTx = fmt.Errorf("proto: unexpected end of group") +) diff --git a/x/ccv/types/events.go b/x/ccv/types/events.go index d99efba77e..12409e4f6a 100644 --- a/x/ccv/types/events.go +++ b/x/ccv/types/events.go @@ -7,6 +7,7 @@ const ( EventTypeChannelEstablished = "channel_established" EventTypeFeeTransferChannelOpened = "fee_transfer_channel_opened" EventTypeConsumerClientCreated = "consumer_client_created" + EventTypeAssignConsumerKey = "assign_consumer_key" EventTypeExecuteConsumerChainSlash = "execute_consumer_chain_slash" EventTypeFeeDistribution = "fee_distribution" @@ -17,17 +18,20 @@ const ( AttributeKeyAck = "acknowledgement" AttributeKeyAckError = "error" - AttributeChainID = "chain_id" - AttributeValidatorAddress = "validator_address" - AttributeInfractionType = "infraction_type" - AttributeInfractionHeight = "infraction_height" - AttributeConsumerHeight = "consumer_height" - AttributeValSetUpdateID = "valset_update_id" - AttributeTimestamp = "timestamp" - AttributeInitialHeight = "initial_height" - AttributeInitializationTimeout = "initialization_timeout" - AttributeTrustingPeriod = "trusting_period" - AttributeUnbondingPeriod = "unbonding_period" + AttributeChainID = "chain_id" + AttributeValidatorAddress = "validator_address" + AttributeValidatorConsumerAddress = "validator_consumer_address" + AttributeInfractionType = "infraction_type" + AttributeInfractionHeight = "infraction_height" + AttributeConsumerHeight = "consumer_height" + AttributeValSetUpdateID = "valset_update_id" + AttributeTimestamp = "timestamp" + AttributeInitialHeight = "initial_height" + AttributeInitializationTimeout = "initialization_timeout" + AttributeTrustingPeriod = "trusting_period" + AttributeUnbondingPeriod = "unbonding_period" + AttributeProviderValidatorAddress = "provider_validator_address" + AttributeConsumerConsensusPubKey = "consumer_consensus_pub_key" AttributeDistributionCurrentHeight = "current_distribution_height" AttributeDistributionNextHeight = "next_distribution_height" diff --git a/x/ccv/types/expected_keepers.go b/x/ccv/types/expected_keepers.go index e792fd2c7d..a127c31727 100644 --- a/x/ccv/types/expected_keepers.go +++ b/x/ccv/types/expected_keepers.go @@ -25,6 +25,7 @@ type StakingKeeper interface { UnbondingCanComplete(ctx sdk.Context, id uint64) error UnbondingTime(ctx sdk.Context) time.Duration GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator stakingtypes.Validator, found bool) + GetLastValidatorPower(ctx sdk.Context, operator sdk.ValAddress) (power int64) // slash the validator and delegators of the validator, specifying offence height, offence power, and slash fraction Jail(sdk.Context, sdk.ConsAddress) // jail a validator Slash(sdk.Context, sdk.ConsAddress, int64, int64, sdk.Dec, stakingtypes.InfractionType) diff --git a/x/ccv/utils/utils.go b/x/ccv/utils/utils.go index 8cfd01220c..9cac156662 100644 --- a/x/ccv/utils/utils.go +++ b/x/ccv/utils/utils.go @@ -11,6 +11,7 @@ import ( host "github.com/cosmos/ibc-go/v3/modules/core/24-host" ccv "github.com/cosmos/interchain-security/x/ccv/types" abci "github.com/tendermint/tendermint/abci/types" + tmprotocrypto "github.com/tendermint/tendermint/proto/tendermint/crypto" ) func AccumulateChanges(currentChanges, newChanges []abci.ValidatorUpdate) []abci.ValidatorUpdate { @@ -41,6 +42,14 @@ func GetChangePubKeyAddress(change abci.ValidatorUpdate) (addr []byte) { return pk.Address() } +func TMCryptoPublicKeyToConsAddr(k tmprotocrypto.PublicKey) sdk.ConsAddress { + sdkK, err := cryptocodec.FromTmProtoPublicKey(k) + if err != nil { + panic("could not get public key from tm proto public key") + } + return sdk.GetConsAddress(sdkK) +} + // SendIBCPacket sends an IBC packet with packetData // over the source channelID and portID func SendIBCPacket( @@ -75,5 +84,6 @@ func SendIBCPacket( channel.Counterparty.PortId, channel.Counterparty.ChannelId, clienttypes.Height{}, uint64(ctx.BlockTime().Add(timeoutPeriod).UnixNano()), ) + return channelKeeper.SendPacket(ctx, channelCap, packet) }