Skip to content

Commit 7b03c56

Browse files
authored
feat!: remove functionality that stops validators to opt-in on multiple chains with same chain ID (#2249)
* refactor: move opt-in methods to partial_set_security.go * refactor: move methods to power-shaping.go * refactor: move ComputeNextValidators to validator_set_update.go * handle error in test * remove ProviderConsAddrToOptedInConsumerIds index * make ComputeNextValidators return error * remove logger from GetLastBondedValidatorsUtil
1 parent 0600f7f commit 7b03c56

23 files changed

+1260
-1455
lines changed

tests/mbt/driver/setup.go

+3-2
Original file line numberDiff line numberDiff line change
@@ -377,8 +377,9 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC
377377
stakingValidators = append(stakingValidators, v)
378378
}
379379

380-
considerAll := func(providerAddr providertypes.ProviderConsAddress) bool { return true }
381-
nextValidators := s.providerKeeper().FilterValidators(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll)
380+
considerAll := func(providerAddr providertypes.ProviderConsAddress) (bool, error) { return true, nil }
381+
nextValidators, err := s.providerKeeper().FilterValidators(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll)
382+
require.NoError(s.t, err)
382383
err = s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators)
383384
require.NoError(s.t, err)
384385

testutil/ibc_testing/generic_setup.go

-2
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,6 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp](
176176
for _, v := range lastVals {
177177
consAddr, _ := v.GetConsAddr()
178178
providerKeeper.SetOptedIn(providerChain.GetContext(), consumerId, providertypes.NewProviderConsAddress(consAddr))
179-
err = providerKeeper.AppendOptedInConsumerId(providerChain.GetContext(), providertypes.NewProviderConsAddress(consAddr), consumerId)
180-
s.Require().NoError(err)
181179
}
182180

183181
// commit the state on the provider chain

x/ccv/consumer/keeper/keeper.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -720,5 +720,5 @@ func (k Keeper) GetLastBondedValidators(ctx sdk.Context) ([]stakingtypes.Validat
720720
if err != nil {
721721
return nil, err
722722
}
723-
return ccv.GetLastBondedValidatorsUtil(ctx, k.standaloneStakingKeeper, k.Logger(ctx), maxVals)
723+
return ccv.GetLastBondedValidatorsUtil(ctx, k.standaloneStakingKeeper, maxVals)
724724
}

x/ccv/provider/keeper/consumer_lifecycle.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -335,10 +335,13 @@ func (k Keeper) MakeConsumerGenesis(
335335
}
336336

337337
// need to use the bondedValidators, not activeValidators, here since the chain might be opt-in and allow inactive vals
338-
nextValidators := k.ComputeNextValidators(ctx, consumerId, bondedValidators, powerShapingParameters, minPower)
338+
nextValidators, err := k.ComputeNextValidators(ctx, consumerId, bondedValidators, powerShapingParameters, minPower)
339+
if err != nil {
340+
return gen, nil, fmt.Errorf("unable to compute the next validators in MakeConsumerGenesis, consumerId(%s): %w", consumerId, err)
341+
}
339342
err = k.SetConsumerValSet(ctx, consumerId, nextValidators)
340343
if err != nil {
341-
return gen, nil, fmt.Errorf("unable to set consumer validator set in MakeConsumerGenesis: %s", err)
344+
return gen, nil, fmt.Errorf("unable to set consumer validator set in MakeConsumerGenesis, consumerId(%s): %w", consumerId, err)
342345
}
343346

344347
// get the initial updates with the latest set consumer public keys

x/ccv/provider/keeper/distribution_test.go

+47
Original file line numberDiff line numberDiff line change
@@ -330,3 +330,50 @@ func TestChangeRewardDenoms(t *testing.T) {
330330
attributes = keeper.ChangeRewardDenoms(ctx, denomsToAdd, denomsToRemove)
331331
require.Len(t, attributes, 0) // No attributes should be returned since the denom is not registered
332332
}
333+
334+
func TestHandleSetConsumerCommissionRate(t *testing.T) {
335+
providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
336+
defer ctrl.Finish()
337+
338+
providerAddr := providertypes.NewProviderConsAddress([]byte("providerAddr"))
339+
340+
// trying to set a commission rate to a unknown consumer chain
341+
require.Error(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, "unknownChainID", providerAddr, math.LegacyZeroDec()))
342+
343+
// setup a pending consumer chain
344+
consumerId := "0"
345+
providerKeeper.FetchAndIncrementConsumerId(ctx)
346+
providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_INITIALIZED)
347+
348+
// check that there's no commission rate set for the validator yet
349+
_, found := providerKeeper.GetConsumerCommissionRate(ctx, consumerId, providerAddr)
350+
require.False(t, found)
351+
352+
mocks.MockStakingKeeper.EXPECT().MinCommissionRate(ctx).Return(math.LegacyZeroDec(), nil).Times(1)
353+
require.NoError(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, consumerId, providerAddr, math.LegacyOneDec()))
354+
355+
// check that the commission rate is now set
356+
cr, found := providerKeeper.GetConsumerCommissionRate(ctx, consumerId, providerAddr)
357+
require.Equal(t, math.LegacyOneDec(), cr)
358+
require.True(t, found)
359+
360+
// set minimum rate of 1/2
361+
commissionRate := math.LegacyNewDec(1).Quo(math.LegacyNewDec(2))
362+
mocks.MockStakingKeeper.EXPECT().MinCommissionRate(ctx).Return(commissionRate, nil).AnyTimes()
363+
364+
// try to set a rate slightly below the minimum
365+
require.Error(t, providerKeeper.HandleSetConsumerCommissionRate(
366+
ctx,
367+
consumerId,
368+
providerAddr,
369+
commissionRate.Sub(math.LegacyNewDec(1).Quo(math.LegacyNewDec(100)))), // 0.5 - 0.01
370+
"commission rate should be rejected (below min), but is not",
371+
)
372+
373+
// set a valid commission equal to the minimum
374+
require.NoError(t, providerKeeper.HandleSetConsumerCommissionRate(ctx, consumerId, providerAddr, commissionRate))
375+
// check that the rate was set
376+
cr, found = providerKeeper.GetConsumerCommissionRate(ctx, consumerId, providerAddr)
377+
require.Equal(t, commissionRate, cr)
378+
require.True(t, found)
379+
}

