x{stake,slash,gov,distrib} In-place Store Migrations (#8504)

* Add 1st version of migrate

* Put migration logic into Configurator

* add test to bank store migration

* add test for configurator

* Error if no migration found

* Remove RunMigrations from Configurator interface

* Update spec

* Rename folders

* copy-paste from keys.go

* Fix nil map

* rename function

* Update simapp/app.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Update simapp/app_test.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Adderss reviews

* Fix tests

* Update testutil/context.go

Co-authored-by: Robert Zaremba <robert@zaremba.ch>

* Update docs for ConsensusVersion

* Rename to forVersion

* Fix tests

* Check error early

* Return 1 for intiial version

* Use MigrationKeeper

* Fix test

* Revert adding marshaler to Configurator

* Godoc updates

* Update docs

* Add distrib legacy folder

* Add tests for distrib migration

* Add gov migrations

* Copy paste whole keys file

* Add gov migrations

* Add staking

* Fix staking tests

* Update spec and module.go

* Update to latest changes

* Update migration scripts

* capability to 1

* Fix tests

* Add package godoc

* Remove whitespace

* Remove global

* Use Migrator

* Remove 042 keys files

* Fix build

* Unlambda

* Rename to Migrate1to2

Co-authored-by: Robert Zaremba <robert@zaremba.ch>
This commit is contained in:
Amaury 2021-02-25 11:43:31 +01:00 committed by GitHub
parent eeb3eabdc6
commit ba74a7c737
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1588 additions and 115 deletions

View File

@ -11,8 +11,27 @@ import (
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
dbm "github.com/tendermint/tm-db" dbm "github.com/tendermint/tm-db"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module" "github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/vesting"
"github.com/cosmos/cosmos-sdk/x/authz"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
"github.com/cosmos/cosmos-sdk/x/capability"
"github.com/cosmos/cosmos-sdk/x/crisis"
"github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/evidence"
feegrant "github.com/cosmos/cosmos-sdk/x/feegrant"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
transfer "github.com/cosmos/cosmos-sdk/x/ibc/applications/transfer"
ibc "github.com/cosmos/cosmos-sdk/x/ibc/core"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/cosmos/cosmos-sdk/x/upgrade"
) )
func TestSimAppExportAndBlockedAddrs(t *testing.T) { func TestSimAppExportAndBlockedAddrs(t *testing.T) {
@ -52,11 +71,33 @@ func TestGetMaccPerms(t *testing.T) {
func TestRunMigrations(t *testing.T) { func TestRunMigrations(t *testing.T) {
db := dbm.NewMemDB() db := dbm.NewMemDB()
encCfg := MakeTestEncodingConfig() encCfg := MakeTestEncodingConfig()
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{}) logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, EmptyAppOptions{})
// Create a new configurator for the purpose of this test. // Create a new baseapp and configurator for the purpose of this test.
bApp := baseapp.NewBaseApp(appName, logger, db, encCfg.TxConfig.TxDecoder())
bApp.SetCommitMultiStoreTracer(nil)
bApp.SetInterfaceRegistry(encCfg.InterfaceRegistry)
app.BaseApp = bApp
app.configurator = module.NewConfigurator(app.MsgServiceRouter(), app.GRPCQueryRouter()) app.configurator = module.NewConfigurator(app.MsgServiceRouter(), app.GRPCQueryRouter())
// We register all modules on the Configurator, except x/bank. x/bank will
// serve as the test subject on which we run the migration tests.
//
// The loop below is the same as calling `RegisterServices` on
// ModuleManager, except that we skip x/bank.
for _, module := range app.mm.Modules {
if module.Name() == banktypes.ModuleName {
continue
}
module.RegisterServices(app.configurator)
}
// Initialize the chain
app.InitChain(abci.RequestInitChain{})
app.Commit()
testCases := []struct { testCases := []struct {
name string name string
moduleName string moduleName string
@ -115,12 +156,30 @@ func TestRunMigrations(t *testing.T) {
} }
require.NoError(t, err) require.NoError(t, err)
// Run migrations only for bank. That's why we put the initial
// version for bank as 1, and for all other modules, we put as
// their latest ConsensusVersion.
err = app.RunMigrations( err = app.RunMigrations(
app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}), app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}),
module.MigrationMap{ module.MigrationMap{
"auth": 1, "authz": 1, "bank": 1, "staking": 1, "mint": 1, "distribution": 1, "bank": 1,
"slashing": 1, "gov": 1, "params": 1, "ibc": 1, "upgrade": 1, "vesting": 1, "auth": auth.AppModule{}.ConsensusVersion(),
"feegrant": 1, "transfer": 1, "evidence": 1, "crisis": 1, "genutil": 1, "capability": 1, "authz": authz.AppModule{}.ConsensusVersion(),
"staking": staking.AppModule{}.ConsensusVersion(),
"mint": mint.AppModule{}.ConsensusVersion(),
"distribution": distribution.AppModule{}.ConsensusVersion(),
"slashing": slashing.AppModule{}.ConsensusVersion(),
"gov": gov.AppModule{}.ConsensusVersion(),
"params": params.AppModule{}.ConsensusVersion(),
"ibc": ibc.AppModule{}.ConsensusVersion(),
"upgrade": upgrade.AppModule{}.ConsensusVersion(),
"vesting": vesting.AppModule{}.ConsensusVersion(),
"feegrant": feegrant.AppModule{}.ConsensusVersion(),
"transfer": transfer.AppModule{}.ConsensusVersion(),
"evidence": evidence.AppModule{}.ConsensusVersion(),
"crisis": crisis.AppModule{}.ConsensusVersion(),
"genutil": genutil.AppModule{}.ConsensusVersion(),
"capability": capability.AppModule{}.ConsensusVersion(),
}, },
) )
if tc.expRunErr { if tc.expRunErr {

View File

@ -331,7 +331,7 @@ func (m *Manager) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) map[st
} }
// MigrationHandler is the migration function that each module registers. // MigrationHandler is the migration function that each module registers.
type MigrationHandler func(store sdk.Context) error type MigrationHandler func(sdk.Context) error
// MigrationMap is a map of moduleName -> version, where version denotes the // MigrationMap is a map of moduleName -> version, where version denotes the
// version from which we should perform the migration for each module. // version from which we should perform the migration for each module.

View File

@ -5,16 +5,17 @@ import (
v042 "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042" v042 "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042"
) )
// MigrationKeeper is an interface that the keeper implements for handling // Migrator is a struct for handling in-place store migrations.
// in-place store migrations. type Migrator struct {
type MigrationKeeper interface { keeper BaseKeeper
// Migrate1 migrates the store from version 1 to 2.
Migrate1(ctx sdk.Context) error
} }
var _ MigrationKeeper = (*BaseKeeper)(nil) // NewMigrator returns a new Migrator.
func NewMigrator(keeper BaseKeeper) Migrator {
// Migrate1 implements MigrationKeeper.Migrate1 method. return Migrator{keeper: keeper}
func (keeper BaseKeeper) Migrate1(ctx sdk.Context) error { }
return v042.MigrateStore(ctx, keeper.storeKey)
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v042.MigrateStore(ctx, m.keeper.storeKey)
} }

View File

