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

fix: partially revert key assignment type safety PR #980

Merged
merged 12 commits into from
May 26, 2023
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Some PRs from v2.0.0 may reappear from other releases below. This is due to the

## PRs included in v2.0.0

* (fix) partially revert key assignment type safety PR [#980](https://github.com/cosmos/interchain-security/pull/980)
* (fix) Remove panics on failure to send IBC packets [#876](https://github.com/cosmos/interchain-security/pull/876)
* (fix) consumer key prefix order to avoid complex migrations [#963](https://github.com/cosmos/interchain-security/pull/963)
* (fix) Prevent denom DOS [#931](https://github.com/cosmos/interchain-security/pull/931)
Expand Down
38 changes: 11 additions & 27 deletions proto/interchain_security/ccv/provider/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ message GlobalSlashEntry {
// This field is used to obtain validator power in HandleThrottleQueues.
//
// This field is not used in the store key, but is persisted in value bytes, see QueueGlobalSlashEntry.
ProviderConsAddress provider_val_cons_addr = 4;
bytes provider_val_cons_addr = 4;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See diff between this branch and ICS v1.0.0, for the proto/interchain_security/ccv/provider/v1/genesis.proto and proto/interchain_security/ccv/provider/v1/provider.proto files

}

// Params defines the parameters for CCV Provider module
Expand Down Expand Up @@ -166,6 +166,11 @@ message ConsumerRemovalProposals {
repeated ConsumerRemovalProposal pending = 1;
}

// AddressList contains a list of consensus addresses
message AddressList {
repeated bytes addresses = 1;
}

message ChannelToChain {
string channel_id = 1;
string chain_id = 2;
Expand Down Expand Up @@ -200,29 +205,8 @@ message VscSendTimestamp {
// Key assignment section
//

// A validator's assigned consensus address for a consumer chain.
// Note this type is for type safety within provider code, consumer code uses normal sdk.ConsAddress,
// since there's no notion of provider vs consumer address.
message ConsumerConsAddress {
// Do not generate stringer for this type, we'll use sdk.ConsAddress.String() instead
option (gogoproto.goproto_stringer) = false;
bytes address = 1;
}

// A validator's consensus address on the provider chain
message ProviderConsAddress {
// Do not generate stringer for this type, we'll use sdk.ConsAddress.String() instead
option (gogoproto.goproto_stringer) = false;
bytes address = 1;
}

// ConsumerAddressList contains a list of consumer consensus addresses
message ConsumerAddressList {
repeated ConsumerConsAddress addresses = 1;
}

message KeyAssignmentReplacement {
ProviderConsAddress provider_addr = 1;
bytes provider_addr = 1;
tendermint.crypto.PublicKey prev_c_key = 2;
int64 power = 3;
}
Expand All @@ -231,22 +215,22 @@ message KeyAssignmentReplacement {
// ValidatorConsumerPubKey: (chainID, providerAddr consAddr) -> consumerKey tmprotocrypto.PublicKey
message ValidatorConsumerPubKey {
string chain_id = 1;
ProviderConsAddress provider_addr = 2;
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;
ConsumerConsAddress consumer_addr = 2;
ProviderConsAddress provider_addr = 3;
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;
ConsumerAddressList consumer_addrs = 3;
AddressList consumer_addrs = 3;
}
4 changes: 2 additions & 2 deletions tests/integration/stop_consumer.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func (s *CCVTestSuite) TestStopConsumerChain() {
func(suite *CCVTestSuite) error {
// Queue slash and vsc packet data for consumer 0, these queue entries will be removed
firstBundle := s.getFirstBundle()
globalEntry := types.NewGlobalSlashEntry(s.providerCtx().BlockTime(), firstBundle.Chain.ChainID, 7, types.ProviderConsAddress{})
globalEntry := types.NewGlobalSlashEntry(s.providerCtx().BlockTime(), firstBundle.Chain.ChainID, 7, types.ProviderConsAddress{Address: []byte{}})
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CRUD tests panic if you try to persist a nil byte array type. So I had to add this here. Previously Address was a different type that didn't need to be populated

providerKeeper.QueueGlobalSlashEntry(s.providerCtx(), globalEntry)
err := providerKeeper.QueueThrottledSlashPacketData(s.providerCtx(), firstBundle.Chain.ChainID, 1,
ccv.SlashPacketData{ValsetUpdateId: 1})
Expand All @@ -94,7 +94,7 @@ func (s *CCVTestSuite) TestStopConsumerChain() {

// Queue slash and vsc packet data for consumer 1, these queue entries will be not be removed
secondBundle := s.getBundleByIdx(1)
globalEntry = types.NewGlobalSlashEntry(s.providerCtx().BlockTime(), secondBundle.Chain.ChainID, 7, types.ProviderConsAddress{})
globalEntry = types.NewGlobalSlashEntry(s.providerCtx().BlockTime(), secondBundle.Chain.ChainID, 7, types.ProviderConsAddress{Address: []byte{}})
providerKeeper.QueueGlobalSlashEntry(s.providerCtx(), globalEntry)
err = providerKeeper.QueueThrottledSlashPacketData(s.providerCtx(), secondBundle.Chain.ChainID, 1,
ccv.SlashPacketData{ValsetUpdateId: 1})
Expand Down
10 changes: 7 additions & 3 deletions x/ccv/provider/keeper/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,16 +73,20 @@ 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)
providerAddr := types.NewProviderConsAddress(item.ProviderAddr)
k.SetValidatorConsumerPubKey(ctx, item.ChainId, providerAddr, *item.ConsumerKey)
}

for _, item := range genState.ValidatorsByConsumerAddr {
k.SetValidatorByConsumerAddr(ctx, item.ChainId, *item.ConsumerAddr, *item.ProviderAddr)
consumerAddr := types.NewConsumerConsAddress(item.ConsumerAddr)
providerAddr := types.NewProviderConsAddress(item.ProviderAddr)
k.SetValidatorByConsumerAddr(ctx, item.ChainId, consumerAddr, providerAddr)
}

for _, item := range genState.ConsumerAddrsToPrune {
for _, addr := range item.ConsumerAddrs.Addresses {
k.AppendConsumerAddrsToPrune(ctx, item.ChainId, item.VscId, *addr)
consumerAddr := types.NewConsumerConsAddress(addr)
k.AppendConsumerAddrsToPrune(ctx, item.ChainId, item.VscId, consumerAddr)
}
}

Expand Down
10 changes: 5 additions & 5 deletions x/ccv/provider/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,22 +79,22 @@ func TestInitAndExportGenesis(t *testing.T) {
[]providertypes.ValidatorConsumerPubKey{
{
ChainId: cChainIDs[0],
ProviderAddr: &provAddr,
ProviderAddr: provAddr.ToSdkConsAddr(),
ConsumerKey: &consumerTmPubKey,
},
},
[]providertypes.ValidatorByConsumerAddr{
{
ChainId: cChainIDs[0],
ProviderAddr: &provAddr,
ConsumerAddr: &consumerConsAddr,
ProviderAddr: provAddr.ToSdkConsAddr(),
ConsumerAddr: consumerConsAddr.ToSdkConsAddr(),
},
},
[]providertypes.ConsumerAddrsToPrune{
{
ChainId: cChainIDs[0],
VscId: vscID,
ConsumerAddrs: &providertypes.ConsumerAddressList{Addresses: []*providertypes.ConsumerConsAddress{&consumerConsAddr}},
ConsumerAddrs: &providertypes.AddressList{Addresses: [][]byte{consumerConsAddr.ToSdkConsAddr()}},
},
},
)
Expand Down Expand Up @@ -155,7 +155,7 @@ func TestInitAndExportGenesis(t *testing.T) {

addrs := pk.GetConsumerAddrsToPrune(ctx, cChainIDs[0], vscID)
// Expect same list as what was provided in provGenesis
expectedAddrList := providertypes.ConsumerAddressList{Addresses: []*providertypes.ConsumerConsAddress{&consumerConsAddr}}
expectedAddrList := providertypes.AddressList{Addresses: [][]byte{consumerConsAddr.ToSdkConsAddr()}}
require.Equal(t, expectedAddrList, addrs)

// check provider chain's consumer chain states
Expand Down
7 changes: 4 additions & 3 deletions x/ccv/provider/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func ValidatorConsensusKeyInUse(k *Keeper, ctx sdk.Context, valAddr sdk.ValAddre
inUse := false

for _, validatorConsumerAddrs := range k.GetAllValidatorsByConsumerAddr(ctx, nil) {
if validatorConsumerAddrs.ConsumerAddr.ToSdkConsAddr().Equals(consensusAddr) {
if sdk.ConsAddress(validatorConsumerAddrs.ConsumerAddr).Equals(consensusAddr) {
inUse = true
break
}
Expand All @@ -103,15 +103,16 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {

func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, valConsAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
for _, validatorConsumerPubKey := range h.k.GetAllValidatorConsumerPubKeys(ctx, nil) {
if validatorConsumerPubKey.ProviderAddr.ToSdkConsAddr().Equals(valConsAddr) {
if sdk.ConsAddress(validatorConsumerPubKey.ProviderAddr).Equals(valConsAddr) {
consumerAddrTmp, err := ccvtypes.TMCryptoPublicKeyToConsAddr(*validatorConsumerPubKey.ConsumerKey)
if err != nil {
// An error here would indicate something is very wrong
panic("cannot get address of consumer key")
}
consumerAddr := providertypes.NewConsumerConsAddress(consumerAddrTmp)
h.k.DeleteValidatorByConsumerAddr(ctx, validatorConsumerPubKey.ChainId, consumerAddr)
h.k.DeleteValidatorConsumerPubKey(ctx, validatorConsumerPubKey.ChainId, *validatorConsumerPubKey.ProviderAddr)
providerAddr := providertypes.NewProviderConsAddress(validatorConsumerPubKey.ProviderAddr)
h.k.DeleteValidatorConsumerPubKey(ctx, validatorConsumerPubKey.ChainId, providerAddr)
}
}
}
Expand Down
58 changes: 24 additions & 34 deletions x/ccv/provider/keeper/key_assignment.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (k Keeper) GetAllValidatorConsumerPubKeys(ctx sdk.Context, chainID *string)

validatorConsumerPubKeys = append(validatorConsumerPubKeys, types.ValidatorConsumerPubKey{
ChainId: chainID,
ProviderAddr: &providerAddr,
ProviderAddr: providerAddr.ToSdkConsAddr(),
ConsumerKey: &consumerKey,
})
}
Expand All @@ -116,12 +116,7 @@ func (k Keeper) GetValidatorByConsumerAddr(
if bz == nil {
return providerAddr, false
}
err := providerAddr.Unmarshal(bz)
if err != nil {
// An error here would indicate something is very wrong,
// the provider address is assumed to be correctly serialized in SetValidatorByConsumerAddr.
panic(fmt.Sprintf("failed to unmarshal provider address: %v", err))
}
providerAddr = types.NewProviderConsAddress(bz)
return providerAddr, true
}

Expand All @@ -135,11 +130,7 @@ func (k Keeper) SetValidatorByConsumerAddr(
) {
store := ctx.KVStore(k.storeKey)
// Cons address is a type alias for a byte string, no marshaling needed
bz, err := providerAddr.Marshal()
if err != nil {
// An error here would indicate something is very wrong,
panic(fmt.Sprintf("failed to marshal provider address: %v", err))
}
bz := providerAddr.ToSdkConsAddr()
store.Set(types.ValidatorsByConsumerAddrKey(chainID, consumerAddr), bz)
}

Expand Down Expand Up @@ -173,17 +164,11 @@ func (k Keeper) GetAllValidatorsByConsumerAddr(ctx sdk.Context, chainID *string)
panic(fmt.Sprintf("failed to parse chainID and consumer address: %v", err))
}
consumerAddr := types.NewConsumerConsAddress(consumerAddrTmp)
var providerAddr types.ProviderConsAddress
err = providerAddr.Unmarshal(iterator.Value())
if err != nil {
// An error here would indicate something is very wrong,
// the provider address is assumed to be correctly serialized in SetValidatorByConsumerAddr.
panic(fmt.Sprintf("failed to unmarshal provider address: %v", err))
}
providerAddr := types.NewProviderConsAddress(iterator.Value())

validatorConsumerAddrs = append(validatorConsumerAddrs, types.ValidatorByConsumerAddr{
ConsumerAddr: &consumerAddr,
ProviderAddr: &providerAddr,
ConsumerAddr: consumerAddr.ToSdkConsAddr(),
ProviderAddr: providerAddr.ToSdkConsAddr(),
ChainId: chainID,
})
}
Expand Down Expand Up @@ -274,7 +259,7 @@ func (k Keeper) GetAllKeyAssignmentReplacements(ctx sdk.Context, chainID string)
}

replacements = append(replacements, types.KeyAssignmentReplacement{
ProviderAddr: &providerAddr,
ProviderAddr: providerAddr.ToSdkConsAddr(),
PrevCKey: &pubKeyAndPower.PubKey,
Power: pubKeyAndPower.Power,
})
Expand Down Expand Up @@ -302,7 +287,7 @@ func (k Keeper) DeleteKeyAssignmentReplacement(ctx sdk.Context, chainID string,
func (k Keeper) AppendConsumerAddrsToPrune(ctx sdk.Context, chainID string, vscID uint64, consumerAddr types.ConsumerConsAddress) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.ConsumerAddrsToPruneKey(chainID, vscID))
var consumerAddrsToPrune types.ConsumerAddressList
var consumerAddrsToPrune types.AddressList
if bz != nil {
err := consumerAddrsToPrune.Unmarshal(bz)
if err != nil {
Expand All @@ -311,7 +296,7 @@ func (k Keeper) AppendConsumerAddrsToPrune(ctx sdk.Context, chainID string, vscI
panic(err)
}
}
consumerAddrsToPrune.Addresses = append(consumerAddrsToPrune.Addresses, &consumerAddr)
consumerAddrsToPrune.Addresses = append(consumerAddrsToPrune.Addresses, consumerAddr.ToSdkConsAddr())
bz, err := consumerAddrsToPrune.Marshal()
if err != nil {
// An error here would indicate something is very wrong,
Expand All @@ -327,7 +312,7 @@ func (k Keeper) GetConsumerAddrsToPrune(
ctx sdk.Context,
chainID string,
vscID uint64,
) (consumerAddrsToPrune types.ConsumerAddressList) {
) (consumerAddrsToPrune types.AddressList) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.ConsumerAddrsToPruneKey(chainID, vscID))
if bz == nil {
Expand Down Expand Up @@ -359,7 +344,7 @@ func (k Keeper) GetAllConsumerAddrsToPrune(ctx sdk.Context, chainID string) (con
// store keys are assumed to be correctly serialized in AppendConsumerAddrsToPrune.
panic(err)
}
var addrs types.ConsumerAddressList
var addrs types.AddressList
err = addrs.Unmarshal(iterator.Value())
if err != nil {
// An error here would indicate something is very wrong,
Expand Down Expand Up @@ -564,13 +549,14 @@ func (k Keeper) MustApplyKeyAssignmentToValUpdates(
// 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) {
k.DeleteKeyAssignmentReplacement(ctx, chainID, *replacement.ProviderAddr)
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, *replacement.ProviderAddr)
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.
Expand Down Expand Up @@ -605,11 +591,12 @@ func (k Keeper) GetProviderAddrFromConsumerAddr(
// 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)
for _, addrBz := range consumerAddrs.Addresses {
consumerAddr := types.NewConsumerConsAddress(addrBz)
k.DeleteValidatorByConsumerAddr(ctx, chainID, consumerAddr)
k.Logger(ctx).Info("consumer address was pruned",
"consumer chainID", chainID,
"consumer consensus addr", addr.String(),
"consumer consensus addr", consumerAddr.String(),
)
}

Expand All @@ -620,17 +607,20 @@ func (k Keeper) PruneKeyAssignments(ctx sdk.Context, chainID string, vscID uint6
func (k Keeper) DeleteKeyAssignments(ctx sdk.Context, chainID string) {
// delete ValidatorConsumerPubKey
for _, validatorConsumerAddr := range k.GetAllValidatorConsumerPubKeys(ctx, &chainID) {
k.DeleteValidatorConsumerPubKey(ctx, chainID, *validatorConsumerAddr.ProviderAddr)
providerAddr := types.NewProviderConsAddress(validatorConsumerAddr.ProviderAddr)
k.DeleteValidatorConsumerPubKey(ctx, chainID, providerAddr)
}

// delete ValidatorsByConsumerAddr
for _, validatorConsumerAddr := range k.GetAllValidatorsByConsumerAddr(ctx, &chainID) {
k.DeleteValidatorByConsumerAddr(ctx, chainID, *validatorConsumerAddr.ConsumerAddr)
consumerAddr := types.NewConsumerConsAddress(validatorConsumerAddr.ConsumerAddr)
k.DeleteValidatorByConsumerAddr(ctx, chainID, consumerAddr)
}

// delete KeyAssignmentReplacements
for _, keyAssignmentReplacement := range k.GetAllKeyAssignmentReplacements(ctx, chainID) {
k.DeleteKeyAssignmentReplacement(ctx, chainID, *keyAssignmentReplacement.ProviderAddr)
providerAddr := types.NewProviderConsAddress(keyAssignmentReplacement.ProviderAddr)
k.DeleteKeyAssignmentReplacement(ctx, chainID, providerAddr)
}

// delete ValidatorConsumerPubKey
Expand Down
Loading