Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat! use protos to serialize opted-in validators #1659

Merged
merged 1 commit into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions proto/interchain_security/ccv/provider/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -313,3 +313,16 @@ message ConsumerRewardsAllocation {
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins"
];
}

// OptedInValidator is used to store a opted-in validator
// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator
message OptedInValidator {
// validator address
bytes provider_addr = 1;
// block height at which the validator opted-in
int64 block_height = 2;
// validator voting power at the block it opted-in
int64 power = 3;
// public key used by the validator on the consumer
bytes public_key = 4;
}
9 changes: 6 additions & 3 deletions x/ccv/provider/keeper/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) {
keeper.SetOptedIn(
ctx,
chainID,
types.NewProviderConsAddress(sdk.ConsAddress(val.Address)),
0,
types.OptedInValidator{
ProviderAddr: val.Address,
BlockHeight: ctx.BlockHeight(),
Power: val.VotingPower,
PublicKey: val.PubKey.Bytes(),
},
)

validatorsVotes = append(
Expand All @@ -65,7 +69,6 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) {
}

func TestIdentifyConsumerChainIDFromIBCPacket(t *testing.T) {

var (
chainID = "consumer"
ccvChannel = "channel-0"
Expand Down
38 changes: 21 additions & 17 deletions x/ccv/provider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1189,16 +1189,15 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool {
func (k Keeper) SetOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
blockHeight uint64,
validator types.OptedInValidator,
) {
store := ctx.KVStore(k.storeKey)
bz, err := validator.Marshal()
if err != nil {
panic(fmt.Errorf("failed to marshal OptedInValidator: %w", err))
}

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

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

func (k Keeper) DeleteOptedIn(
Expand All @@ -1207,7 +1206,7 @@ func (k Keeper) DeleteOptedIn(
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.OptedInKey(chainID, providerAddr))
store.Delete(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr()))
}

func (k Keeper) IsOptedIn(
Expand All @@ -1216,22 +1215,25 @@ func (k Keeper) IsOptedIn(
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.OptedInKey(chainID, providerAddr)) != nil
return store.Get(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) != nil
}

func (k Keeper) GetOptedIn(
// GetAllOptedIn returns all the opted-in validators on chain `chainID`
func (k Keeper) GetAllOptedIn(
ctx sdk.Context,
chainID string) (optedInValidators []OptedInValidator) {
chainID string) (optedInValidators []types.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()),
})
iterator.Value()
var optedInValidator types.OptedInValidator
if err := optedInValidator.Unmarshal(iterator.Value()); err != nil {
panic(fmt.Errorf("failed to unmarshal OptedInValidator: %w", err))
}
optedInValidators = append(optedInValidators, optedInValidator)
}

return optedInValidators
Expand Down Expand Up @@ -1264,7 +1266,8 @@ func (k Keeper) IsToBeOptedIn(
return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil
}

func (k Keeper) GetToBeOptedIn(
// GetAllToBeOptedIn returns all the to-be-opted-in validators on chain `chainID`
func (k Keeper) GetAllToBeOptedIn(
ctx sdk.Context,
chainID string) (addresses []types.ProviderConsAddress) {

Expand Down Expand Up @@ -1308,7 +1311,8 @@ func (k Keeper) IsToBeOptedOut(
return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil
}

func (k Keeper) GetToBeOptedOut(
// GetAllToBeOptedOut returns all the to-be-opted-out validators on chain `chainID`
func (k Keeper) GetAllToBeOptedOut(
ctx sdk.Context,
chainID string) (addresses []types.ProviderConsAddress) {

Expand Down
56 changes: 33 additions & 23 deletions x/ccv/provider/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package keeper_test
import (
"bytes"
"fmt"
"github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper"
"sort"
"testing"
"time"
Expand Down Expand Up @@ -662,39 +661,49 @@ func TestTopN(t *testing.T) {
}
}

func TestGetOptedIn(t *testing.T) {
func TestGetAllOptedIn(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

expectedOptedInValidators := []keeper.OptedInValidator{
expectedOptedInValidators := []types.OptedInValidator{
{
ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr1")),
ProviderAddr: []byte("providerAddr1"),
BlockHeight: 1,
Power: 2,
PublicKey: []byte{3},
},
{
ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr2")),
ProviderAddr: []byte("providerAddr2"),
BlockHeight: 2,
Power: 3,
PublicKey: []byte{4},
},
{
ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr3")),
ProviderAddr: []byte("providerAddr3"),
BlockHeight: 3,
Power: 4,
PublicKey: []byte{5},
},
}

for _, expectedOptedInValidator := range expectedOptedInValidators {
providerKeeper.SetOptedIn(ctx, "chainID",
expectedOptedInValidator.ProviderAddr, expectedOptedInValidator.BlockHeight)
types.OptedInValidator{
ProviderAddr: expectedOptedInValidator.ProviderAddr,
BlockHeight: expectedOptedInValidator.BlockHeight,
Power: expectedOptedInValidator.Power,
PublicKey: expectedOptedInValidator.PublicKey})
}

actualOptedInValidators := providerKeeper.GetOptedIn(ctx, "chainID")
actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, "chainID")

// sort validators first to be able to compare
sortOptedInValidators := func(optedInValidators []keeper.OptedInValidator) {
sortOptedInValidators := func(optedInValidators []types.OptedInValidator) {
sort.Slice(optedInValidators, func(i int, j int) bool {
a := optedInValidators[i]
b := optedInValidators[j]
return a.BlockHeight < b.BlockHeight ||
(a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr.ToSdkConsAddr(), b.ProviderAddr.ToSdkConsAddr()) < 0)
(a.BlockHeight == b.BlockHeight && bytes.Compare(a.ProviderAddr, b.ProviderAddr) < 0)
})
}
sortOptedInValidators(expectedOptedInValidators)
Expand All @@ -707,19 +716,20 @@ func TestOptedIn(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

optedInValidator := keeper.OptedInValidator{
ProviderAddr: types.NewProviderConsAddress([]byte("providerAddr")),
BlockHeight: 1,
optedInValidator := types.OptedInValidator{ProviderAddr: []byte("providerAddr"),
BlockHeight: 1,
Power: 2,
PublicKey: []byte{3},
}

require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr))
providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator.ProviderAddr, optedInValidator.BlockHeight)
require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr))
providerKeeper.DeleteOptedIn(ctx, "chainID", optedInValidator.ProviderAddr)
require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", optedInValidator.ProviderAddr))
require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr)))
providerKeeper.SetOptedIn(ctx, "chainID", optedInValidator)
require.True(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr)))
providerKeeper.DeleteOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr))
require.False(t, providerKeeper.IsOptedIn(ctx, "chainID", types.NewProviderConsAddress(optedInValidator.ProviderAddr)))
}