x/ccv/provider/keeper/grpc_query.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,10 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
348348
}
349349
}
350350

351-
consumerValSet = k.ComputeNextValidators(ctx, consumerId, bondedValidators, powerShapingParameters, minPower)
351+
consumerValSet, err = k.ComputeNextValidators(ctx, consumerId, bondedValidators, powerShapingParameters, minPower)
352+
if err != nil {
353+
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to compute the next validators for chain %s: %s", consumerId, err))
354+
}
352355

353356
// sort the address of the validators by ascending lexical order as they were persisted to the store
354357
sort.Slice(consumerValSet, func(i, j int) bool {
@@ -476,7 +479,10 @@ func (k Keeper) hasToValidate(
476479
if err != nil {
477480
return false, err
478481
}
479-
nextValidators := k.ComputeNextValidators(ctx, consumerId, lastVals, powerShapingParameters, minPowerToOptIn)
482+
nextValidators, err := k.ComputeNextValidators(ctx, consumerId, lastVals, powerShapingParameters, minPowerToOptIn)
483+
if err != nil {
484+
return false, err
485+
}
480486
for _, v := range nextValidators {
481487
consAddr := sdk.ConsAddress(v.ProviderConsAddr)
482488
if provAddr.ToSdkConsAddr().Equals(consAddr) {

x/ccv/provider/keeper/keeper.go

-63
Original file line numberDiff line numberDiff line change
@@ -735,69 +735,6 @@ func (k Keeper) GetAllActiveConsumerIds(ctx sdk.Context) []string {
735735
return consumerIds
736736
}
737737

738-
func (k Keeper) SetOptedIn(
739-
ctx sdk.Context,
740-
consumerId string,
741-
providerConsAddress types.ProviderConsAddress,
742-
) {
743-
store := ctx.KVStore(k.storeKey)
744-
store.Set(types.OptedInKey(consumerId, providerConsAddress), []byte{})
745-
}
746-
747-
func (k Keeper) DeleteOptedIn(
748-
ctx sdk.Context,
749-
consumerId string,
750-
providerAddr types.ProviderConsAddress,
751-
) {
752-
store := ctx.KVStore(k.storeKey)
753-
store.Delete(types.OptedInKey(consumerId, providerAddr))
754-
}
755-
756-
func (k Keeper) IsOptedIn(
757-
ctx sdk.Context,
758-
consumerId string,
759-
providerAddr types.ProviderConsAddress,
760-
) bool {
761-
store := ctx.KVStore(k.storeKey)
762-
return store.Get(types.OptedInKey(consumerId, providerAddr)) != nil
763-
}
764-
765-
// GetAllOptedIn returns all the opted-in validators on chain `consumerId`
766-
func (k Keeper) GetAllOptedIn(
767-
ctx sdk.Context,
768-
consumerId string,
769-
) (providerConsAddresses []types.ProviderConsAddress) {
770-
store := ctx.KVStore(k.storeKey)
771-
key := types.StringIdWithLenKey(types.OptedInKeyPrefix(), consumerId)
772-
iterator := storetypes.KVStorePrefixIterator(store, key)
773-
defer iterator.Close()
774-
775-
for ; iterator.Valid(); iterator.Next() {
776-
providerConsAddresses = append(providerConsAddresses, types.NewProviderConsAddress(iterator.Key()[len(key):]))
777-
}
778-
779-
return providerConsAddresses
780-
}
781-
782-
// DeleteAllOptedIn deletes all the opted-in validators for chain with `consumerId`
783-
func (k Keeper) DeleteAllOptedIn(
784-
ctx sdk.Context,
785-
consumerId string,
786-
) {
787-
store := ctx.KVStore(k.storeKey)
788-
key := types.StringIdWithLenKey(types.OptedInKeyPrefix(), consumerId)
789-
iterator := storetypes.KVStorePrefixIterator(store, key)
790-
791-
var keysToDel [][]byte
792-
defer iterator.Close()
793-
for ; iterator.Valid(); iterator.Next() {
794-
keysToDel = append(keysToDel, iterator.Key())
795-
}
796-
for _, delKey := range keysToDel {
797-
store.Delete(delKey)
798-
}
799-
}
800-
801738
// SetConsumerCommissionRate sets a per-consumer chain commission rate
802739
// for the given validator address
803740
func (k Keeper) SetConsumerCommissionRate(

x/ccv/provider/keeper/keeper_test.go

-51
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package keeper_test
22

33
import (
4-
"bytes"
54
"fmt"
65
"sort"
76
"testing"
@@ -293,56 +292,6 @@ func TestSetSlashLog(t *testing.T) {
293292
require.False(t, providerKeeper.GetSlashLog(ctx, addrWithoutDoubleSigns))
294293
}
295294

296-
func TestGetAllOptedIn(t *testing.T) {
297-
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
298-
defer ctrl.Finish()
299-
300-
expectedOptedInValidators := []providertypes.ProviderConsAddress{
301-
providertypes.NewProviderConsAddress([]byte("providerAddr1")),
302-
providertypes.NewProviderConsAddress([]byte("providerAddr2")),
303-
providertypes.NewProviderConsAddress([]byte("providerAddr3")),
304-
}
305-
306-
for _, expectedOptedInValidator := range expectedOptedInValidators {
307-
providerKeeper.SetOptedIn(ctx, CONSUMER_ID, expectedOptedInValidator)
308-
}
309-
310-
actualOptedInValidators := providerKeeper.GetAllOptedIn(ctx, CONSUMER_ID)
311-
312-
// sort validators first to be able to compare
313-
sortOptedInValidators := func(addresses []providertypes.ProviderConsAddress) {
314-
sort.Slice(addresses, func(i, j int) bool {
315-
return bytes.Compare(addresses[i].ToSdkConsAddr(), addresses[j].ToSdkConsAddr()) < 0
316-
})
317-
}
318-
sortOptedInValidators(expectedOptedInValidators)
319-
sortOptedInValidators(actualOptedInValidators)
320-
require.Equal(t, expectedOptedInValidators, actualOptedInValidators)
321-
}
322-
323-
// TestOptedIn tests the `SetOptedIn`, `IsOptedIn`, `DeleteOptedIn` and `DeleteAllOptedIn` methods
324-
func TestOptedIn(t *testing.T) {
325-
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
326-
defer ctrl.Finish()
327-
328-
optedInValidator1 := providertypes.NewProviderConsAddress([]byte("providerAddr1"))
329-
optedInValidator2 := providertypes.NewProviderConsAddress([]byte("providerAddr2"))
330-
331-
require.False(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator1))
332-
providerKeeper.SetOptedIn(ctx, CONSUMER_ID, optedInValidator1)
333-
require.True(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator1))
334-
providerKeeper.DeleteOptedIn(ctx, CONSUMER_ID, optedInValidator1)
335-
require.False(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator1))
336-
337-
providerKeeper.SetOptedIn(ctx, CONSUMER_ID, optedInValidator1)
338-
providerKeeper.SetOptedIn(ctx, CONSUMER_ID, optedInValidator2)
339-
require.True(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator1))
340-
require.True(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator2))
341-
providerKeeper.DeleteAllOptedIn(ctx, CONSUMER_ID)
342-
require.False(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator1))
343-
require.False(t, providerKeeper.IsOptedIn(ctx, CONSUMER_ID, optedInValidator2))
344-
}
345-
346295
// TestConsumerCommissionRate tests the `SetConsumerCommissionRate`, `GetConsumerCommissionRate`, and `DeleteConsumerCommissionRate` methods
347296
func TestConsumerCommissionRate(t *testing.T) {
348297
providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))

