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:
parent
eeb3eabdc6
commit
ba74a7c737
|
@ -11,8 +11,27 @@ import (
|
|||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||
dbm "github.com/tendermint/tm-db"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"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) {
|
||||
|
@ -52,11 +71,33 @@ func TestGetMaccPerms(t *testing.T) {
|
|||
func TestRunMigrations(t *testing.T) {
|
||||
db := dbm.NewMemDB()
|
||||
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())
|
||||
|
||||
// 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 {
|
||||
name string
|
||||
moduleName string
|
||||
|
@ -115,12 +156,30 @@ func TestRunMigrations(t *testing.T) {
|
|||
}
|
||||
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(
|
||||
app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}),
|
||||
module.MigrationMap{
|
||||
"auth": 1, "authz": 1, "bank": 1, "staking": 1, "mint": 1, "distribution": 1,
|
||||
"slashing": 1, "gov": 1, "params": 1, "ibc": 1, "upgrade": 1, "vesting": 1,
|
||||
"feegrant": 1, "transfer": 1, "evidence": 1, "crisis": 1, "genutil": 1, "capability": 1,
|
||||
"bank": 1,
|
||||
"auth": auth.AppModule{}.ConsensusVersion(),
|
||||
"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 {
|
||||
|
|
|
@ -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.
|
||||
type MigrationHandler func(store sdk.Context) error
|
||||
type MigrationHandler func(sdk.Context) error
|
||||
|
||||
// MigrationMap is a map of moduleName -> version, where version denotes the
|
||||
// version from which we should perform the migration for each module.
|
||||
|
|
|
@ -5,16 +5,17 @@ import (
|
|||
v042 "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042"
|
||||
)
|
||||
|
||||
// MigrationKeeper is an interface that the keeper implements for handling
|
||||
// in-place store migrations.
|
||||
type MigrationKeeper interface {
|
||||
// Migrate1 migrates the store from version 1 to 2.
|
||||
Migrate1(ctx sdk.Context) error
|
||||
// Migrator is a struct for handling in-place store migrations.
|
||||
type Migrator struct {
|
||||
keeper BaseKeeper
|
||||
}
|
||||
|
||||
var _ MigrationKeeper = (*BaseKeeper)(nil)
|
||||
|
||||
// Migrate1 implements MigrationKeeper.Migrate1 method.
|
||||
func (keeper BaseKeeper) Migrate1(ctx sdk.Context) error {
|
||||
return v042.MigrateStore(ctx, keeper.storeKey)
|
||||
// NewMigrator returns a new Migrator.
|
||||
func NewMigrator(keeper BaseKeeper) 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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
import (
|
||||
|
|
|
@ -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)...)
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
v040auth "github.com/cosmos/cosmos-sdk/x/auth/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
|
||||
|
@ -27,7 +28,7 @@ func MigrateStore(ctx sdk.Context, storeKey sdk.StoreKey) error {
|
|||
for ; oldStoreIter.Valid(); oldStoreIter.Next() {
|
||||
addr := v040bank.AddressFromBalancesStore(oldStoreIter.Key())
|
||||
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.
|
||||
store.Set(newStoreKey, oldStoreIter.Value())
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
v040bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v040"
|
||||
v042bank "github.com/cosmos/cosmos-sdk/x/bank/legacy/v042"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||
)
|
||||
|
||||
func TestStoreMigration(t *testing.T) {
|
||||
|
@ -27,7 +28,7 @@ func TestStoreMigration(t *testing.T) {
|
|||
err := v042bank.MigrateStore(ctx, bankKey)
|
||||
require.NoError(t, err)
|
||||
|
||||
newKey := append(v042bank.CreateAccountBalancesPrefix(addr), denom...)
|
||||
newKey := append(types.CreateAccountBalancesPrefix(addr), denom...)
|
||||
// -7 because we replaced "balances" with 0x02,
|
||||
// +1 because we added length-prefix to address.
|
||||
require.Equal(t, len(oldKey)-7+1, len(newKey))
|
||||
|
|
|
@ -98,9 +98,9 @@ type AppModule struct {
|
|||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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...)
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package v040
|
||||
|
||||
// Default parameter values
|
||||
const (
|
||||
ModuleName = "distribution"
|
||||
)
|
|
@ -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())
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -141,6 +141,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
|
|||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(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
|
||||
|
@ -160,7 +163,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
|
|||
}
|
||||
|
||||
// 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.
|
||||
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {
|
||||
|
|
|
@ -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
|
||||
`sdk.Coins` which are non-decimal.
|
||||
|
||||
- FeePool: `0x00 -> ProtocolBuffer(FeePool)`
|
||||
- FeePool: `0x00 -> ProtocolBuffer(FeePool)`
|
||||
|
||||
```go
|
||||
// coins with decimal
|
||||
|
@ -33,12 +33,12 @@ type DecCoin struct {
|
|||
|
||||
Validator distribution information for the relevant validator is updated each time:
|
||||
|
||||
1. delegation amount to a validator is updated,
|
||||
2. a validator successfully proposes a block and receives a reward,
|
||||
3. any delegator withdraws from a validator, or
|
||||
4. the validator withdraws it's commission.
|
||||
1. delegation amount to a validator is updated,
|
||||
2. a validator successfully proposes a block and receives a reward,
|
||||
3. any delegator withdraws from a validator, or
|
||||
4. the validator withdraws it's commission.
|
||||
|
||||
- ValidatorDistInfo: `0x02 | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)`
|
||||
- ValidatorDistInfo: `0x02 | ValOperatorAddrLen (1 byte) | ValOperatorAddr -> ProtocolBuffer(validatorDistribution)`
|
||||
|
||||
```go
|
||||
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
|
||||
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
|
||||
type DelegationDistInfo struct {
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package v040
|
||||
|
||||
// Default parameter values
|
||||
const (
|
||||
ModuleName = "gov"
|
||||
)
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -157,6 +157,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
|
|||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(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
|
||||
|
@ -176,7 +179,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
|
|||
}
|
||||
|
||||
// ConsensusVersion implements AppModule/ConsensusVersion.
|
||||
func (AppModule) ConsensusVersion() uint64 { return 1 }
|
||||
func (AppModule) ConsensusVersion() uint64 { return 2 }
|
||||
|
||||
// BeginBlock performs a no-op.
|
||||
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) {}
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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...)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package v040
|
||||
|
||||
const (
|
||||
ModuleName = "slashing"
|
||||
)
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -139,6 +139,9 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc *codec.LegacyAmino) sd
|
|||
func (am AppModule) RegisterServices(cfg module.Configurator) {
|
||||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(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
|
||||
|
|
|
@ -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`.
|
||||
It is indexed in the store as follows:
|
||||
|
||||
- ValidatorSigningInfo: ` 0x01 | ConsAddress -> ProtocolBuffer(ValSigningInfo)`
|
||||
- MissedBlocksBitArray: ` 0x02 | ConsAddress | LittleEndianUint64(signArrayIndex) -> VarInt(didMiss)` (varint is a number encoding format)
|
||||
- ValidatorSigningInfo: ` 0x01 | ConsAddrLen (1 byte) | ConsAddress -> ProtocolBuffer(ValSigningInfo)`
|
||||
- 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
|
||||
validator based on the validator's consensus address.
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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))...)
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
package v040
|
||||
|
||||
const (
|
||||
ModuleName = "staking"
|
||||
)
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
})
|
||||
}
|
||||
}
|
|
@ -138,6 +138,9 @@ func (am AppModule) RegisterServices(cfg module.Configurator) {
|
|||
types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
|
||||
querier := keeper.Querier{Keeper: am.keeper}
|
||||
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
|
||||
|
@ -158,7 +161,7 @@ func (am AppModule) ExportGenesis(ctx sdk.Context, cdc codec.JSONMarshaler) json
|
|||
}
|
||||
|
||||
// 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.
|
||||
func (am AppModule) BeginBlock(ctx sdk.Context, _ abci.RequestBeginBlock) {
|
||||
|
|
|
@ -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
|
||||
records within a block.
|
||||
|
||||
- Validators: `0x21 | OperatorAddr -> ProtocolBuffer(validator)`
|
||||
- ValidatorsByConsAddr: `0x22 | ConsAddr -> OperatorAddr`
|
||||
- ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddr -> OperatorAddr`
|
||||
- LastValidatorsPower: `0x11 OperatorAddr -> ProtocolBuffer(ConsensusPower)`
|
||||
- Validators: `0x21 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(validator)`
|
||||
- ValidatorsByConsAddr: `0x22 | ConsAddrLen (1 byte) | ConsAddr -> OperatorAddr`
|
||||
- ValidatorsByPower: `0x23 | BigEndian(ConsensusPower) | OperatorAddrLen (1 byte) | OperatorAddr -> OperatorAddr`
|
||||
- LastValidatorsPower: `0x11 | OperatorAddrLen (1 byte) | OperatorAddr -> ProtocolBuffer(ConsensusPower)`
|
||||
|
||||
`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
|
||||
|
@ -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)
|
||||
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
|
||||
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: `0x32 | DelegatorAddr | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)`
|
||||
- UnbondingDelegationsFromValidator: `0x33 | ValidatorAddr | DelegatorAddr -> nil`
|
||||
- UnbondingDelegation: `0x32 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorAddr -> ProtocolBuffer(unbondingDelegation)`
|
||||
- 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
|
||||
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:
|
||||
|
||||
- Redelegations: `0x34 | DelegatorAddr | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)`
|
||||
- RedelegationsBySrc: `0x35 | ValidatorSrcAddr | ValidatorDstAddr | DelegatorAddr -> nil`
|
||||
- RedelegationsByDst: `0x36 | ValidatorDstAddr | ValidatorSrcAddr | DelegatorAddr -> nil`
|
||||
- Redelegations: `0x34 | DelegatorAddrLen (1 byte) | DelegatorAddr | ValidatorAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddr -> ProtocolBuffer(redelegation)`
|
||||
- RedelegationsBySrc: `0x35 | ValidatorSrcAddrLen (1 byte) | ValidatorSrcAddr | ValidatorDstAddrLen (1 byte) | ValidatorDstAddr | DelegatorAddrLen (1 byte) | 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
|
||||
delegator. The second map is used for slashing based on the `ValidatorSrcAddr`,
|
||||
|
|
Loading…
Reference in New Issue