@ -1,3 +1,5 @@
// Package v040 is copy-pasted from:
// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/bank/types/key.go
package v040 package v040
import ( import (

View File

@ -1,50 +0,0 @@
package v042
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
)
const (
// ModuleName defines the module name
ModuleName = "bank"
// StoreKey defines the primary module store key
StoreKey = ModuleName
// RouterKey defines the module's message routing key
RouterKey = ModuleName
// QuerierRoute defines the module's query routing key
QuerierRoute = ModuleName
)
// KVStore keys
var (
// BalancesPrefix is the for the account balances store. We use a byte
// (instead of say `[]]byte("balances")` to save some disk space).
BalancesPrefix = []byte{0x02}
SupplyKey = []byte{0x00}
DenomMetadataPrefix = []byte{0x1}
)
// DenomMetadataKey returns the denomination metadata key.
func DenomMetadataKey(denom string) []byte {
d := []byte(denom)
return append(DenomMetadataPrefix, d...)
}
// AddressFromBalancesStore returns an account address from a balances prefix
// store. The key must not contain the perfix BalancesPrefix as the prefix store
// iterator discards the actual prefix.
func AddressFromBalancesStore(key []byte) sdk.AccAddress {
addrLen := key[0]
addr := key[1 : addrLen+1]
return sdk.AccAddress(addr)
}
// CreateAccountBalancesPrefix creates the prefix for an account's balances.
func CreateAccountBalancesPrefix(addr []byte) []byte {
return append(BalancesPrefix, address.MustLengthPrefix(addr)...)
}

View File

@ -5,6 +5,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040" v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
v040bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v040" v040bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v040"
"github.com/cosmos/cosmos-sdk/x/bank/types"
) )
// MigrateStore performs in-place store migrations from v0.40 to v0.42. The // MigrateStore performs in-place store migrations from v0.40 to v0.42. The
@ -27,7 +28,7 @@ func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
for ; oldStoreIter.Valid(); oldStoreIter.Next() { for ; oldStoreIter.Valid(); oldStoreIter.Next() {
addr := v040bank.AddressFromBalancesStore(oldStoreIter.Key()) addr := v040bank.AddressFromBalancesStore(oldStoreIter.Key())
denom := oldStoreIter.Key()[v040auth.AddrLen:] denom := oldStoreIter.Key()[v040auth.AddrLen:]
newStoreKey := append(CreateAccountBalancesPrefix(addr), denom...) newStoreKey := append(types.CreateAccountBalancesPrefix(addr), denom...)
// Set new key on store. Values don't change. // Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value()) store.Set(newStoreKey, oldStoreIter.Value())

View File

@ -10,6 +10,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
v040bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v040" v040bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v040"
v042bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042" v042bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042"
"github.com/cosmos/cosmos-sdk/x/bank/types"
) )
func TestStoreMigration(t *testing.T) { func TestStoreMigration(t *testing.T) {
@ -27,7 +28,7 @@ func TestStoreMigration(t *testing.T) {
err := v042bank.MigrateStore(ctx, bankKey) err := v042bank.MigrateStore(ctx, bankKey)
require.NoError(t, err) require.NoError(t, err)
newKey := append(v042bank.CreateAccountBalancesPrefix(addr), denom...) newKey := append(types.CreateAccountBalancesPrefix(addr), denom...)
// -7 because we replaced "balances" with 0x02, // -7 because we replaced "balances" with 0x02,
// +1 because we added length-prefix to address. // +1 because we added length-prefix to address.
require.Equal(t, len(oldKey)-7+1, len(newKey)) require.Equal(t, len(oldKey)-7+1, len(newKey))

View File

@ -98,9 +98,9 @@ type AppModule struct {
func (am AppModule) RegisterServices(cfg module.Configurator) { func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
cfg.RegisterMigration(types.ModuleName, 0, func(ctx sdk.Context) error {
return am.keeper.(keeper.MigrationKeeper).Migrate1(ctx) m := keeper.NewMigrator(am.keeper.(keeper.BaseKeeper))
}) cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
} }
// NewAppModule creates a new AppModule object // NewAppModule creates a new AppModule object

View File

@ -0,0 +1,21 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v042 "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v042"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v042.MigrateStore(ctx, m.keeper.storeKey)
}

View File

@ -0,0 +1,196 @@
// Package v040 is copy-pasted from:
// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/distribution/types/keys.go
package v040
import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
)
const (
// ModuleName is the module name constant used in many places
ModuleName = "distribution"
// StoreKey is the store key string for distribution
StoreKey = ModuleName
// RouterKey is the message route for distribution
RouterKey = ModuleName
// QuerierRoute is the querier route for distribution
QuerierRoute = ModuleName
)
// Keys for distribution store
// Items are stored with the following key: values
//
// - 0x00<proposalID_Bytes>: FeePol
//
// - 0x01: sdk.ConsAddress
//
// - 0x02<valAddr_Bytes>: ValidatorOutstandingRewards
//
// - 0x03<accAddr_Bytes>: sdk.AccAddress
//
// - 0x04<valAddr_Bytes><accAddr_Bytes>: DelegatorStartingInfo
//
// - 0x05<valAddr_Bytes><period_Bytes>: ValidatorHistoricalRewards
//
// - 0x06<valAddr_Bytes>: ValidatorCurrentRewards
//
// - 0x07<valAddr_Bytes>: ValidatorCurrentRewards
//
// - 0x08<valAddr_Bytes><height>: ValidatorSlashEvent
var (
FeePoolKey = []byte{0x00} // key for global distribution state
ProposerKey = []byte{0x01} // key for the proposer operator address
ValidatorOutstandingRewardsPrefix = []byte{0x02} // key for outstanding rewards
DelegatorWithdrawAddrPrefix = []byte{0x03} // key for delegator withdraw address
DelegatorStartingInfoPrefix = []byte{0x04} // key for delegator starting info
ValidatorHistoricalRewardsPrefix = []byte{0x05} // key for historical validators rewards / stake
ValidatorCurrentRewardsPrefix = []byte{0x06} // key for current validator rewards
ValidatorAccumulatedCommissionPrefix = []byte{0x07} // key for accumulated validator commission
ValidatorSlashEventPrefix = []byte{0x08} // key for validator slash fraction
)
// gets an address from a validator's outstanding rewards key
func GetValidatorOutstandingRewardsAddress(key []byte) (valAddr sdk.ValAddress) {
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
return sdk.ValAddress(addr)
}
// gets an address from a delegator's withdraw info key
func GetDelegatorWithdrawInfoAddress(key []byte) (delAddr sdk.AccAddress) {
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
return sdk.AccAddress(addr)
}
// gets the addresses from a delegator starting info key
func GetDelegatorStartingInfoAddresses(key []byte) (valAddr sdk.ValAddress, delAddr sdk.AccAddress) {
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
valAddr = sdk.ValAddress(addr)
addr = key[1+v040auth.AddrLen:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
delAddr = sdk.AccAddress(addr)
return
}
// gets the address & period from a validator's historical rewards key
func GetValidatorHistoricalRewardsAddressPeriod(key []byte) (valAddr sdk.ValAddress, period uint64) {
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
valAddr = sdk.ValAddress(addr)
b := key[1+v040auth.AddrLen:]
if len(b) != 8 {
panic("unexpected key length")
}
period = binary.LittleEndian.Uint64(b)
return
}
// gets the address from a validator's current rewards key
func GetValidatorCurrentRewardsAddress(key []byte) (valAddr sdk.ValAddress) {
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
return sdk.ValAddress(addr)
}
// gets the address from a validator's accumulated commission key
func GetValidatorAccumulatedCommissionAddress(key []byte) (valAddr sdk.ValAddress) {
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
return sdk.ValAddress(addr)
}
// gets the height from a validator's slash event key
func GetValidatorSlashEventAddressHeight(key []byte) (valAddr sdk.ValAddress, height uint64) {
addr := key[1 : 1+v040auth.AddrLen]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
valAddr = sdk.ValAddress(addr)
startB := 1 + v040auth.AddrLen
b := key[startB : startB+8] // the next 8 bytes represent the height
height = binary.BigEndian.Uint64(b)
return
}
// gets the outstanding rewards key for a validator
func GetValidatorOutstandingRewardsKey(valAddr sdk.ValAddress) []byte {
return append(ValidatorOutstandingRewardsPrefix, valAddr.Bytes()...)
}
// gets the key for a delegator's withdraw addr
func GetDelegatorWithdrawAddrKey(delAddr sdk.AccAddress) []byte {
return append(DelegatorWithdrawAddrPrefix, delAddr.Bytes()...)
}
// gets the key for a delegator's starting info
func GetDelegatorStartingInfoKey(v sdk.ValAddress, d sdk.AccAddress) []byte {
return append(append(DelegatorStartingInfoPrefix, v.Bytes()...), d.Bytes()...)
}
// gets the prefix key for a validator's historical rewards
func GetValidatorHistoricalRewardsPrefix(v sdk.ValAddress) []byte {
return append(ValidatorHistoricalRewardsPrefix, v.Bytes()...)
}
// gets the key for a validator's historical rewards
func GetValidatorHistoricalRewardsKey(v sdk.ValAddress, k uint64) []byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, k)
return append(append(ValidatorHistoricalRewardsPrefix, v.Bytes()...), b...)
}
// gets the key for a validator's current rewards
func GetValidatorCurrentRewardsKey(v sdk.ValAddress) []byte {
return append(ValidatorCurrentRewardsPrefix, v.Bytes()...)
}
// gets the key for a validator's current commission
func GetValidatorAccumulatedCommissionKey(v sdk.ValAddress) []byte {
return append(ValidatorAccumulatedCommissionPrefix, v.Bytes()...)
}
// gets the prefix key for a validator's slash fractions
func GetValidatorSlashEventPrefix(v sdk.ValAddress) []byte {
return append(ValidatorSlashEventPrefix, v.Bytes()...)
}
// gets the prefix key for a validator's slash fraction (ValidatorSlashEventPrefix + height)
func GetValidatorSlashEventKeyPrefix(v sdk.ValAddress, height uint64) []byte {
heightBz := make([]byte, 8)
binary.BigEndian.PutUint64(heightBz, height)
return append(
ValidatorSlashEventPrefix,
append(v.Bytes(), heightBz...)...,
)
}
// gets the key for a validator's slash fraction
func GetValidatorSlashEventKey(v sdk.ValAddress, height, period uint64) []byte {
periodBz := make([]byte, 8)
binary.BigEndian.PutUint64(periodBz, period)
prefix := GetValidatorSlashEventKeyPrefix(v, height)
return append(prefix, periodBz...)
}