func TestGetToBeOptedIn(t *testing.T) {
func TestGetAllToBeOptedIn(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

Expand All @@ -732,7 +742,7 @@ func TestGetToBeOptedIn(t *testing.T) {
providerKeeper.SetToBeOptedIn(ctx, "chainID", addr)
}

actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID")
actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID")

// sort addresses first to be able to compare
sortAddresses := func(addresses []types.ProviderConsAddress) {
Expand Down Expand Up @@ -766,7 +776,7 @@ func TestBeOptedIn(t *testing.T) {
providerKeeper.SetToBeOptedIn(ctx, "chainID", addr)
}

actualAddresses := providerKeeper.GetToBeOptedIn(ctx, "chainID")
actualAddresses := providerKeeper.GetAllToBeOptedIn(ctx, "chainID")

// sort addresses first to be able to compare
sortAddresses := func(addresses []types.ProviderConsAddress) {
Expand Down Expand Up @@ -801,7 +811,7 @@ func TestToBeOptedIn(t *testing.T) {
require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr))
}

func TestGetToBeOptedOut(t *testing.T) {
func TestGetAllToBeOptedOut(t *testing.T) {
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

Expand All @@ -814,7 +824,7 @@ func TestGetToBeOptedOut(t *testing.T) {
providerKeeper.SetToBeOptedOut(ctx, "chainID", addr)
}

actualAddresses := providerKeeper.GetToBeOptedOut(ctx, "chainID")
actualAddresses := providerKeeper.GetAllToBeOptedOut(ctx, "chainID")

// sort addresses first to be able to compare
sortAddresses := func(addresses []types.ProviderConsAddress) {
Expand Down
4 changes: 3 additions & 1 deletion x/ccv/provider/keeper/key_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -502,7 +502,6 @@ func (k Keeper) AssignConsumerKey(
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
Expand Down Expand Up @@ -568,10 +567,13 @@ func (k Keeper) MustApplyKeyAssignmentToValUpdates(
// - and setting the new consumer key's power to the power in the update
prevConsumerKey, _, found := k.GetKeyAssignmentReplacement(ctx, chainID, providerAddr)
if found {
//if isOptedIn(providerAddr) && !isToBeOptedOut(providerAddr) {
// only generate a removal (i.e., power 0) if the validator was previously opted in
newUpdates = append(newUpdates, abci.ValidatorUpdate{
PubKey: prevConsumerKey,
Power: 0,
})
//}

newConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr)
if !found {
Expand Down
6 changes: 0 additions & 6 deletions x/ccv/provider/keeper/partial_set_security.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,6 @@ import (
"github.com/cosmos/interchain-security/v4/x/ccv/provider/types"
)

type OptedInValidator struct {
ProviderAddr types.ProviderConsAddress
// block height the validator opted in at
BlockHeight uint64
}

func (k Keeper) HandleOptIn(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress, consumerKey *string) error {
if !k.IsConsumerProposedOrRegistered(ctx, chainID) {
return errorsmod.Wrapf(
Expand Down
7 changes: 5 additions & 2 deletions x/ccv/provider/keeper/partial_set_security_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package keeper_test

import (
"testing"

codectypes "github.com/cosmos/cosmos-sdk/codec/types"
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -10,7 +12,6 @@ import (
ccvtypes "github.com/cosmos/interchain-security/v4/x/ccv/types"
"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
"testing"
)

func TestHandleOptIn(t *testing.T) {
Expand All @@ -32,7 +33,9 @@ func TestHandleOptIn(t *testing.T) {
require.False(t, providerKeeper.IsToBeOptedOut(ctx, "chainID", providerAddr))

// if validator (`providerAddr`) is already opted in, then the validator cannot be opted in
providerKeeper.SetOptedIn(ctx, "chainID", providerAddr, 1)

providerKeeper.SetOptedIn(ctx, "chainID",
types.OptedInValidator{ProviderAddr: providerAddr.ToSdkConsAddr(), BlockHeight: 1, Power: 1, PublicKey: []byte{1}})
providerKeeper.HandleOptIn(ctx, "chainID", providerAddr, nil)
require.False(t, providerKeeper.IsToBeOptedIn(ctx, "chainID", providerAddr))
}
Expand Down
4 changes: 2 additions & 2 deletions x/ccv/provider/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -542,9 +542,9 @@ func TopNKey(chainID string) []byte {
}

// OptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr`
func OptedInKey(chainID string, providerAddr ProviderConsAddress) []byte {
func OptedInKey(chainID string, providerAddr []byte) []byte {
prefix := ChainIdWithLenKey(OptedInBytePrefix, chainID)
return append(prefix, providerAddr.ToSdkConsAddr().Bytes()...)
return append(prefix, providerAddr...)
}

// ToBeOptedInKey returns the key of consumer chain `chainID` and validator with `providerAddr`
Expand Down
Loading
Loading