Fix 0.39 x/auth Migration Types (#6870)

* types: add coins to JSON

* add migrate test

* finish test

* Add panic

* fix test
This commit is contained in:
Alexander Bezobchuk 2020-07-28 15:18:07 -04:00 committed by GitHub
parent 3ff3e58240
commit 72f6bf0893
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 217 additions and 78 deletions

View File

@ -434,7 +434,7 @@ func NewModuleAccount(baseAccount *BaseAccount, name string, permissions ...stri
}
func (ma ModuleAccount) Validate() error {
if err := validatePermissions(ma.Permissions...); err != nil {
if err := ValidatePermissions(ma.Permissions...); err != nil {
return err
}
@ -476,7 +476,7 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error {
return nil
}
func validatePermissions(permissions ...string) error {
func ValidatePermissions(permissions ...string) error {
for _, perm := range permissions {
if strings.TrimSpace(perm) == "" {
return fmt.Errorf("module permission is empty")

View File

@ -0,0 +1,60 @@
package v039
import (
"fmt"
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
)
// Migrate accepts exported genesis state from v0.38 and migrates it to v0.39
// genesis state.
func Migrate(oldAuthGenState v038auth.GenesisState) GenesisState {
accounts := make(v038auth.GenesisAccounts, len(oldAuthGenState.Accounts))
for i, acc := range oldAuthGenState.Accounts {
switch t := acc.(type) {
case *v038auth.BaseAccount:
accounts[i] = NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence)
case *v038auth.BaseVestingAccount:
accounts[i] = NewBaseVestingAccount(
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
)
case *v038auth.ContinuousVestingAccount:
accounts[i] = NewContinuousVestingAccountRaw(
NewBaseVestingAccount(
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
),
t.StartTime,
)
case *v038auth.DelayedVestingAccount:
accounts[i] = NewDelayedVestingAccountRaw(
NewBaseVestingAccount(
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
t.OriginalVesting, t.DelegatedFree, t.DelegatedVesting, t.EndTime,
),
)
case *v038auth.ModuleAccount:
accounts[i] = NewModuleAccount(
NewBaseAccount(t.Address, t.Coins, t.PubKey, t.AccountNumber, t.Sequence),
t.Name, t.Permissions...,
)
default:
panic(fmt.Sprintf("unexpected account type: %T", acc))
}
}
accounts = v038auth.SanitizeGenesisAccounts(accounts)
if err := v038auth.ValidateGenAccounts(accounts); err != nil {
panic(err)
}
return NewGenesisState(oldAuthGenState.Params, accounts)
}

View File

@ -7,7 +7,6 @@ import (
"bytes"
"errors"
"fmt"
"sort"
"strings"
"github.com/tendermint/tendermint/crypto"
@ -16,6 +15,7 @@ import (
"github.com/cosmos/cosmos-sdk/codec/legacy"
sdk "github.com/cosmos/cosmos-sdk/types"
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34"
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
)
const (
@ -23,25 +23,9 @@ const (
)
type (
// partial interface needed only for amino encoding and sanitization
Account interface {
GetAddress() sdk.AccAddress
GetAccountNumber() uint64
GetCoins() sdk.Coins
SetCoins(sdk.Coins) error
}
GenesisAccount interface {
Account
Validate() error
}
GenesisAccounts []GenesisAccount
GenesisState struct {
Params v034auth.Params `json:"params" yaml:"params"`
Accounts GenesisAccounts `json:"accounts" yaml:"accounts"`
Params v034auth.Params `json:"params" yaml:"params"`
Accounts v038auth.GenesisAccounts `json:"accounts" yaml:"accounts"`
}
BaseAccount struct {
@ -119,7 +103,7 @@ type (
}
)
func NewGenesisState(params v034auth.Params, accounts GenesisAccounts) GenesisState {
func NewGenesisState(params v034auth.Params, accounts v038auth.GenesisAccounts) GenesisState {
return GenesisState{
Params: params,
Accounts: accounts,
@ -187,6 +171,7 @@ func NewBaseVestingAccount(
func (bva BaseVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountJSON{
Address: bva.Address,
Coins: bva.Coins,
PubKey: bva.PubKey,
AccountNumber: bva.AccountNumber,
Sequence: bva.Sequence,
@ -245,6 +230,7 @@ func (cva ContinuousVestingAccount) Validate() error {
func (cva ContinuousVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountJSON{
Address: cva.Address,
Coins: cva.Coins,
PubKey: cva.PubKey,
AccountNumber: cva.AccountNumber,
Sequence: cva.Sequence,
@ -276,6 +262,12 @@ func (cva *ContinuousVestingAccount) UnmarshalJSON(bz []byte) error {
return nil
}
func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount {
return &DelayedVestingAccount{
BaseVestingAccount: bva,
}
}
func (dva DelayedVestingAccount) Validate() error {
return dva.BaseVestingAccount.Validate()
}
@ -283,6 +275,7 @@ func (dva DelayedVestingAccount) Validate() error {
func (dva DelayedVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountJSON{
Address: dva.Address,
Coins: dva.Coins,
PubKey: dva.PubKey,
AccountNumber: dva.AccountNumber,
Sequence: dva.Sequence,
@ -340,6 +333,7 @@ func (pva PeriodicVestingAccount) Validate() error {
func (pva PeriodicVestingAccount) MarshalJSON() ([]byte, error) {
alias := vestingAccountJSON{
Address: pva.Address,
Coins: pva.Coins,
PubKey: pva.PubKey,
AccountNumber: pva.AccountNumber,
Sequence: pva.Sequence,
@ -374,8 +368,16 @@ func (pva *PeriodicVestingAccount) UnmarshalJSON(bz []byte) error {
return nil
}
func NewModuleAccount(baseAccount *BaseAccount, name string, permissions ...string) *ModuleAccount {
return &ModuleAccount{
BaseAccount: baseAccount,
Name: name,
Permissions: permissions,
}
}
func (ma ModuleAccount) Validate() error {
if err := validatePermissions(ma.Permissions...); err != nil {
if err := v038auth.ValidatePermissions(ma.Permissions...); err != nil {
return err
}
@ -383,8 +385,8 @@ func (ma ModuleAccount) Validate() error {
return errors.New("module account name cannot be blank")
}
if !ma.Address.Equals(sdk.AccAddress(crypto.AddressHash([]byte(ma.Name)))) {
return fmt.Errorf("address %s cannot be derived from the module name '%s'", ma.Address, ma.Name)
if x := sdk.AccAddress(crypto.AddressHash([]byte(ma.Name))); !ma.Address.Equals(x) {
return fmt.Errorf("address %s cannot be derived from the module name '%s'; expected: %s", ma.Address, ma.Name, x)
}
return ma.BaseAccount.Validate()
@ -417,54 +419,9 @@ func (ma *ModuleAccount) UnmarshalJSON(bz []byte) error {
return nil
}
func SanitizeGenesisAccounts(genAccounts GenesisAccounts) GenesisAccounts {
sort.Slice(genAccounts, func(i, j int) bool {
return genAccounts[i].GetAccountNumber() < genAccounts[j].GetAccountNumber()
})
for _, acc := range genAccounts {
if err := acc.SetCoins(acc.GetCoins().Sort()); err != nil {
panic(err)
}
}
return genAccounts
}
func ValidateGenAccounts(genAccounts GenesisAccounts) error {
addrMap := make(map[string]bool, len(genAccounts))
for _, acc := range genAccounts {
// check for duplicated accounts
addrStr := acc.GetAddress().String()
if _, ok := addrMap[addrStr]; ok {
return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr)
}
addrMap[addrStr] = true
// check account specific validation
if err := acc.Validate(); err != nil {
return fmt.Errorf("invalid account found in genesis state; address: %s, error: %s", addrStr, err.Error())
}
}
return nil
}
func validatePermissions(permissions ...string) error {
for _, perm := range permissions {
if strings.TrimSpace(perm) == "" {
return fmt.Errorf("module permission is empty")
}
}
return nil
}
func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterInterface((*GenesisAccount)(nil), nil)
cdc.RegisterInterface((*Account)(nil), nil)
cdc.RegisterInterface((*v038auth.GenesisAccount)(nil), nil)
cdc.RegisterInterface((*v038auth.Account)(nil), nil)
cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/BaseAccount", nil)
cdc.RegisterConcrete(&BaseVestingAccount{}, "cosmos-sdk/BaseVestingAccount", nil)
cdc.RegisterConcrete(&ContinuousVestingAccount{}, "cosmos-sdk/ContinuousVestingAccount", nil)

View File

@ -3,6 +3,7 @@ package v040
import (
"fmt"
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39"
)
@ -18,6 +19,6 @@ func Migrate(authGenState v039auth.GenesisState) v039auth.GenesisState {
}
}
authGenState.Accounts = v039auth.SanitizeGenesisAccounts(authGenState.Accounts)
authGenState.Accounts = v038auth.SanitizeGenesisAccounts(authGenState.Accounts)
return authGenState
}

View File

@ -3,14 +3,15 @@ package v040_test
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/cosmos/cosmos-sdk/codec"
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34"
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39"
v040 "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_40"
"github.com/stretchr/testify/require"
)
func TestMigrate(t *testing.T) {
@ -36,7 +37,7 @@ func TestMigrate(t *testing.T) {
SigVerifyCostED25519: 10,
SigVerifyCostSecp256k1: 10,
},
Accounts: v039auth.GenesisAccounts{acc1, vaac},
Accounts: v038auth.GenesisAccounts{acc1, vaac},
}
migrated := v040.Migrate(gs)

View File

@ -35,7 +35,7 @@ func TestMigrate(t *testing.T) {
SendEnabled: true,
}
authGenState := v039auth.GenesisState{
Accounts: v039auth.GenesisAccounts{acc1, vaac},
Accounts: v038auth.GenesisAccounts{acc1, vaac},
}
migrated := v040bank.Migrate(bankGenState, authGenState)

View File

@ -27,7 +27,7 @@ func Migrate(appState types.AppMap) types.AppMap {
v038Codec.MustUnmarshalJSON(appState[v038auth.ModuleName], &authGenState)
delete(appState, v038auth.ModuleName) // delete old key in case the name changed
appState[v039auth.ModuleName] = v039Codec.MustMarshalJSON(authGenState)
appState[v039auth.ModuleName] = v039Codec.MustMarshalJSON(v039auth.Migrate(authGenState))
}
return appState

View File

@ -0,0 +1,120 @@
package v039_test
import (
"testing"
"github.com/stretchr/testify/require"
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
v039auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_39"
v039 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_39"
"github.com/cosmos/cosmos-sdk/x/genutil/types"
)
var genAuthState = []byte(`{
"params": {
"max_memo_characters": "10",
"tx_sig_limit": "10",
"tx_size_cost_per_byte": "10",
"sig_verify_cost_ed25519": "10",
"sig_verify_cost_secp256k1": "10"
},
"accounts": [
{
"type": "cosmos-sdk/BaseAccount",
"value": {
"address": "cosmos19hz3ee9e3lj9mne4jggj3v8hxjrpre22jukj9y",
"coins": [
{
"denom": "stake",
"amount": "400000"
}
],
"public_key": "cosmospub1addwnpepqtezq4ajkevh724ls45zp72x70rj8mhszqf5pxcaahazm8trv490swlf404",
"account_number": 1,
"sequence": 1
}
},
{
"type": "cosmos-sdk/ModuleAccount",
"value": {
"address": "cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh",
"coins": [
{
"denom": "stake",
"amount": "400000000"
}
],
"public_key": "",
"account_number": 2,
"sequence": 4,
"name": "bonded_tokens_pool",
"permissions": [
"burner",
"staking"
]
}
},
{
"type": "cosmos-sdk/ContinuousVestingAccount",
"value": {
"address": "cosmos1vtzxzyjv506dvhl9pa527xsugf5gez4fnqxq0n",
"coins": [
{
"denom": "stake",
"amount": "10000205"
}
],
"public_key": "cosmospub1addwnpepqdxrk48q89xlmnzrr5nkssle05tkp73uknevzaavm53c02v26vlyzz6vcdh",
"account_number": 3,
"sequence": 5,
"original_vesting": [
{
"denom": "stake",
"amount": "10000205"
}
],
"delegated_free": [],
"delegated_vesting": [],
"end_time": 1596125048,
"start_time": 1595952248
}
},
{
"type": "cosmos-sdk/DelayedVestingAccount",
"value": {
"address": "cosmos1prxkcqclweqa0g28p7vmf6z78ghyeckm4qak30",
"coins": [
{
"denom": "stake",
"amount": "10000205"
}
],
"public_key": "cosmospub1addwnpepqwewcad349e2yw3weatf8lzfyv5cd6am9jkk4ajach3f568k6gg47nls3p8",
"account_number": 4,
"sequence": 15,
"original_vesting": [
{
"denom": "stake",
"amount": "10000205"
}
],
"delegated_free": [],
"delegated_vesting": [],
"end_time": 1596125048
}
}
]
}`)
var expectedGenAuthState = []byte(`{"params":{"max_memo_characters":"10","tx_sig_limit":"10","tx_size_cost_per_byte":"10","sig_verify_cost_ed25519":"10","sig_verify_cost_secp256k1":"10"},"accounts":[{"type":"cosmos-sdk/BaseAccount","value":{"address":"cosmos19hz3ee9e3lj9mne4jggj3v8hxjrpre22jukj9y","coins":[{"denom":"stake","amount":"400000"}],"public_key":{"type":"tendermint/PubKeySecp256k1","value":"AvIgV7K2WX8qv4VoIPlG88cj7vAQE0CbHe36LZ1jZUr4"},"account_number":"1","sequence":"1"}},{"type":"cosmos-sdk/ModuleAccount","value":{"address":"cosmos1fl48vsnmsdzcv85q5d2q4z5ajdha8yu34mf0eh","coins":[{"denom":"stake","amount":"400000000"}],"public_key":"","account_number":"2","sequence":"4","name":"bonded_tokens_pool","permissions":["burner","staking"]}},{"type":"cosmos-sdk/ContinuousVestingAccount","value":{"address":"cosmos1vtzxzyjv506dvhl9pa527xsugf5gez4fnqxq0n","coins":[{"denom":"stake","amount":"10000205"}],"public_key":{"type":"tendermint/PubKeySecp256k1","value":"A0w7VOA5Tf3MQx0naEP5fRdg+jy08sF3rN0jh6mK0z5B"},"account_number":"3","sequence":"5","original_vesting":[{"denom":"stake","amount":"10000205"}],"delegated_free":[],"delegated_vesting":[],"end_time":"1596125048","start_time":"1595952248"}},{"type":"cosmos-sdk/DelayedVestingAccount","value":{"address":"cosmos1prxkcqclweqa0g28p7vmf6z78ghyeckm4qak30","coins":[{"denom":"stake","amount":"10000205"}],"public_key":{"type":"tendermint/PubKeySecp256k1","value":"A7LsdbGpcqI6Ls9Wk/xJIymG67ssrWr2XcXimmj20hFf"},"account_number":"4","sequence":"15","original_vesting":[{"denom":"stake","amount":"10000205"}],"delegated_free":[],"delegated_vesting":[],"end_time":"1596125048"}}]}`)
func TestMigrate(t *testing.T) {
genesis := types.AppMap{
v038auth.ModuleName: genAuthState,
}
var migrated types.AppMap
require.NotPanics(t, func() { migrated = v039.Migrate(genesis) })
require.Equal(t, string(expectedGenAuthState), string(migrated[v039auth.ModuleName]))
}