View File

@ -1,6 +0,0 @@
package v040
// Default parameter values
const (
ModuleName = "distribution"
)

View File

@ -0,0 +1,70 @@
package v042
import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
)
// MigratePrefixAddress is a helper function that migrates all keys of format:
// prefix_bytes | address_bytes
// into format:
// prefix_bytes | address_len (1 byte) | address_bytes
func MigratePrefixAddress(store sdk.KVStore, prefixBz []byte) {
oldStore := prefix.NewStore(store, prefixBz)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
addr := oldStoreIter.Key()
newStoreKey := append(prefixBz, address.MustLengthPrefix(addr)...)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}
// MigratePrefixAddressBytes is a helper function that migrates all keys of format:
// prefix_bytes | address_bytes | arbitrary_bytes
// into format:
// prefix_bytes | address_len (1 byte) | address_bytes | arbitrary_bytes
func MigratePrefixAddressBytes(store sdk.KVStore, prefixBz []byte) {
oldStore := prefix.NewStore(store, prefixBz)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
addr := oldStoreIter.Key()[:v040auth.AddrLen]
endBz := oldStoreIter.Key()[v040auth.AddrLen:]
newStoreKey := append(append(prefixBz, address.MustLengthPrefix(addr)...), endBz...)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}
// MigratePrefixAddressAddress is a helper function that migrates all keys of format:
// prefix_bytes | address_1_bytes | address_2_bytes
// into format:
// prefix_bytes | address_1_len (1 byte) | address_1_bytes | address_2_len (1 byte) | address_2_bytes
func MigratePrefixAddressAddress(store sdk.KVStore, prefixBz []byte) {
oldStore := prefix.NewStore(store, prefixBz)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
addr1 := oldStoreIter.Key()[:v040auth.AddrLen]
addr2 := oldStoreIter.Key()[v040auth.AddrLen:]
newStoreKey := append(append(prefixBz, address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}

View File

@ -0,0 +1,23 @@
package v042
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v040distribution "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v040"
)
// MigrateStore performs in-place store migrations from v0.40 to v0.42. The
// migration includes:
//
// - Change addresses to be length-prefixed.
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
store := ctx.KVStore(storeKey)
MigratePrefixAddress(store, v040distribution.ValidatorOutstandingRewardsPrefix)
MigratePrefixAddress(store, v040distribution.DelegatorWithdrawAddrPrefix)
MigratePrefixAddressAddress(store, v040distribution.DelegatorStartingInfoPrefix)
MigratePrefixAddressBytes(store, v040distribution.ValidatorHistoricalRewardsPrefix)
MigratePrefixAddress(store, v040distribution.ValidatorCurrentRewardsPrefix)
MigratePrefixAddress(store, v040distribution.ValidatorAccumulatedCommissionPrefix)
MigratePrefixAddressBytes(store, v040distribution.ValidatorSlashEventPrefix)
return nil
}

View File

@ -0,0 +1,99 @@
package v042_test
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
v040distribution "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v040"
v042distribution "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v042"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
)
func TestStoreMigration(t *testing.T) {
distributionKey := sdk.NewKVStoreKey("distribution")
ctx := testutil.DefaultContext(distributionKey, sdk.NewTransientStoreKey("transient_test"))
store := ctx.KVStore(distributionKey)
_, _, addr1 := testdata.KeyTestPubAddr()
valAddr := sdk.ValAddress(addr1)
_, _, addr2 := testdata.KeyTestPubAddr()
// Use dummy value for all keys.
value := []byte("foo")
testCases := []struct {
name string
oldKey []byte
newKey []byte
}{
{
"FeePoolKey",
v040distribution.FeePoolKey,
types.FeePoolKey,
},
{
"ProposerKey",
v040distribution.ProposerKey,
types.ProposerKey,
},
{
"ValidatorOutstandingRewards",
v040distribution.GetValidatorOutstandingRewardsKey(valAddr),
types.GetValidatorOutstandingRewardsKey(valAddr),
},
{
"DelegatorWithdrawAddr",
v040distribution.GetDelegatorWithdrawAddrKey(addr2),
types.GetDelegatorWithdrawAddrKey(addr2),
},
{
"DelegatorStartingInfo",
v040distribution.GetDelegatorStartingInfoKey(valAddr, addr2),
types.GetDelegatorStartingInfoKey(valAddr, addr2),
},
{
"ValidatorHistoricalRewards",
v040distribution.GetValidatorHistoricalRewardsKey(valAddr, 6),
types.GetValidatorHistoricalRewardsKey(valAddr, 6),
},
{
"ValidatorCurrentRewards",
v040distribution.GetValidatorCurrentRewardsKey(valAddr),
types.GetValidatorCurrentRewardsKey(valAddr),
},
{
"ValidatorAccumulatedCommission",
v040distribution.GetValidatorAccumulatedCommissionKey(valAddr),
types.GetValidatorAccumulatedCommissionKey(valAddr),
},
{
"ValidatorSlashEvent",
v040distribution.GetValidatorSlashEventKey(valAddr, 6, 8),
types.GetValidatorSlashEventKey(valAddr, 6, 8),
},
}
// Set all the old keys to the store
for _, tc := range testCases {
store.Set(tc.oldKey, value)
}
// Run migrations.
err := v042distribution.MigrateStore(ctx, distributionKey)
require.NoError(t, err)
// Make sure the new keys are set and old keys are deleted.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if bytes.Compare(tc.oldKey, tc.newKey) != 0 {
require.Nil(t, store.Get(tc.oldKey))
}
require.Equal(t, value, store.Get(tc.newKey))
})
}
}

View File

