diff --git a/.changelog/unreleased/state-breaking/2866-migrate-signing-infos.md b/.changelog/unreleased/state-breaking/2866-migrate-signing-infos.md new file mode 100644 index 00000000000..58ac9f43e99 --- /dev/null +++ b/.changelog/unreleased/state-breaking/2866-migrate-signing-infos.md @@ -0,0 +1,5 @@ +Migrate the signing infos of validators for which the consensus address is missing. +([\#2866](https://github.com/cosmos/gaia/pull/2866)) + + + diff --git a/app/upgrades/v15/upgrades.go b/app/upgrades/v15/upgrades.go index b14797dfeda..f43437dcd85 100644 --- a/app/upgrades/v15/upgrades.go +++ b/app/upgrades/v15/upgrades.go @@ -3,12 +3,18 @@ package v15 import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + slashingkeeper "github.com/cosmos/cosmos-sdk/x/slashing/keeper" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper" upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" "github.com/cosmos/gaia/v15/app/keepers" ) +// CreateUpgradeHandler returns a upgrade handler for Gaia v15 +// which executes the following migrations: +// - update the slashing module SigningInfos for which the consensus address is empty, +// see https://github.com/cosmos/gaia/issues/1734. func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, @@ -22,6 +28,7 @@ func CreateUpgradeHandler( return vm, err } + UpgradeSigningInfos(ctx, keepers.SlashingKeeper) UpgradeMinCommissionRate(ctx, *keepers.StakingKeeper) ctx.Logger().Info("Upgrade v15 complete") @@ -29,6 +36,36 @@ func CreateUpgradeHandler( } } +// UpgradeSigningInfos updates the signing infos of validators for which +// the consensus address is missing +func UpgradeSigningInfos(ctx sdk.Context, sk slashingkeeper.Keeper) { + ctx.Logger().Info("Migrating signing infos...") + + signingInfos := []slashingtypes.ValidatorSigningInfo{} + + // update consensus address in signing info + // using the store key of validators + sk.IterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + if info.Address == "" { + info.Address = address.String() + signingInfos = append(signingInfos, info) + } + + return false + }) + + for _, si := range signingInfos { + addr, err := sdk.ConsAddressFromBech32(si.Address) + if err != nil { + ctx.Logger().Error("incorrect consensus address in signing info %s: %s", si.Address, err) + continue + } + sk.SetValidatorSigningInfo(ctx, addr, si) + } + + ctx.Logger().Info("Finished migrating signing infos") +} + // UpgradeMinCommissionRate sets the minimum commission rate staking parameter to 5% // and updates the commission rate for all validators that have a commission rate less than 5% // adhere to prop 826 which sets the minimum commission rate to 5% for all validators diff --git a/app/upgrades/v15/upgrades_test.go b/app/upgrades/v15/upgrades_test.go index b381be91009..3edb20ed87e 100644 --- a/app/upgrades/v15/upgrades_test.go +++ b/app/upgrades/v15/upgrades_test.go @@ -2,6 +2,7 @@ package v15_test import ( "testing" + "time" "github.com/stretchr/testify/require" @@ -9,13 +10,71 @@ import ( tmproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" + "github.com/cosmos/cosmos-sdk/testutil/mock" sdk "github.com/cosmos/cosmos-sdk/types" + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/gaia/v15/app/helpers" v15 "github.com/cosmos/gaia/v15/app/upgrades/v15" ) +func TestUpgradeSigningInfos(t *testing.T) { + gaiaApp := helpers.Setup(t) + ctx := gaiaApp.NewUncachedContext(true, tmproto.Header{}) + slashingKeeper := gaiaApp.SlashingKeeper + + signingInfosNum := 8 + emptyAddrSigningInfo := make(map[string]struct{}) + + // create some dummy signing infos, half of which with an empty address field + for i := 0; i < signingInfosNum; i++ { + pubKey, err := mock.NewPV().GetPubKey() + require.NoError(t, err) + + consAddr := sdk.ConsAddress(pubKey.Address()) + info := slashingtypes.NewValidatorSigningInfo( + consAddr, + 0, + 0, + time.Unix(0, 0), + false, + 0, + ) + + if i < signingInfosNum/2 { + info.Address = "" + emptyAddrSigningInfo[consAddr.String()] = struct{}{} + } + + slashingKeeper.SetValidatorSigningInfo(ctx, consAddr, info) + require.NoError(t, err) + } + + require.Equal(t, signingInfosNum/2, len(emptyAddrSigningInfo)) + + // check that signing info are correctly set before migration + slashingKeeper.IterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + if _, ok := emptyAddrSigningInfo[address.String()]; ok { + require.Empty(t, info.Address) + } else { + require.NotEmpty(t, info.Address) + } + + return false + }) + + // upgrade signing infos + v15.UpgradeSigningInfos(ctx, slashingKeeper) + + // check that all signing info are updated as expected after migration + slashingKeeper.IterateValidatorSigningInfos(ctx, func(address sdk.ConsAddress, info slashingtypes.ValidatorSigningInfo) (stop bool) { + require.NotEmpty(t, info.Address) + + return false + }) +} + func TestUpgradeMinCommissionRate(t *testing.T) { gaiaApp := helpers.Setup(t) ctx := gaiaApp.NewUncachedContext(true, tmproto.Header{})