diff --git a/docs/docs/adrs/adr-001-key-assignment.md b/docs/docs/adrs/adr-001-key-assignment.md index 874321db0c..36dbdfdb09 100644 --- a/docs/docs/adrs/adr-001-key-assignment.md +++ b/docs/docs/adrs/adr-001-key-assignment.md @@ -7,6 +7,7 @@ title: Key Assignment ## Changelog * 2022-12-01: Initial Draft +* 2024-03-01: Updated to take into account they key-assigment-replacement deprecation. ## Status @@ -30,10 +31,6 @@ ConsumerValidatorsBytePrefix | len(chainID) | chainID | providerConsAddress -> c ```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 @@ -67,20 +64,6 @@ if _, consumerRegistered := GetConsumerClientId(chainID); consumerRegistered { 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 @@ -129,89 +112,24 @@ func (k Keeper) MakeConsumerGenesis(chainID string) (gen consumertypes.GenesisSt } ``` -On `EndBlock` while queueing `VSCPacket`s to send to registered consumer chains: +Note that key assignment works hand-in-hand with [epochs](https://github.com/cosmos/interchain-security/blob/main/docs/docs/adrs/adr-014-epochs.md). +For each consumer chain, we store the consumer validator set that is currently (i.e., in this epoch) validating the consumer chain. +Specifically, for each validator in the set we store among others, the public key that it is using on the consumer chain during the current (i.e., ongoing) epoch. +At the end of every epoch, if there were validator set changes on the provider, then for every consumer chain, we construct a `VSCPacket` +with all the validator updates and add it to the list of `PendingVSCPacket`s. We compute the validator updates needed by a consumer chain by +comparing the stored list of consumer validators with the current bonded validators on the provider, with something similar to this: ```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 -} +// get the valset that has been validating the consumer chain during this epoch +currentValidators := GetConsumerValSet(consumerChain) +// generate the validator updates needed to be sent through a `VSCPacket` by comparing the current validators +// in the epoch with the latest bonded validators +valUpdates := DiffValidators(currentValidators, stakingmodule.GetBondedValidators()) +// update the current validators set for the upcoming epoch to be the latest bonded validators instead +SetConsumerValSet(stakingmodule.GetBondedValidators()) ``` +where `DiffValidators` internally checks if the consumer public key for a validator has changed since the last +epoch and if so generates a validator update. This way, a validator can change its consumer public key for a consumer +chain an arbitrary amount of times and only the last set consumer public key would be taken into account. On receiving a `SlashPacket` from a consumer chain with id `chainID` for a infraction of a validator `data.Validator`: ```golang diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index dc901712ff..ff3df99763 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -252,7 +252,6 @@ func TestProviderStateIsCleanedAfterConsumerChainIsStopped(t *testing.T, ctx sdk // test key assignment state is cleaned require.Empty(t, providerKeeper.GetAllValidatorConsumerPubKeys(ctx, &expectedChainID)) require.Empty(t, providerKeeper.GetAllValidatorsByConsumerAddr(ctx, &expectedChainID)) - require.Empty(t, providerKeeper.GetAllKeyAssignmentReplacements(ctx, expectedChainID)) require.Empty(t, providerKeeper.GetAllConsumerAddrsToPrune(ctx, expectedChainID)) } diff --git a/x/ccv/consumer/types/keys.go b/x/ccv/consumer/types/keys.go index 0292ca84c5..20163f5ed9 100644 --- a/x/ccv/consumer/types/keys.go +++ b/x/ccv/consumer/types/keys.go @@ -51,7 +51,7 @@ const ( // received over CCV channel but not yet flushed over ABCI PendingChangesByteKey - // NOTE: This prefix is depreciated, but left in place to avoid consumer state migrations + // NOTE: This prefix is deprecated, but left in place to avoid consumer state migrations // [DEPRECATED] PendingDataPacketsByteKey @@ -61,7 +61,7 @@ const ( // InitialValSetByteKey is the byte to store the initial validator set for a consumer InitialValSetByteKey - // NOTE: This prefix is depreciated, but left in place to avoid consumer state migrations + // NOTE: This prefix is deprecated, but left in place to avoid consumer state migrations // [DEPRECATED] LastStandaloneHeightByteKey diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go index dfe0a73895..e3273d1fb5 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -23,7 +23,6 @@ func TestQueryAllPairsValConAddrByConsumerChainID(t *testing.T) { defer ctrl.Finish() pk.SetValidatorConsumerPubKey(ctx, chainID, providerAddr, consumerKey) - pk.SetKeyAssignmentReplacement(ctx, chainID, providerAddr, consumerKey, 100) consumerPubKey, found := pk.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) require.True(t, found, "consumer pubkey not found") diff --git a/x/ccv/provider/keeper/key_assignment.go b/x/ccv/provider/keeper/key_assignment.go index c54d922f0f..89dbcfda4e 100644 --- a/x/ccv/provider/keeper/key_assignment.go +++ b/x/ccv/provider/keeper/key_assignment.go @@ -8,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" - abci "github.com/cometbft/cometbft/abci/types" tmprotocrypto "github.com/cometbft/cometbft/proto/tendermint/crypto" "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" @@ -184,99 +183,6 @@ func (k Keeper) DeleteValidatorByConsumerAddr(ctx sdk.Context, chainID string, c 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 types.ProviderConsAddress, -) (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 { - // An error here would indicate something is very wrong, - // the public key and power are assumed to be correctly serialized in SetKeyAssignmentReplacement. - panic(fmt.Sprintf("failed to unmarshal public key and power: %v", 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 types.ProviderConsAddress, - prevCKey tmprotocrypto.PublicKey, - power int64, -) { - store := ctx.KVStore(k.storeKey) - pubKeyAndPower := abci.ValidatorUpdate{PubKey: prevCKey, Power: power} - bz, err := pubKeyAndPower.Marshal() - if err != nil { - // An error here would indicate something is very wrong, - // prevCKey is obtained from GetValidatorConsumerPubKey (called from AssignConsumerKey), - // and power is obtained from GetLastValidatorPower (called from AssignConsumerKey). - // Both of which are assumed to return valid values. - panic(fmt.Sprintf("failed to marshal public key and power: %v", err)) - } - store.Set(types.KeyAssignmentReplacementsKey(chainID, providerAddr), bz) -} - -// GetAllKeyAssignmentReplacements gets all pairs of previous assigned consumer keys -// and current powers for all provider validator for which key assignments were received in this block. -// -// Note that the pairs are stored under keys with the following format: -// KeyAssignmentReplacementsBytePrefix | len(chainID) | chainID | providerAddress -// Thus, the iteration is in ascending order of providerAddresses. -func (k Keeper) GetAllKeyAssignmentReplacements(ctx sdk.Context, chainID string) (replacements []types.KeyAssignmentReplacement) { - store := ctx.KVStore(k.storeKey) - iteratorPrefix := types.ChainIdWithLenKey(types.KeyAssignmentReplacementsBytePrefix, chainID) - iterator := sdk.KVStorePrefixIterator(store, iteratorPrefix) - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - // TODO: store chainID and provider cons address in value bytes, marshaled as protobuf type - _, providerAddrTmp, err := types.ParseChainIdAndConsAddrKey(types.KeyAssignmentReplacementsBytePrefix, iterator.Key()) - if err != nil { - // An error here would indicate something is very wrong, - // store keys are assumed to be correctly serialized in SetKeyAssignmentReplacement. - panic(err) - } - providerAddr := types.NewProviderConsAddress(providerAddrTmp) - var pubKeyAndPower abci.ValidatorUpdate - err = pubKeyAndPower.Unmarshal(iterator.Value()) - if err != nil { - // An error here would indicate something is very wrong, - // the public key and power are assumed to be correctly serialized in SetKeyAssignmentReplacement. - panic(fmt.Sprintf("failed to unmarshal public key and power: %v", err)) - } - - replacements = append(replacements, types.KeyAssignmentReplacement{ - ProviderAddr: providerAddr.ToSdkConsAddr(), - PrevCKey: &pubKeyAndPower.PubKey, - Power: pubKeyAndPower.Power, - }) - } - - return replacements -} - -// 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 types.ProviderConsAddress) { - 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. // @@ -425,20 +331,20 @@ func (k Keeper) AssignConsumerKey( ) } - // 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 + // get the previous key assigned for this validator on this consumer chain + if oldConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr); found { + oldConsumerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(oldConsumerKey) + if err != nil { + return err + } + oldConsumerAddr := types.NewConsumerConsAddress(oldConsumerAddrTmp) + + // 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 { + // mark the old consumer address as prunable once the VSCMaturedPacket // for the current VSC ID is received; // note: this state is removed on receiving the VSCMaturedPacket - oldConsumerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(oldConsumerKey) - if err != nil { - return err - } - oldConsumerAddr := types.NewConsumerConsAddress(oldConsumerAddrTmp) k.AppendConsumerAddrsToPrune( ctx, chainID, @@ -446,42 +352,8 @@ func (k Keeper) AssignConsumerKey( oldConsumerAddr, ) } 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 { - oldConsumerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(oldConsumerKey) - if err != nil { - return err - } - oldConsumerAddr := types.NewConsumerConsAddress(oldConsumerAddrTmp) + // if the consumer chain is not registered, then remove the mapping + // from the old consumer address to the provider address k.DeleteValidatorByConsumerAddr(ctx, chainID, oldConsumerAddr) } } @@ -499,88 +371,6 @@ func (k Keeper) AssignConsumerKey( return nil } -// MustApplyKeyAssignmentToValUpdates applies the key assignment to the validator updates -// received from the staking module. -// The method panics if the key-assignment state is corrupted. -func (k Keeper) MustApplyKeyAssignmentToValUpdates( - ctx sdk.Context, - chainID string, - valUpdates []abci.ValidatorUpdate, -) (newUpdates []abci.ValidatorUpdate) { - for _, valUpdate := range valUpdates { - providerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(valUpdate.PubKey) - if err != nil { - panic(fmt.Errorf("cannot get provider address from pub key: %s", err.Error())) - } - providerAddr := types.NewProviderConsAddress(providerAddrTmp) - - // 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 { - // This should never happen as for every KeyAssignmentReplacement there should - // be a ValidatorConsumerPubKey that was stored when AssignConsumerKey() was called. - panic(fmt.Errorf("consumer key not found for provider addr %s stored in KeyAssignmentReplacement", 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 branch 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. - for _, replacement := range k.GetAllKeyAssignmentReplacements(ctx, chainID) { - providerAddr := types.NewProviderConsAddress(replacement.ProviderAddr) - k.DeleteKeyAssignmentReplacement(ctx, chainID, providerAddr) - newUpdates = append(newUpdates, abci.ValidatorUpdate{ - PubKey: *replacement.PrevCKey, - Power: 0, - }) - - newConsumerKey, found := k.GetValidatorConsumerPubKey(ctx, chainID, providerAddr) - if !found { - // This should never happen as for every KeyAssignmentReplacement there should - // be a ValidatorConsumerPubKey that was stored when AssignConsumerKey() was called. - panic(fmt.Errorf("consumer key not found for provider addr %s stored in KeyAssignmentReplacement", replacement.ProviderAddr)) - } - newUpdates = append(newUpdates, abci.ValidatorUpdate{ - PubKey: newConsumerKey, - Power: replacement.Power, - }) - } - - return newUpdates -} - // GetProviderAddrFromConsumerAddr returns the consensus address of a validator with // consAddr set as the consensus address on a consumer chain func (k Keeper) GetProviderAddrFromConsumerAddr( @@ -627,12 +417,6 @@ func (k Keeper) DeleteKeyAssignments(ctx sdk.Context, chainID string) { k.DeleteValidatorByConsumerAddr(ctx, chainID, consumerAddr) } - // delete KeyAssignmentReplacements - for _, keyAssignmentReplacement := range k.GetAllKeyAssignmentReplacements(ctx, chainID) { - providerAddr := types.NewProviderConsAddress(keyAssignmentReplacement.ProviderAddr) - k.DeleteKeyAssignmentReplacement(ctx, chainID, providerAddr) - } - // delete ValidatorConsumerPubKey for _, consumerAddrsToPrune := range k.GetAllConsumerAddrsToPrune(ctx, chainID) { k.DeleteConsumerAddrsToPrune(ctx, chainID, consumerAddrsToPrune.VscId) diff --git a/x/ccv/provider/keeper/key_assignment_test.go b/x/ccv/provider/keeper/key_assignment_test.go index 4fab08c981..7cb222a3be 100644 --- a/x/ccv/provider/keeper/key_assignment_test.go +++ b/x/ccv/provider/keeper/key_assignment_test.go @@ -2,6 +2,7 @@ package keeper_test import ( "bytes" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "math/rand" "sort" "testing" @@ -184,67 +185,6 @@ func TestGetAllValidatorsByConsumerAddr(t *testing.T) { require.Len(t, result, len(testAssignments)) } -func TestKeyAssignmentReplacementCRUD(t *testing.T) { - chainID := consumer - providerAddr := types.NewProviderConsAddress([]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 TestGetAllKeyAssignmentReplacements(t *testing.T) { - pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) - defer ctrl.Finish() - - chainID := "consumer-1" - - seed := time.Now().UnixNano() - rng := rand.New(rand.NewSource(seed)) - - numAssignments := 10 - testAssignments := []types.KeyAssignmentReplacement{} - for i := 0; i < numAssignments; i++ { - consumerKey := cryptotestutil.NewCryptoIdentityFromIntSeed(i).TMProtoCryptoPublicKey() - providerAddr := cryptotestutil.NewCryptoIdentityFromIntSeed(numAssignments + i).ProviderConsAddress() - testAssignments = append(testAssignments, - types.KeyAssignmentReplacement{ - ProviderAddr: providerAddr.ToSdkConsAddr(), - PrevCKey: &consumerKey, - Power: rng.Int63(), - }, - ) - } - expectedGetAllOrder := testAssignments - // sorting by KeyAssignmentReplacement.ProviderAddr - sort.Slice(expectedGetAllOrder, func(i, j int) bool { - return bytes.Compare(expectedGetAllOrder[i].ProviderAddr, expectedGetAllOrder[j].ProviderAddr) == -1 - }) - - firstTestAssignmentProviderAddr := types.NewProviderConsAddress(testAssignments[0].ProviderAddr) - pk.SetKeyAssignmentReplacement(ctx, "consumer-2", firstTestAssignmentProviderAddr, *testAssignments[0].PrevCKey, testAssignments[0].Power) - for _, assignment := range testAssignments { - providerAddr := types.NewProviderConsAddress(assignment.ProviderAddr) - pk.SetKeyAssignmentReplacement(ctx, chainID, providerAddr, *assignment.PrevCKey, assignment.Power) - } - - result := pk.GetAllKeyAssignmentReplacements(ctx, chainID) - require.Len(t, result, len(testAssignments)) - require.Equal(t, expectedGetAllOrder, result) -} - func TestConsumerAddrsToPruneCRUD(t *testing.T) { chainID := consumer consumerAddr := types.NewConsumerConsAddress([]byte("consumerAddr1")) @@ -420,9 +360,6 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, consumerIdentities[0].SDKValConsAddress(), ).Return(stakingtypes.Validator{}, false), - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( - ctx, providerIdentities[0].SDKValOpAddress(), - ).Return(int64(0)), ) }, doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { @@ -445,15 +382,9 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, consumerIdentities[0].SDKValConsAddress(), ).Return(stakingtypes.Validator{}, false), - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( - ctx, providerIdentities[0].SDKValOpAddress(), - ).Return(int64(0)), mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, consumerIdentities[1].SDKValConsAddress(), ).Return(stakingtypes.Validator{}, false), - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( - ctx, providerIdentities[0].SDKValOpAddress(), - ).Return(int64(0)), ) }, doActions: func(ctx sdk.Context, k providerkeeper.Keeper) { @@ -481,9 +412,6 @@ func TestAssignConsensusKeyForConsumerChain(t *testing.T) { mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, consumerIdentities[0].SDKValConsAddress(), ).Return(stakingtypes.Validator{}, false), - mocks.MockStakingKeeper.EXPECT().GetLastValidatorPower( - ctx, providerIdentities[0].SDKValOpAddress(), - ).Return(int64(0)), mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, consumerIdentities[0].SDKValConsAddress(), ).Return(stakingtypes.Validator{}, false), @@ -692,7 +620,6 @@ func (vs *ValSet) apply(updates []abci.ValidatorUpdate) { // 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, _ := ccvtypes.TMCryptoPublicKeyToConsAddr(u.PubKey) if id.SDKValConsAddress().Equals(cons) { vs.power[i] = u.Power @@ -828,7 +755,21 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { // and increment the provider vscid. applyUpdatesAndIncrementVSCID := func(updates []abci.ValidatorUpdate) { providerValset.apply(updates) - updates = k.MustApplyKeyAssignmentToValUpdates(ctx, CHAINID, updates) + + var bondedValidators []stakingtypes.Validator + for _, v := range providerValset.identities { + pkAny, _ := codectypes.NewAnyWithValue(v.ConsensusSDKPubKey()) + + bondedValidators = append(bondedValidators, stakingtypes.Validator{ + OperatorAddress: v.SDKValOpAddress().String(), + ConsensusPubkey: pkAny, + }) + } + + nextValidators := k.ComputeNextEpochConsumerValSet(ctx, CHAINID, bondedValidators) + updates = providerkeeper.DiffValidators(k.GetConsumerValSet(ctx, CHAINID), nextValidators) + k.SetConsumerValSet(ctx, CHAINID, nextValidators) + consumerValset.apply(updates) // Simulate the VSCID update in EndBlock k.IncrementValidatorSetUpdateId(ctx) @@ -844,10 +785,13 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { // The consumer chain has not yet been registered // Apply some randomly generated key assignments - applyAssignments(getAssignments()) + assignments := getAssignments() + applyAssignments(assignments) // And generate a random provider valset which, in the real system, will // be put into the consumer genesis. - applyUpdatesAndIncrementVSCID(getStakingUpdates()) + stakingUpdates := getStakingUpdates() + + applyUpdatesAndIncrementVSCID(stakingUpdates) // Register the consumer chain k.SetConsumerClientId(ctx, CHAINID, "") @@ -861,9 +805,12 @@ func TestSimulatedAssignmentsAndUpdateApplication(t *testing.T) { // and a random set of validator power updates for block := 0; block < NUM_BLOCKS_PER_EXECUTION; block++ { + stakingUpdates = getStakingUpdates() + assignments = getAssignments() + // Generate and apply assignments and power updates - applyAssignments(getAssignments()) - applyUpdatesAndIncrementVSCID(getStakingUpdates()) + applyAssignments(assignments) + applyUpdatesAndIncrementVSCID(stakingUpdates) // Randomly fast forward the greatest pruned VSCID. This simulates // delivery of maturity packets from the consumer chain. diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index 29e3486071..e9222ade98 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -120,7 +120,9 @@ const ( // 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 was the byte prefix used to store the key assignments that needed to be replaced in the current block + // NOTE: This prefix is deprecated, but left in place to avoid consumer state migrations + // [DEPRECATED] KeyAssignmentReplacementsBytePrefix // ConsumerAddrsToPruneBytePrefix is the byte prefix that will store the mapping from VSC ids @@ -365,12 +367,6 @@ func ValidatorsByConsumerAddrKey(chainID string, addr ConsumerConsAddress) []byt return ChainIdAndConsAddrKey(ValidatorsByConsumerAddrBytePrefix, chainID, addr.ToSdkConsAddr()) } -// 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 ProviderConsAddress) []byte { - return ChainIdAndConsAddrKey(KeyAssignmentReplacementsBytePrefix, chainID, addr.ToSdkConsAddr()) -} - // ConsumerAddrsToPruneKey returns the key under which the // mapping from VSC ids to consumer validators addresses is stored func ConsumerAddrsToPruneKey(chainID string, vscID uint64) []byte { diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 24178f6180..02faa9a640 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -97,7 +97,6 @@ func getAllFullyDefinedKeys() [][]byte { providertypes.GlobalSlashEntryKey(providertypes.GlobalSlashEntry{}), providertypes.ConsumerValidatorsKey("chainID", providertypes.NewProviderConsAddress([]byte{0x05})), providertypes.ValidatorsByConsumerAddrKey("chainID", providertypes.NewConsumerConsAddress([]byte{0x05})), - providertypes.KeyAssignmentReplacementsKey("chainID", providertypes.NewProviderConsAddress([]byte{0x05})), providertypes.ConsumerAddrsToPruneKey("chainID", 88), providertypes.SlashLogKey(providertypes.NewProviderConsAddress([]byte{0x05})), providertypes.VSCMaturedHandledThisBlockKey(),