diff --git a/x/auth/legacy/v0_38/types.go b/x/auth/legacy/v0_38/types.go index ac62694e7..b7004a408 100644 --- a/x/auth/legacy/v0_38/types.go +++ b/x/auth/legacy/v0_38/types.go @@ -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") diff --git a/x/auth/legacy/v0_39/migrate.go b/x/auth/legacy/v0_39/migrate.go new file mode 100644 index 000000000..410283dc9 --- /dev/null +++ b/x/auth/legacy/v0_39/migrate.go @@ -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) +} diff --git a/x/auth/legacy/v0_39/types.go b/x/auth/legacy/v0_39/types.go index 55ecec233..9de38e6d6 100644 --- a/x/auth/legacy/v0_39/types.go +++ b/x/auth/legacy/v0_39/types.go @@ -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) diff --git a/x/auth/legacy/v0_40/migrate.go b/x/auth/legacy/v0_40/migrate.go index cf25525d1..1e1b7fea4 100644 --- a/x/auth/legacy/v0_40/migrate.go +++ b/x/auth/legacy/v0_40/migrate.go @@ -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 } diff --git a/x/auth/legacy/v0_40/migrate_test.go b/x/auth/legacy/v0_40/migrate_test.go index 879805c3e..f60f3507a 100644 --- a/x/auth/legacy/v0_40/migrate_test.go +++ b/x/auth/legacy/v0_40/migrate_test.go @@ -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) diff --git a/x/bank/legacy/v0_40/migrate_test.go b/x/bank/legacy/v0_40/migrate_test.go index e51909702..10b245c5e 100644 --- a/x/bank/legacy/v0_40/migrate_test.go +++ b/x/bank/legacy/v0_40/migrate_test.go @@ -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) diff --git a/x/genutil/legacy/v0_39/migrate.go b/x/genutil/legacy/v0_39/migrate.go index 0452b6dea..f1d1b45d5 100644 --- a/x/genutil/legacy/v0_39/migrate.go +++ b/x/genutil/legacy/v0_39/migrate.go @@ -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 diff --git a/x/genutil/legacy/v0_39/migrate_test.go b/x/genutil/legacy/v0_39/migrate_test.go new file mode 100644 index 000000000..d6f68a000 --- /dev/null +++ b/x/genutil/legacy/v0_39/migrate_test.go @@ -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])) +}