@ -141,6 +141,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
func (am AppModule) RegisterServices(cfg module.Configurator) { func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
m := keeper.NewMigrator(am.keeper)
cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
} }
// InitGenesis performs genesis initialization for the distribution module. It returns // InitGenesis performs genesis initialization for the distribution module. It returns
@ -160,7 +163,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
} }
// ConsensusVersion implements AppModule/ConsensusVersion. // ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 } func (AppModule) ConsensusVersion() uint64 { return 2 }
// BeginBlock returns the begin blocker for the distribution module. // BeginBlock returns the begin blocker for the distribution module.
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) { func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {

View File

@ -15,7 +15,7 @@ for fractions of coins to be received from operations like inflation.
When coins are distributed from the pool they are truncated back to When coins are distributed from the pool they are truncated back to
`sdk.Coins` which are non-decimal. `sdk.Coins` which are non-decimal.
- FeePool: `0x00 -> ProtocolBuffer(FeePool)` - FeePool: `0x00 -> ProtocolBuffer(FeePool)`
```go ```go
// coins with decimal // coins with decimal
@ -33,12 +33,12 @@ type DecCoin struct {
Validator distribution information for the relevant validator is updated each time: Validator distribution information for the relevant validator is updated each time:
1. delegation amount to a validator is updated, 1. delegation amount to a validator is updated,
2. a validator successfully proposes a block and receives a reward, 2. a validator successfully proposes a block and receives a reward,
3. any delegator withdraws from a validator, or 3. any delegator withdraws from a validator, or
4. the validator withdraws it's commission. 4. the validator withdraws it's commission.
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)` - ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)`
```go ```go
type ValidatorDistInfo struct { type ValidatorDistInfo struct {
@ -56,7 +56,7 @@ properties change (aka bonded tokens etc.) its properties will remain constant
and the delegator's _accumulation_ factor can be calculated passively knowing and the delegator's _accumulation_ factor can be calculated passively knowing
only the height of the last withdrawal and its current properties. only the height of the last withdrawal and its current properties.
- DelegationDistInfo: `0x02 | DelegatorAddr | ValOperatorAddr -> ProtocolBuffer(delegatorDist)` - DelegationDistInfo: `0x02 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(delegatorDist)`
```go ```go
type DelegationDistInfo struct { type DelegationDistInfo struct {

View File

@ -0,0 +1,21 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v042 "github.com/cosmos/cosmos-sdk/x/gov/legacy/v042"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v042.MigrateStore(ctx, m.keeper.storeKey)
}

167
x/gov/legacy/v040/keys.go Normal file
View File

@ -0,0 +1,167 @@
// Package v040 is copy-pasted from:
// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/gov/types/keys.go
package v040
import (
"encoding/binary"
"fmt"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
)
const (
// ModuleName is the name of the module
ModuleName = "gov"
// StoreKey is the store key string for gov
StoreKey = ModuleName
// RouterKey is the message route for gov
RouterKey = ModuleName
// QuerierRoute is the querier route for gov
QuerierRoute = ModuleName
)
// Keys for governance store
// Items are stored with the following key: values
//
// - 0x00<proposalID_Bytes>: Proposal
//
// - 0x01<endTime_Bytes><proposalID_Bytes>: activeProposalID
//
// - 0x02<endTime_Bytes><proposalID_Bytes>: inactiveProposalID
//
// - 0x03: nextProposalID
//
// - 0x10<proposalID_Bytes><depositorAddr_Bytes>: Deposit
//
// - 0x20<proposalID_Bytes><voterAddr_Bytes>: Voter
var (
ProposalsKeyPrefix = []byte{0x00}
ActiveProposalQueuePrefix = []byte{0x01}
InactiveProposalQueuePrefix = []byte{0x02}
ProposalIDKey = []byte{0x03}
DepositsKeyPrefix = []byte{0x10}
VotesKeyPrefix = []byte{0x20}
)
var lenTime = len(sdk.FormatTimeBytes(time.Now()))
// GetProposalIDBytes returns the byte representation of the proposalID
func GetProposalIDBytes(proposalID uint64) (proposalIDBz []byte) {
proposalIDBz = make([]byte, 8)
binary.BigEndian.PutUint64(proposalIDBz, proposalID)
return
}
// GetProposalIDFromBytes returns proposalID in uint64 format from a byte array
func GetProposalIDFromBytes(bz []byte) (proposalID uint64) {
return binary.BigEndian.Uint64(bz)
}
// ProposalKey gets a specific proposal from the store
func ProposalKey(proposalID uint64) []byte {
return append(ProposalsKeyPrefix, GetProposalIDBytes(proposalID)...)
}
// ActiveProposalByTimeKey gets the active proposal queue key by endTime
func ActiveProposalByTimeKey(endTime time.Time) []byte {
return append(ActiveProposalQueuePrefix, sdk.FormatTimeBytes(endTime)...)
}
// ActiveProposalQueueKey returns the key for a proposalID in the activeProposalQueue
func ActiveProposalQueueKey(proposalID uint64, endTime time.Time) []byte {
return append(ActiveProposalByTimeKey(endTime), GetProposalIDBytes(proposalID)...)
}
// InactiveProposalByTimeKey gets the inactive proposal queue key by endTime
func InactiveProposalByTimeKey(endTime time.Time) []byte {
return append(InactiveProposalQueuePrefix, sdk.FormatTimeBytes(endTime)...)
}
// InactiveProposalQueueKey returns the key for a proposalID in the inactiveProposalQueue
func InactiveProposalQueueKey(proposalID uint64, endTime time.Time) []byte {
return append(InactiveProposalByTimeKey(endTime), GetProposalIDBytes(proposalID)...)
}
// DepositsKey gets the first part of the deposits key based on the proposalID
func DepositsKey(proposalID uint64) []byte {
return append(DepositsKeyPrefix, GetProposalIDBytes(proposalID)...)
}
// DepositKey key of a specific deposit from the store
func DepositKey(proposalID uint64, depositorAddr sdk.AccAddress) []byte {
return append(DepositsKey(proposalID), depositorAddr.Bytes()...)
}
// VotesKey gets the first part of the votes key based on the proposalID
func VotesKey(proposalID uint64) []byte {
return append(VotesKeyPrefix, GetProposalIDBytes(proposalID)...)
}
// VoteKey key of a specific vote from the store
func VoteKey(proposalID uint64, voterAddr sdk.AccAddress) []byte {
return append(VotesKey(proposalID), voterAddr.Bytes()...)
}
// Split keys function; used for iterators
// SplitProposalKey split the proposal key and returns the proposal id
func SplitProposalKey(key []byte) (proposalID uint64) {
if len(key[1:]) != 8 {
panic(fmt.Sprintf("unexpected key length (%d ≠ 8)", len(key[1:])))
}
return GetProposalIDFromBytes(key[1:])
}
// SplitActiveProposalQueueKey split the active proposal key and returns the proposal id and endTime
func SplitActiveProposalQueueKey(key []byte) (proposalID uint64, endTime time.Time) {
return splitKeyWithTime(key)
}
// SplitInactiveProposalQueueKey split the inactive proposal key and returns the proposal id and endTime
func SplitInactiveProposalQueueKey(key []byte) (proposalID uint64, endTime time.Time) {
return splitKeyWithTime(key)
}
// SplitKeyDeposit split the deposits key and returns the proposal id and depositor address
func SplitKeyDeposit(key []byte) (proposalID uint64, depositorAddr sdk.AccAddress) {
return splitKeyWithAddress(key)
}
// SplitKeyVote split the votes key and returns the proposal id and voter address
func SplitKeyVote(key []byte) (proposalID uint64, voterAddr sdk.AccAddress) {
return splitKeyWithAddress(key)
}
// private functions
func splitKeyWithTime(key []byte) (proposalID uint64, endTime time.Time) {
if len(key[1:]) != 8+lenTime {
panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key[1:]), lenTime+8))
}
endTime, err := sdk.ParseTimeBytes(key[1 : 1+lenTime])
if err != nil {
panic(err)
}
proposalID = GetProposalIDFromBytes(key[1+lenTime:])
return
}
func splitKeyWithAddress(key []byte) (proposalID uint64, addr sdk.AccAddress) {
if len(key[1:]) != 8+v040auth.AddrLen {
panic(fmt.Sprintf("unexpected key length (%d ≠ %d)", len(key), 8+v040auth.AddrLen))
}
proposalID = GetProposalIDFromBytes(key[1:9])
addr = sdk.AccAddress(key[9:])
return
}

View File

@ -1,6 +0,0 @@
package v040
// Default parameter values
const (
ModuleName = "gov"
)

View File

@ -0,0 +1,43 @@
package v042
import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040"
)
const proposalIDLen = 8
// migratePrefixProposalAddress is a helper function that migrates all keys of format:
// <prefix_bytes><proposal_id (8 bytes)><address_bytes>
// into format:
// <prefix_bytes><proposal_id (8 bytes)><address_len (1 byte)><address_bytes>
func migratePrefixProposalAddress(store sdk.KVStore, prefixBz []byte) {
oldStore := prefix.NewStore(store, prefixBz)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
proposalID := oldStoreIter.Key()[:proposalIDLen]
addr := oldStoreIter.Key()[proposalIDLen:]
newStoreKey := append(append(prefixBz, proposalID...), address.MustLengthPrefix(addr)...)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}
// MigrateStore performs in-place store migrations from v0.40 to v0.42. The
// migration includes:
//
// - Change addresses to be length-prefixed.
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
store := ctx.KVStore(storeKey)
migratePrefixProposalAddress(store, v040gov.DepositsKeyPrefix)
migratePrefixProposalAddress(store, v040gov.VotesKeyPrefix)
return nil
}

View File

