Skip to content

Commit

Permalink
feat!: introduce MsgOptIn and MsgOptOut (#1620)
Browse files Browse the repository at this point in the history
* init commit

* cleaning up

* changed cons to val address

* Revert "changed cons to val address"

This reverts commit a32e882.

* Update x/ccv/provider/keeper/keeper.go

Co-authored-by: Simon Noetzlin <simon.ntz@gmail.com>

* took into account comments

* added key assignment

* add contraint such that opt out only works if the chain is running

---------

Co-authored-by: insumity <karolos@informal.systems>
Co-authored-by: Simon Noetzlin <simon.ntz@gmail.com>
  • Loading branch information
3 people committed Mar 12, 2024
1 parent 1f1d3bd commit 6693dd3
Show file tree
Hide file tree
Showing 14 changed files with 1,717 additions and 90 deletions.
28 changes: 28 additions & 0 deletions proto/interchain_security/ccv/provider/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ service Msg {
rpc AssignConsumerKey(MsgAssignConsumerKey) returns (MsgAssignConsumerKeyResponse);
rpc SubmitConsumerMisbehaviour(MsgSubmitConsumerMisbehaviour) returns (MsgSubmitConsumerMisbehaviourResponse);
rpc SubmitConsumerDoubleVoting(MsgSubmitConsumerDoubleVoting) returns (MsgSubmitConsumerDoubleVotingResponse);
rpc OptIn(MsgOptIn) returns (MsgOptInResponse);
rpc OptOut(MsgOptOut) returns (MsgOptOutResponse);
}

message MsgAssignConsumerKey {
Expand Down Expand Up @@ -61,3 +63,29 @@ message MsgSubmitConsumerDoubleVoting {
}

message MsgSubmitConsumerDoubleVotingResponse {}

message MsgOptIn {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// the chain id of the consumer chain to opt in to
string chain_id = 1;
// the validator address on the provider
string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ];
// (optional) the consensus public key to use on the consumer in json string format corresponding to proto-any,
// for example `{"@type":"/cosmos.crypto.ed25519.PubKey","key":"Ui5Gf1+mtWUdH8u3xlmzdKID+F3PK0sfXZ73GZ6q6is="}`
// we can set `consumer_key = ""` if we do not consider the `consumer_key`
string consumer_key = 3;
}

message MsgOptInResponse {}

message MsgOptOut {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;
// the chain id of the consumer chain to opt out from
string chain_id = 1;
// the validator address on the provider
string provider_addr = 2 [ (gogoproto.moretags) = "yaml:\"address\"" ];
}

message MsgOptOutResponse {}
87 changes: 87 additions & 0 deletions x/ccv/provider/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ func GetTxCmd() *cobra.Command {
cmd.AddCommand(NewAssignConsumerKeyCmd())
cmd.AddCommand(NewSubmitConsumerMisbehaviourCmd())
cmd.AddCommand(NewSubmitConsumerDoubleVotingCmd())
cmd.AddCommand(NewOptInCmd())
cmd.AddCommand(NewOptOutCmd())

return cmd
}
Expand Down Expand Up @@ -202,3 +204,88 @@ Example:

return cmd
}

func NewOptInCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "opt-in [consumer-chain-id] [consumer-pubkey]",
Short: "opts in validator to the consumer chain, and if given uses the " +
"provided consensus public key for this consumer chain",
Args: cobra.RangeArgs(1, 2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if err != nil {
return err
}
txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)

providerValAddr := clientCtx.GetFromAddress()

var consumerPubKey string
if len(args) == 2 {
// consumer public key was provided
consumerPubKey = args[1]
} else {
consumerPubKey = ""
}
msg, err := types.NewMsgOptIn(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
}

func NewOptOutCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "opt-out [consumer-chain-id]",
Short: "opts out validator from this consumer chain",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

txf, err := tx.NewFactoryCLI(clientCtx, cmd.Flags())
if err != nil {
return err
}
txf = txf.WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)

providerValAddr := clientCtx.GetFromAddress()

msg, err := types.NewMsgOptOut(args[0], sdk.ValAddress(providerValAddr))
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
}
141 changes: 140 additions & 1 deletion x/ccv/provider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1160,7 +1160,7 @@ func (k Keeper) DeleteTopN(
store.Delete(types.TopNKey(chainID))
}

// GetTopN returns (N, true) if chain `chainID` has a top N associated, and (0, false) otherwise.
// GetTopN returns (N, true) if chain `chainID` has a top N associated, and (0, false) otherwise.
func (k Keeper) GetTopN(
ctx sdk.Context,
chainID string,
Expand All @@ -1184,3 +1184,142 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool {
topN, found := k.GetTopN(ctx, chainID)
return !found || topN == 0
}

func (k Keeper) SetOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
blockHeight uint64,
) {
store := ctx.KVStore(k.storeKey)

// validator is considered opted in
blockHeightBytes := make([]byte, 8)
binary.BigEndian.PutUint64(blockHeightBytes, blockHeight)

store.Set(types.OptedInKey(chainID, providerAddr), blockHeightBytes)
}

func (k Keeper) DeleteOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.OptedInKey(chainID, providerAddr))
}

func (k Keeper) IsOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.OptedInKey(chainID, providerAddr)) != nil
}

func (k Keeper) GetOptedIn(
ctx sdk.Context,
chainID string) (optedInValidators []OptedInValidator) {
store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
optedInValidators = append(optedInValidators, OptedInValidator{
ProviderAddr: types.NewProviderConsAddress(iterator.Key()[len(key):]),
BlockHeight: binary.BigEndian.Uint64(iterator.Value()),
})
}

return optedInValidators
}

func (k Keeper) SetToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Set(types.ToBeOptedInKey(chainID, providerAddr), []byte{})
}

func (k Keeper) DeleteToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ToBeOptedInKey(chainID, providerAddr))
}

func (k Keeper) IsToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil
}

func (k Keeper) GetToBeOptedIn(
ctx sdk.Context,
chainID string) (addresses []types.ProviderConsAddress) {

store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.ToBeOptedInBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):])
addresses = append(addresses, providerAddr)
}

return addresses
}

func (k Keeper) SetToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Set(types.ToBeOptedOutKey(chainID, providerAddr), []byte{})
}

func (k Keeper) DeleteToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ToBeOptedOutKey(chainID, providerAddr))
}

func (k Keeper) IsToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil
}

func (k Keeper) GetToBeOptedOut(
ctx sdk.Context,
chainID string) (addresses []types.ProviderConsAddress) {

store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.ToBeOptedOutBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):])
addresses = append(addresses, providerAddr)
}

return addresses
}
Loading

0 comments on commit 6693dd3

Please sign in to comment.