x/ccv/provider/keeper/key_assignment_test.go

+7-6
Original file line numberDiff line numberDiff line change
@@ -788,14 +788,15 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) {
788788
})
789789
}
790790

791-
nextValidators := k.FilterValidators(ctx, CONSUMERID, bondedValidators,
792-
func(providerAddr types.ProviderConsAddress) bool {
793-
return true
791+
nextValidators, err := k.FilterValidators(ctx, CONSUMERID, bondedValidators,
792+
func(providerAddr types.ProviderConsAddress) (bool, error) {
793+
return true, nil
794794
})
795-
valSet, error := k.GetConsumerValSet(ctx, CONSUMERID)
796-
require.NoError(t, error)
795+
require.NoError(t, err)
796+
valSet, err := k.GetConsumerValSet(ctx, CONSUMERID)
797+
require.NoError(t, err)
797798
updates = providerkeeper.DiffValidators(valSet, nextValidators)
798-
err := k.SetConsumerValSet(ctx, CONSUMERID, nextValidators)
799+
err = k.SetConsumerValSet(ctx, CONSUMERID, nextValidators)
799800
require.NoError(t, err)
800801

801802
consumerValset.apply(updates)

x/ccv/provider/keeper/msg_server_test.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
package keeper_test
22

33
import (
4-
"github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
54
"testing"
65
"time"
76

7+
"github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
8+
89
"github.com/stretchr/testify/require"
910

1011
"github.com/cosmos/cosmos-sdk/codec/address"
@@ -242,6 +243,7 @@ func TestUpdateConsumer(t *testing.T) {
242243
InitializationParameters: &expectedInitializationParameters,
243244
PowerShapingParameters: nil,
244245
})
246+
require.NoError(t, err)
245247
// assert the chain is not scheduled to launch
246248
consumerIds, err = providerKeeper.GetConsumersToBeLaunched(ctx, previousSpawnTime)
247249
require.NoError(t, err)

0 commit comments

Comments
 (0)