@ -0,0 +1,85 @@
package v042_test
import (
"bytes"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
v040gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v040"
v042gov "github.com/cosmos/cosmos-sdk/x/gov/legacy/v042"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
func TestStoreMigration(t *testing.T) {
govKey := sdk.NewKVStoreKey("gov")
ctx := testutil.DefaultContext(govKey, sdk.NewTransientStoreKey("transient_test"))
store := ctx.KVStore(govKey)
_, _, addr1 := testdata.KeyTestPubAddr()
proposalID := uint64(6)
now := time.Now()
// Use dummy value for all keys.
value := []byte("foo")
testCases := []struct {
name string
oldKey []byte
newKey []byte
}{
{
"ProposalKey",
v040gov.ProposalKey(proposalID),
types.ProposalKey(proposalID),
},
{
"ActiveProposalQueue",
v040gov.ActiveProposalQueueKey(proposalID, now),
types.ActiveProposalQueueKey(proposalID, now),
},
{
"InactiveProposalQueue",
v040gov.InactiveProposalQueueKey(proposalID, now),
types.InactiveProposalQueueKey(proposalID, now),
},
{
"ProposalIDKey",
v040gov.ProposalIDKey,
types.ProposalIDKey,
},
{
"DepositKey",
v040gov.DepositKey(proposalID, addr1),
types.DepositKey(proposalID, addr1),
},
{
"VotesKeyPrefix",
v040gov.VoteKey(proposalID, addr1),
types.VoteKey(proposalID, addr1),
},
}
// Set all the old keys to the store
for _, tc := range testCases {
store.Set(tc.oldKey, value)
}
// Run migrations.
err := v042gov.MigrateStore(ctx, govKey)
require.NoError(t, err)
// Make sure the new keys are set and old keys are deleted.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if bytes.Compare(tc.oldKey, tc.newKey) != 0 {
require.Nil(t, store.Get(tc.oldKey))
}
require.Equal(t, value, store.Get(tc.newKey))
})
}
}

View File

@ -157,6 +157,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
func (am AppModule) RegisterServices(cfg module.Configurator) { func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
m := keeper.NewMigrator(am.keeper)
cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
} }
// InitGenesis performs genesis initialization for the gov module. It returns // InitGenesis performs genesis initialization for the gov module. It returns
@ -176,7 +179,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
} }
// ConsensusVersion implements AppModule/ConsensusVersion. // ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 } func (AppModule) ConsensusVersion() uint64 { return 2 }
// BeginBlock performs a no-op. // BeginBlock performs a no-op.
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {} func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}

View File

@ -0,0 +1,21 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v042 "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v042"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v042.MigrateStore(ctx, m.keeper.storeKey)
}

View File

@ -0,0 +1,69 @@
// Package v040 is copy-pasted from:
// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/slashing/types/keys.go
package v040
import (
"encoding/binary"
sdk "github.com/cosmos/cosmos-sdk/types"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
)
const (
// ModuleName is the name of the module
ModuleName = "slashing"
// StoreKey is the store key string for slashing
StoreKey = ModuleName
// RouterKey is the message route for slashing
RouterKey = ModuleName
// QuerierRoute is the querier route for slashing
QuerierRoute = ModuleName
)
// Keys for slashing store
// Items are stored with the following key: values
//
// - 0x01<consAddress_Bytes>: ValidatorSigningInfo
//
// - 0x02<consAddress_Bytes><period_Bytes>: bool
//
// - 0x03<accAddr_Bytes>: crypto.PubKey
var (
ValidatorSigningInfoKeyPrefix = []byte{0x01} // Prefix for signing info
ValidatorMissedBlockBitArrayKeyPrefix = []byte{0x02} // Prefix for missed block bit array
AddrPubkeyRelationKeyPrefix = []byte{0x03} // Prefix for address-pubkey relation
)
// ValidatorSigningInfoKey - stored by *Consensus* address (not operator address)
func ValidatorSigningInfoKey(v sdk.ConsAddress) []byte {
return append(ValidatorSigningInfoKeyPrefix, v.Bytes()...)
}
// ValidatorSigningInfoAddress - extract the address from a validator signing info key
func ValidatorSigningInfoAddress(key []byte) (v sdk.ConsAddress) {
addr := key[1:]
if len(addr) != v040auth.AddrLen {
panic("unexpected key length")
}
return sdk.ConsAddress(addr)
}
// ValidatorMissedBlockBitArrayPrefixKey - stored by *Consensus* address (not operator address)
func ValidatorMissedBlockBitArrayPrefixKey(v sdk.ConsAddress) []byte {
return append(ValidatorMissedBlockBitArrayKeyPrefix, v.Bytes()...)
}
// ValidatorMissedBlockBitArrayKey - stored by *Consensus* address (not operator address)
func ValidatorMissedBlockBitArrayKey(v sdk.ConsAddress, i int64) []byte {
b := make([]byte, 8)
binary.LittleEndian.PutUint64(b, uint64(i))
return append(ValidatorMissedBlockBitArrayPrefixKey(v), b...)
}
// AddrPubkeyRelationKey gets pubkey relation key used to get the pubkey from the address
func AddrPubkeyRelationKey(address []byte) []byte {
return append(AddrPubkeyRelationKeyPrefix, address...)
}

View File

@ -1,5 +0,0 @@
package v040
const (
ModuleName = "slashing"
)

View File

@ -0,0 +1,20 @@
package v042
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v042distribution "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v042"
v040slashing "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v040"
)
// MigrateStore performs in-place store migrations from v0.40 to v0.42. The
// migration includes:
//
// - Change addresses to be length-prefixed.
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
store := ctx.KVStore(storeKey)
v042distribution.MigratePrefixAddress(store, v040slashing.ValidatorSigningInfoKeyPrefix)
v042distribution.MigratePrefixAddressBytes(store, v040slashing.ValidatorMissedBlockBitArrayKeyPrefix)
v042distribution.MigratePrefixAddress(store, v040slashing.AddrPubkeyRelationKeyPrefix)
return nil
}

View File

@ -0,0 +1,68 @@
package v042_test
import (
"bytes"
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
v040slashing "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v040"
v042slashing "github.com/cosmos/cosmos-sdk/x/slashing/legacy/v042"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
)
func TestStoreMigration(t *testing.T) {
slashingKey := sdk.NewKVStoreKey("slashing")
ctx := testutil.DefaultContext(slashingKey, sdk.NewTransientStoreKey("transient_test"))
store := ctx.KVStore(slashingKey)
_, _, addr1 := testdata.KeyTestPubAddr()
consAddr := sdk.ConsAddress(addr1)
// Use dummy value for all keys.
value := []byte("foo")
testCases := []struct {
name string
oldKey []byte
newKey []byte
}{
{
"ValidatorSigningInfoKey",
v040slashing.ValidatorSigningInfoKey(consAddr),
types.ValidatorSigningInfoKey(consAddr),
},
{
"ValidatorMissedBlockBitArrayKey",
v040slashing.ValidatorMissedBlockBitArrayKey(consAddr, 2),
types.ValidatorMissedBlockBitArrayKey(consAddr, 2),
},
{
"AddrPubkeyRelationKey",
v040slashing.AddrPubkeyRelationKey(consAddr),
types.AddrPubkeyRelationKey(consAddr),
},
}
// Set all the old keys to the store
for _, tc := range testCases {
store.Set(tc.oldKey, value)
}
// Run migrations.
err := v042slashing.MigrateStore(ctx, slashingKey)
require.NoError(t, err)
// Make sure the new keys are set and old keys are deleted.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if bytes.Compare(tc.oldKey, tc.newKey) != 0 {
require.Nil(t, store.Get(tc.oldKey))
}
require.Equal(t, value, store.Get(tc.newKey))
})
}
}

View File

@ -139,6 +139,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
func (am AppModule) RegisterServices(cfg module.Configurator) { func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
types.RegisterQueryServer(cfg.QueryServer(), am.keeper) types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
m := keeper.NewMigrator(am.keeper)
cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
} }
// InitGenesis performs genesis initialization for the slashing module. It returns // InitGenesis performs genesis initialization for the slashing module. It returns

View File

@ -27,8 +27,8 @@ number of blocks by being automatically jailed, potentially slashed, and unbonde
Information about validator's liveness activity is tracked through `ValidatorSigningInfo`. Information about validator's liveness activity is tracked through `ValidatorSigningInfo`.
It is indexed in the store as follows: It is indexed in the store as follows:
- ValidatorSigningInfo: ` 0x01 | ConsAddress -> ProtocolBuffer(ValSigningInfo)` - ValidatorSigningInfo: ` 0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)`
- MissedBlocksBitArray: ` 0x02 | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format) - MissedBlocksBitArray: ` 0x02 | ConsAddrLen (1 byte) | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format)
The first mapping allows us to easily lookup the recent signing info for a The first mapping allows us to easily lookup the recent signing info for a
validator based on the validator's consensus address. validator based on the validator's consensus address.

View File

@ -0,0 +1,21 @@
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
v042 "github.com/cosmos/cosmos-sdk/x/staking/legacy/v042"
)
// Migrator is a struct for handling in-place store migrations.
type Migrator struct {
keeper Keeper
}
// NewMigrator returns a new Migrator.
func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}
// Migrate1to2 migrates from version 1 to 2.
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return v042.MigrateStore(ctx, m.keeper.storeKey)
}

View File

@ -0,0 +1,330 @@
// Package v040 is copy-pasted from:
// https://github.com/cosmos/cosmos-sdk/blob/v0.41.0/x/staking/types/keys.go
package v040
import (
"bytes"
"encoding/binary"
"fmt"
"strconv"
"time"
sdk "github.com/cosmos/cosmos-sdk/types"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)
const (
// ModuleName is the name of the staking module
ModuleName = "staking"
// StoreKey is the string store representation
StoreKey = ModuleName
// QuerierRoute is the querier route for the staking module
QuerierRoute = ModuleName
// RouterKey is the msg router key for the staking module
RouterKey = ModuleName
)
var (
// Keys for store prefixes
// Last* values are constant during a block.
LastValidatorPowerKey = []byte{0x11} // prefix for each key to a validator index, for bonded validators
LastTotalPowerKey = []byte{0x12} // prefix for the total power
ValidatorsKey = []byte{0x21} // prefix for each key to a validator
ValidatorsByConsAddrKey = []byte{0x22} // prefix for each key to a validator index, by pubkey
ValidatorsByPowerIndexKey = []byte{0x23} // prefix for each key to a validator index, sorted by power
DelegationKey = []byte{0x31} // key for a delegation
UnbondingDelegationKey = []byte{0x32} // key for an unbonding-delegation
UnbondingDelegationByValIndexKey = []byte{0x33} // prefix for each key for an unbonding-delegation, by validator operator
RedelegationKey = []byte{0x34} // key for a redelegation
RedelegationByValSrcIndexKey = []byte{0x35} // prefix for each key for an redelegation, by source validator operator
RedelegationByValDstIndexKey = []byte{0x36} // prefix for each key for an redelegation, by destination validator operator
UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue
RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue
ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue
HistoricalInfoKey = []byte{0x50} // prefix for the historical info
)
// gets the key for the validator with address
// VALUE: staking/Validator
func GetValidatorKey(operatorAddr sdk.ValAddress) []byte {
return append(ValidatorsKey, operatorAddr.Bytes()...)
}
// gets the key for the validator with pubkey
// VALUE: validator operator address ([]byte)
func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
}
// Get the validator operator address from LastValidatorPowerKey
func AddressFromLastValidatorPowerKey(key []byte) []byte {
return key[1:] // remove prefix bytes
}
// get the validator by power index.
// Power index is the key used in the power-store, and represents the relative
// power ranking of the validator.
// VALUE: validator operator address ([]byte)
func GetValidatorsByPowerIndexKey(validator types.Validator) []byte {
// NOTE the address doesn't need to be stored because counter bytes must always be different
// NOTE the larger values are of higher value
consensusPower := sdk.TokensToConsensusPower(validator.Tokens)
consensusPowerBytes := make([]byte, 8)
binary.BigEndian.PutUint64(consensusPowerBytes, uint64(consensusPower))
powerBytes := consensusPowerBytes
powerBytesLen := len(powerBytes) // 8
// key is of format prefix || powerbytes || addrBytes
key := make([]byte, 1+powerBytesLen+v040auth.AddrLen)
key[0] = ValidatorsByPowerIndexKey[0]
copy(key[1:powerBytesLen+1], powerBytes)
addr, err := sdk.ValAddressFromBech32(validator.OperatorAddress)
if err != nil {
panic(err)
}
operAddrInvr := sdk.CopyBytes(addr)
for i, b := range operAddrInvr {
operAddrInvr[i] = ^b
}
copy(key[powerBytesLen+1:], operAddrInvr)
return key
}
// get the bonded validator index key for an operator address
func GetLastValidatorPowerKey(operator sdk.ValAddress) []byte {
return append(LastValidatorPowerKey, operator...)
}
// parse the validators operator address from power rank key
func ParseValidatorPowerRankKey(key []byte) (operAddr []byte) {
powerBytesLen := 8
if len(key) != 1+powerBytesLen+v040auth.AddrLen {
panic("Invalid validator power rank key length")
}
operAddr = sdk.CopyBytes(key[powerBytesLen+1:])
for i, b := range operAddr {
operAddr[i] = ^b
}
return operAddr
}
// GetValidatorQueueKey returns the prefix key used for getting a set of unbonding
// validators whose unbonding completion occurs at the given time and height.
func GetValidatorQueueKey(timestamp time.Time, height int64) []byte {
heightBz := sdk.Uint64ToBigEndian(uint64(height))
timeBz := sdk.FormatTimeBytes(timestamp)
timeBzL := len(timeBz)
prefixL := len(ValidatorQueueKey)
bz := make([]byte, prefixL+8+timeBzL+8)
// copy the prefix
copy(bz[:prefixL], ValidatorQueueKey)
// copy the encoded time bytes length
copy(bz[prefixL:prefixL+8], sdk.Uint64ToBigEndian(uint64(timeBzL)))
// copy the encoded time bytes
copy(bz[prefixL+8:prefixL+8+timeBzL], timeBz)
// copy the encoded height
copy(bz[prefixL+8+timeBzL:], heightBz)
return bz
}
// ParseValidatorQueueKey returns the encoded time and height from a key created
// from GetValidatorQueueKey.
func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) {
prefixL := len(ValidatorQueueKey)
if prefix := bz[:prefixL]; !bytes.Equal(prefix, ValidatorQueueKey) {
return time.Time{}, 0, fmt.Errorf("invalid prefix; expected: %X, got: %X", ValidatorQueueKey, prefix)
}
timeBzL := sdk.BigEndianToUint64(bz[prefixL : prefixL+8])
ts, err := sdk.ParseTimeBytes(bz[prefixL+8 : prefixL+8+int(timeBzL)])
if err != nil {
return time.Time{}, 0, err
}
height := sdk.BigEndianToUint64(bz[prefixL+8+int(timeBzL):])
return ts, int64(height), nil
}
// gets the key for delegator bond with validator
// VALUE: staking/Delegation
func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
return append(GetDelegationsKey(delAddr), valAddr.Bytes()...)
}
// gets the prefix for a delegator for all validators
func GetDelegationsKey(delAddr sdk.AccAddress) []byte {
return append(DelegationKey, delAddr.Bytes()...)
}
// gets the key for an unbonding delegation by delegator and validator addr
// VALUE: staking/UnbondingDelegation
func GetUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
return append(
GetUBDsKey(delAddr.Bytes()),
valAddr.Bytes()...)
}
// gets the index-key for an unbonding delegation, stored by validator-index
// VALUE: none (key rearrangement used)
func GetUBDByValIndexKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
return append(GetUBDsByValIndexKey(valAddr), delAddr.Bytes()...)
}
// rearranges the ValIndexKey to get the UBDKey
func GetUBDKeyFromValIndexKey(indexKey []byte) []byte {
addrs := indexKey[1:] // remove prefix bytes
if len(addrs) != 2*v040auth.AddrLen {
panic("unexpected key length")
}
valAddr := addrs[:v040auth.AddrLen]
delAddr := addrs[v040auth.AddrLen:]
return GetUBDKey(delAddr, valAddr)
}
// gets the prefix for all unbonding delegations from a delegator
func GetUBDsKey(delAddr sdk.AccAddress) []byte {
return append(UnbondingDelegationKey, delAddr.Bytes()...)
}
// gets the prefix keyspace for the indexes of unbonding delegations for a validator
func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte {
return append(UnbondingDelegationByValIndexKey, valAddr.Bytes()...)
}
// gets the prefix for all unbonding delegations from a delegator
func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte {
bz := sdk.FormatTimeBytes(timestamp)
return append(UnbondingQueueKey, bz...)
}
// GetREDKey returns a key prefix for indexing a redelegation from a delegator
// and source validator to a destination validator.
func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte {
key := make([]byte, 1+v040auth.AddrLen*3)
copy(key[0:v040auth.AddrLen+1], GetREDsKey(delAddr.Bytes()))
copy(key[v040auth.AddrLen+1:2*v040auth.AddrLen+1], valSrcAddr.Bytes())
copy(key[2*v040auth.AddrLen+1:3*v040auth.AddrLen+1], valDstAddr.Bytes())
return key
}
// gets the index-key for a redelegation, stored by source-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValSrcIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte {
REDSFromValsSrcKey := GetREDsFromValSrcIndexKey(valSrcAddr)
offset := len(REDSFromValsSrcKey)
// key is of the form REDSFromValsSrcKey || delAddr || valDstAddr
key := make([]byte, len(REDSFromValsSrcKey)+2*v040auth.AddrLen)
copy(key[0:offset], REDSFromValsSrcKey)
copy(key[offset:offset+v040auth.AddrLen], delAddr.Bytes())
copy(key[offset+v040auth.AddrLen:offset+2*v040auth.AddrLen], valDstAddr.Bytes())
return key
}
// gets the index-key for a redelegation, stored by destination-validator-index
// VALUE: none (key rearrangement used)
func GetREDByValDstIndexKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte {
REDSToValsDstKey := GetREDsToValDstIndexKey(valDstAddr)
offset := len(REDSToValsDstKey)
// key is of the form REDSToValsDstKey || delAddr || valSrcAddr
key := make([]byte, len(REDSToValsDstKey)+2*v040auth.AddrLen)
copy(key[0:offset], REDSToValsDstKey)
copy(key[offset:offset+v040auth.AddrLen], delAddr.Bytes())
copy(key[offset+v040auth.AddrLen:offset+2*v040auth.AddrLen], valSrcAddr.Bytes())
return key
}
// GetREDKeyFromValSrcIndexKey rearranges the ValSrcIndexKey to get the REDKey
func GetREDKeyFromValSrcIndexKey(indexKey []byte) []byte {
// note that first byte is prefix byte
if len(indexKey) != 3*v040auth.AddrLen+1 {
panic("unexpected key length")
}
valSrcAddr := indexKey[1 : v040auth.AddrLen+1]
delAddr := indexKey[v040auth.AddrLen+1 : 2*v040auth.AddrLen+1]
valDstAddr := indexKey[2*v040auth.AddrLen+1 : 3*v040auth.AddrLen+1]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
}
// GetREDKeyFromValDstIndexKey rearranges the ValDstIndexKey to get the REDKey
func GetREDKeyFromValDstIndexKey(indexKey []byte) []byte {
// note that first byte is prefix byte
if len(indexKey) != 3*v040auth.AddrLen+1 {
panic("unexpected key length")
}
valDstAddr := indexKey[1 : v040auth.AddrLen+1]
delAddr := indexKey[v040auth.AddrLen+1 : 2*v040auth.AddrLen+1]
valSrcAddr := indexKey[2*v040auth.AddrLen+1 : 3*v040auth.AddrLen+1]
return GetREDKey(delAddr, valSrcAddr, valDstAddr)
}
// GetRedelegationTimeKey returns a key prefix for indexing an unbonding
// redelegation based on a completion time.
func GetRedelegationTimeKey(timestamp time.Time) []byte {
bz := sdk.FormatTimeBytes(timestamp)
return append(RedelegationQueueKey, bz...)
}
// GetREDsKey returns a key prefix for indexing a redelegation from a delegator
// address.
func GetREDsKey(delAddr sdk.AccAddress) []byte {
return append(RedelegationKey, delAddr.Bytes()...)
}
// GetREDsFromValSrcIndexKey returns a key prefix for indexing a redelegation to
// a source validator.
func GetREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte {
return append(RedelegationByValSrcIndexKey, valSrcAddr.Bytes()...)
}
// GetREDsToValDstIndexKey returns a key prefix for indexing a redelegation to a
// destination (target) validator.
func GetREDsToValDstIndexKey(valDstAddr sdk.ValAddress) []byte {
return append(RedelegationByValDstIndexKey, valDstAddr.Bytes()...)
}
// GetREDsByDelToValDstIndexKey returns a key prefix for indexing a redelegation
// from an address to a source validator.
func GetREDsByDelToValDstIndexKey(delAddr sdk.AccAddress, valDstAddr sdk.ValAddress) []byte {
return append(GetREDsToValDstIndexKey(valDstAddr), delAddr.Bytes()...)
}
// GetHistoricalInfoKey returns a key prefix for indexing HistoricalInfo objects.
func GetHistoricalInfoKey(height int64) []byte {
return append(HistoricalInfoKey, []byte(strconv.FormatInt(height, 10))...)
}

View File

@ -1,5 +0,0 @@
package v040
const (
ModuleName = "staking"
)

View File

@ -0,0 +1,78 @@
package v042
import (
"github.com/cosmos/cosmos-sdk/store/prefix"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/address"
v040auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v040"
v042distribution "github.com/cosmos/cosmos-sdk/x/distribution/legacy/v042"
v040staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v040"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)
// migratePrefixAddressAddressAddress is a helper function that migrates all keys of format:
// prefix_bytes | address_1_bytes | address_2_bytes | address_3_bytes
// into format:
// prefix_bytes | address_1_len (1 byte) | address_1_bytes | address_2_len (1 byte) | address_2_bytes | address_3_len (1 byte) | address_3_bytes
func migratePrefixAddressAddressAddress(store sdk.KVStore, prefixBz []byte) {
oldStore := prefix.NewStore(store, prefixBz)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
addr1 := oldStoreIter.Key()[:v040auth.AddrLen]
addr2 := oldStoreIter.Key()[v040auth.AddrLen : 2*v040auth.AddrLen]
addr3 := oldStoreIter.Key()[2*v040auth.AddrLen:]
newStoreKey := append(append(append(
prefixBz,
address.MustLengthPrefix(addr1)...), address.MustLengthPrefix(addr2)...), address.MustLengthPrefix(addr3)...,
)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}
const powerBytesLen = 8
func migrateValidatorsByPowerIndexKey(store sdk.KVStore) {
oldStore := prefix.NewStore(store, v040staking.ValidatorsByPowerIndexKey)
oldStoreIter := oldStore.Iterator(nil, nil)
defer oldStoreIter.Close()
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
powerBytes := oldStoreIter.Key()[:powerBytesLen]
valAddr := oldStoreIter.Key()[powerBytesLen:]
newStoreKey := append(append(types.ValidatorsByPowerIndexKey, powerBytes...), address.MustLengthPrefix(valAddr)...)
// Set new key on store. Values don't change.
store.Set(newStoreKey, oldStoreIter.Value())
oldStore.Delete(oldStoreIter.Key())
}
}
// MigrateStore performs in-place store migrations from v0.40 to v0.42. The
// migration includes:
//
// - Change addresses to be length-prefixed.
func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
store := ctx.KVStore(storeKey)
v042distribution.MigratePrefixAddress(store, v040staking.LastValidatorPowerKey)
v042distribution.MigratePrefixAddress(store, v040staking.ValidatorsKey)
v042distribution.MigratePrefixAddress(store, v040staking.ValidatorsByConsAddrKey)
migrateValidatorsByPowerIndexKey(store)
v042distribution.MigratePrefixAddressAddress(store, v040staking.DelegationKey)
v042distribution.MigratePrefixAddressAddress(store, v040staking.UnbondingDelegationKey)
v042distribution.MigratePrefixAddressAddress(store, v040staking.UnbondingDelegationByValIndexKey)
migratePrefixAddressAddressAddress(store, v040staking.RedelegationKey)
migratePrefixAddressAddressAddress(store, v040staking.RedelegationByValSrcIndexKey)
migratePrefixAddressAddressAddress(store, v040staking.RedelegationByValDstIndexKey)
return nil
}

View File

@ -0,0 +1,137 @@
package v042_test
import (
"bytes"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/testutil"
"github.com/cosmos/cosmos-sdk/testutil/testdata"
sdk "github.com/cosmos/cosmos-sdk/types"
v040staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v040"
v042staking "github.com/cosmos/cosmos-sdk/x/staking/legacy/v042"
"github.com/cosmos/cosmos-sdk/x/staking/teststaking"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)
func TestStoreMigration(t *testing.T) {
stakingKey := sdk.NewKVStoreKey("staking")
ctx := testutil.DefaultContext(stakingKey, sdk.NewTransientStoreKey("transient_test"))
store := ctx.KVStore(stakingKey)
_, pk1, addr1 := testdata.KeyTestPubAddr()
valAddr1 := sdk.ValAddress(addr1)
val := teststaking.NewValidator(t, valAddr1, pk1)
_, pk1, addr2 := testdata.KeyTestPubAddr()
valAddr2 := sdk.ValAddress(addr2)
_, _, addr3 := testdata.KeyTestPubAddr()
consAddr := sdk.ConsAddress(addr3.String())
_, _, addr4 := testdata.KeyTestPubAddr()
now := time.Now()
// Use dummy value for all keys.
value := []byte("foo")
testCases := []struct {
name string
oldKey []byte
newKey []byte
}{
{
"LastValidatorPowerKey",
v040staking.GetLastValidatorPowerKey(valAddr1),
types.GetLastValidatorPowerKey(valAddr1),
},
{
"LastTotalPowerKey",
v040staking.LastTotalPowerKey,
types.LastTotalPowerKey,
},
{
"ValidatorsKey",
v040staking.GetValidatorKey(valAddr1),
types.GetValidatorKey(valAddr1),
},
{
"ValidatorsByConsAddrKey",
v040staking.GetValidatorByConsAddrKey(consAddr),
types.GetValidatorByConsAddrKey(consAddr),
},
{
"ValidatorsByPowerIndexKey",
v040staking.GetValidatorsByPowerIndexKey(val),
types.GetValidatorsByPowerIndexKey(val),
},
{
"DelegationKey",
v040staking.GetDelegationKey(addr4, valAddr1),
types.GetDelegationKey(addr4, valAddr1),
},
{
"UnbondingDelegationKey",
v040staking.GetUBDKey(addr4, valAddr1),
types.GetUBDKey(addr4, valAddr1),
},
{
"UnbondingDelegationByValIndexKey",
v040staking.GetUBDByValIndexKey(addr4, valAddr1),
types.GetUBDByValIndexKey(addr4, valAddr1),
},
{
"RedelegationKey",
v040staking.GetREDKey(addr4, valAddr1, valAddr2),
types.GetREDKey(addr4, valAddr1, valAddr2),
},
{
"RedelegationByValSrcIndexKey",
v040staking.GetREDByValSrcIndexKey(addr4, valAddr1, valAddr2),
types.GetREDByValSrcIndexKey(addr4, valAddr1, valAddr2),
},
{
"RedelegationByValDstIndexKey",
v040staking.GetREDByValDstIndexKey(addr4, valAddr1, valAddr2),
types.GetREDByValDstIndexKey(addr4, valAddr1, valAddr2),
},
{
"UnbondingQueueKey",
v040staking.GetUnbondingDelegationTimeKey(now),
types.GetUnbondingDelegationTimeKey(now),
},
{
"RedelegationQueueKey",
v040staking.GetRedelegationTimeKey(now),
types.GetRedelegationTimeKey(now),
},
{
"ValidatorQueueKey",
v040staking.GetValidatorQueueKey(now, 4),
types.GetValidatorQueueKey(now, 4),
},
{
"HistoricalInfoKey",
v040staking.GetHistoricalInfoKey(4),
types.GetHistoricalInfoKey(4),
},
}
// Set all the old keys to the store
for _, tc := range testCases {
store.Set(tc.oldKey, value)
}
// Run migrations.
err := v042staking.MigrateStore(ctx, stakingKey)
require.NoError(t, err)
// Make sure the new keys are set and old keys are deleted.
for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
if bytes.Compare(tc.oldKey, tc.newKey) != 0 {
require.Nil(t, store.Get(tc.oldKey))
}
require.Equal(t, value, store.Get(tc.newKey))
})
}
}

View File

@ -138,6 +138,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper)) types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
querier := keeper.Querier{Keeper: am.keeper} querier := keeper.Querier{Keeper: am.keeper}
types.RegisterQueryServer(cfg.QueryServer(), querier) types.RegisterQueryServer(cfg.QueryServer(), querier)
m := keeper.NewMigrator(am.keeper)
cfg.RegisterMigration(types.ModuleName, 1, m.Migrate1to2)
} }
// InitGenesis performs genesis initialization for the staking module. It returns // InitGenesis performs genesis initialization for the staking module. It returns
@ -158,7 +161,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
} }
// ConsensusVersion implements AppModule/ConsensusVersion. // ConsensusVersion implements AppModule/ConsensusVersion.
func (AppModule) ConsensusVersion() uint64 { return 1 } func (AppModule) ConsensusVersion() uint64 { return 2 }
// BeginBlock returns the begin blocker for the staking module. // BeginBlock returns the begin blocker for the staking module.
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) { func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {

View File

@ -44,10 +44,10 @@ required lookups for slashing and validator-set updates. A third special index
throughout each block, unlike the first two indices which mirror the validator throughout each block, unlike the first two indices which mirror the validator
records within a block. records within a block.
- Validators: `0x21 | OperatorAddr -> ProtocolBuffer(validator)` - Validators: `0x21 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(validator)`
- ValidatorsByConsAddr: `0x22 | ConsAddr -> OperatorAddr` - ValidatorsByConsAddr: `0x22 | ConsAddrLen (1 byte) | ConsAddr -> OperatorAddr`
- ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddr -> OperatorAddr` - ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddrLen (1 byte) | OperatorAddr -> OperatorAddr`
- LastValidatorsPower: `0x11 OperatorAddr -> ProtocolBuffer(ConsensusPower)` - LastValidatorsPower: `0x11 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(ConsensusPower)`
`Validators` is the primary index - it ensures that each operator can have only one `Validators` is the primary index - it ensures that each operator can have only one
associated validator, where the public key of that validator can change in the associated validator, where the public key of that validator can change in the
@ -79,7 +79,7 @@ Each validator's state is stored in a `Validator` struct:
Delegations are identified by combining `DelegatorAddr` (the address of the delegator) Delegations are identified by combining `DelegatorAddr` (the address of the delegator)
with the `ValidatorAddr` Delegators are indexed in the store as follows: with the `ValidatorAddr` Delegators are indexed in the store as follows:
- Delegation: `0x31 | DelegatorAddr | ValidatorAddr -> ProtocolBuffer(delegation)` - Delegation: `0x31 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(delegation)`
Stake holders may delegate coins to validators; under this circumstance their Stake holders may delegate coins to validators; under this circumstance their
funds are held in a `Delegation` data structure. It is owned by one funds are held in a `Delegation` data structure. It is owned by one
@ -115,8 +115,8 @@ detected.
`UnbondingDelegation` are indexed in the store as: `UnbondingDelegation` are indexed in the store as:
- UnbondingDelegation: `0x32 | DelegatorAddr | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)` - UnbondingDelegation: `0x32 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)`
- UnbondingDelegationsFromValidator: `0x33 | ValidatorAddr | DelegatorAddr -> nil` - UnbondingDelegationsFromValidator: `0x33 | ValidatorAddrLen (1 byte) | ValidatorAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil`
The first map here is used in queries, to lookup all unbonding delegations for The first map here is used in queries, to lookup all unbonding delegations for
a given delegator, while the second map is used in slashing, to lookup all a given delegator, while the second map is used in slashing, to lookup all
@ -137,9 +137,9 @@ committed by the source validator.
`Redelegation` are indexed in the store as: `Redelegation` are indexed in the store as:
- Redelegations: `0x34 | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)` - Redelegations: `0x34 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)`
- RedelegationsBySrc: `0x35 | ValidatorSrcAddr | ValidatorDstAddr | DelegatorAddr -> nil` - RedelegationsBySrc: `0x35 | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil`
- RedelegationsByDst: `0x36 | ValidatorDstAddr | ValidatorSrcAddr | DelegatorAddr -> nil` - RedelegationsByDst: `0x36 | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | DelegatorAddrLen (1 byte) | DelegatorAddr -> nil`
The first map here is used for queries, to lookup all redelegations for a given The first map here is used for queries, to lookup all redelegations for a given
delegator. The second map is used for slashing based on the `ValidatorSrcAddr`, delegator. The second map is used for slashing based on the `ValidatorSrcAddr`,