Merge PR #5017: ADR 011: Generalize Genesis Accounts Implementation
This commit is contained in:
parent
e660adc6e5
commit
ed6366679c
12
CHANGELOG.md
12
CHANGELOG.md
@ -37,6 +37,14 @@ Ref: https://keepachangelog.com/en/1.0.0/
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### State Machine Breaking
|
||||
|
||||
* (genesis) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/genaccounts` module has been
|
||||
deprecated and all components removed except the `legacy/` package. This requires changes to the
|
||||
genesis state. Namely, `accounts` now exist under `app_state.auth.accounts`. The corresponding migration
|
||||
logic has been implemented for v0.38 target version. Applications can migrate via:
|
||||
`$ {appd} migrate v0.38 genesis.json`.
|
||||
|
||||
### API Breaking Changes
|
||||
|
||||
* (store) [\#4748](https://github.com/cosmos/cosmos-sdk/pull/4748) The `CommitMultiStore` interface
|
||||
@ -45,6 +53,8 @@ have this method perform a no-op.
|
||||
* (modules) [\#4665](https://github.com/cosmos/cosmos-sdk/issues/4665) Refactored `x/gov` module structure and dev-UX:
|
||||
* Prepare for module spec integration
|
||||
* Update gov keys to use big endian encoding instead of little endian
|
||||
* (modules) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/genaccounts` module has been
|
||||
deprecated and all components removed except the `legacy/` package.
|
||||
|
||||
### Client Breaking Changes
|
||||
|
||||
@ -68,6 +78,8 @@ and tx hash will be returned for specific Tendermint errors:
|
||||
|
||||
### Improvements
|
||||
|
||||
* (modules) [\#5017](https://github.com/cosmos/cosmos-sdk/pull/5017) The `x/auth` package now supports
|
||||
generalized genesis accounts through the `GenesisAccount` interface.
|
||||
* (modules) [\#4762](https://github.com/cosmos/cosmos-sdk/issues/4762) Deprecate remove and add permissions in ModuleAccount.
|
||||
* (modules) [\#4760](https://github.com/cosmos/cosmos-sdk/issues/4760) update `x/auth` to match module spec.
|
||||
* (modules) [\#4814](https://github.com/cosmos/cosmos-sdk/issues/4814) Add security contact to Validator description.
|
||||
|
||||
@ -45,15 +45,14 @@ func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) {
|
||||
func ExportGenesis(ctx sdk.Context, ak AccountKeeper) GenesisState {
|
||||
params := ak.GetParams(ctx)
|
||||
|
||||
accounts := ak.GetAllAccounts(ctx)
|
||||
// convert accounts to []GenesisAccounts type
|
||||
genAccounts := make([]GenesisAccounts, len(accounts))
|
||||
for i := range accounts {
|
||||
ga := accounts[i].(GenesisAccount) // will panic if an account doesn't implement GenesisAccount
|
||||
genAccounts[i] = ga
|
||||
}
|
||||
var genAccounts []exported.GenesisAccount
|
||||
ak.IterateAccounts(ctx, func(account exported.Account) bool {
|
||||
genAccount := account.(exported.GenesisAccount)
|
||||
genAccounts = append(genAccounts, genAccount)
|
||||
return false
|
||||
})
|
||||
|
||||
return NewGenesisState(params, accounts)
|
||||
return NewGenesisState(params, genAccounts)
|
||||
}
|
||||
```
|
||||
|
||||
@ -64,11 +63,11 @@ The `auth` codec must have all custom account types registered to marshal them.
|
||||
An example custom account definition:
|
||||
|
||||
```go
|
||||
import authTypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
import authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
// Register the module account type with the auth module codec so it can decode module accounts stored in a genesis file
|
||||
func init() {
|
||||
authTypes.RegisterAccountTypeCodec(ModuleAccount{}, "cosmos-sdk/ModuleAccount")
|
||||
authtypes.RegisterAccountTypeCodec(ModuleAccount{}, "cosmos-sdk/ModuleAccount")
|
||||
}
|
||||
|
||||
type ModuleAccount struct {
|
||||
|
||||
@ -18,7 +18,6 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
@ -43,9 +42,9 @@ var (
|
||||
// non-dependant module elements, such as codec registration
|
||||
// and genesis verification.
|
||||
ModuleBasics = module.NewBasicManager(
|
||||
genaccounts.AppModuleBasic{},
|
||||
genutil.AppModuleBasic{},
|
||||
auth.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
genutil.AppModuleBasic{},
|
||||
bank.AppModuleBasic{},
|
||||
staking.AppModuleBasic{},
|
||||
mint.AppModuleBasic{},
|
||||
@ -55,7 +54,6 @@ var (
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
nft.AppModuleBasic{},
|
||||
supply.AppModuleBasic{},
|
||||
)
|
||||
|
||||
// module account permissions
|
||||
@ -178,7 +176,6 @@ func NewSimApp(
|
||||
// NOTE: Any module instantiated in the module manager that is later modified
|
||||
// must be passed by reference here.
|
||||
app.mm = module.NewManager(
|
||||
genaccounts.NewAppModule(app.AccountKeeper),
|
||||
genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx),
|
||||
auth.NewAppModule(app.AccountKeeper),
|
||||
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
|
||||
@ -202,8 +199,8 @@ func NewSimApp(
|
||||
// NOTE: The genutils moodule must occur after staking so that pools are
|
||||
// properly initialized with tokens from genesis accounts.
|
||||
app.mm.SetOrderInitGenesis(
|
||||
genaccounts.ModuleName, distr.ModuleName, staking.ModuleName,
|
||||
auth.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName,
|
||||
auth.ModuleName, distr.ModuleName, staking.ModuleName,
|
||||
bank.ModuleName, slashing.ModuleName, gov.ModuleName,
|
||||
mint.ModuleName, supply.ModuleName, crisis.ModuleName, nft.ModuleName,
|
||||
genutil.ModuleName,
|
||||
)
|
||||
@ -216,7 +213,6 @@ func NewSimApp(
|
||||
// NOTE: this is not required apps that don't use the simulator for fuzz testing
|
||||
// transactions
|
||||
app.sm = module.NewSimulationManager(
|
||||
genaccounts.NewAppModule(app.AccountKeeper),
|
||||
auth.NewAppModule(app.AccountKeeper),
|
||||
bank.NewAppModule(app.BankKeeper, app.AccountKeeper),
|
||||
supply.NewAppModule(app.SupplyKeeper, app.AccountKeeper),
|
||||
|
||||
52
simapp/genesis_account.go
Normal file
52
simapp/genesis_account.go
Normal file
@ -0,0 +1,52 @@
|
||||
package simapp
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
var _ authexported.GenesisAccount = (*SimGenesisAccount)(nil)
|
||||
|
||||
// SimGenesisAccount defines a type that implements the GenesisAccount interface
|
||||
// to be used for simulation accounts in the genesis state.
|
||||
type SimGenesisAccount struct {
|
||||
*authtypes.BaseAccount
|
||||
|
||||
// vesting account fields
|
||||
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // total vesting coins upon initialization
|
||||
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // delegated vested coins at time of delegation
|
||||
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // delegated vesting coins at time of delegation
|
||||
StartTime int64 `json:"start_time" yaml:"start_time"` // vesting start time (UNIX Epoch time)
|
||||
EndTime int64 `json:"end_time" yaml:"end_time"` // vesting end time (UNIX Epoch time)
|
||||
|
||||
// module account fields
|
||||
ModuleName string `json:"module_name" yaml:"module_name"` // name of the module account
|
||||
ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"` // permissions of module account
|
||||
}
|
||||
|
||||
// Validate checks for errors on the vesting and module account parameters
|
||||
func (sga SimGenesisAccount) Validate() error {
|
||||
if !sga.OriginalVesting.IsZero() {
|
||||
if sga.OriginalVesting.IsAnyGT(sga.Coins) {
|
||||
return errors.New("vesting amount cannot be greater than total amount")
|
||||
}
|
||||
if sga.StartTime >= sga.EndTime {
|
||||
return errors.New("vesting start-time cannot be before end-time")
|
||||
}
|
||||
}
|
||||
|
||||
if sga.ModuleName != "" {
|
||||
ma := supply.ModuleAccount{
|
||||
BaseAccount: sga.BaseAccount, Name: sga.ModuleName, Permissions: sga.ModulePermissions,
|
||||
}
|
||||
if err := ma.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return sga.BaseAccount.Validate()
|
||||
}
|
||||
98
simapp/genesis_account_test.go
Normal file
98
simapp/genesis_account_test.go
Normal file
@ -0,0 +1,98 @@
|
||||
package simapp_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
)
|
||||
|
||||
func TestSimGenesisAccountValidate(t *testing.T) {
|
||||
pubkey := secp256k1.GenPrivKey().PubKey()
|
||||
addr := sdk.AccAddress(pubkey.Address())
|
||||
|
||||
vestingStart := time.Now().UTC()
|
||||
|
||||
coins := sdk.NewCoins(sdk.NewInt64Coin("test", 1000))
|
||||
baseAcc := authtypes.NewBaseAccount(addr, nil, pubkey, 0, 0)
|
||||
require.NoError(t, baseAcc.SetCoins(coins))
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
sga simapp.SimGenesisAccount
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
"valid basic account",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: baseAcc,
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"invalid basic account with mismatching address/pubkey",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(addr, nil, secp256k1.GenPrivKey().PubKey(), 0, 0),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid basic account with module name",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: authtypes.NewBaseAccount(sdk.AccAddress(crypto.AddressHash([]byte("testmod"))), nil, nil, 0, 0),
|
||||
ModuleName: "testmod",
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid basic account with invalid module name/pubkey pair",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: baseAcc,
|
||||
ModuleName: "testmod",
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid basic account with valid vesting attributes",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: baseAcc,
|
||||
OriginalVesting: coins,
|
||||
StartTime: vestingStart.Unix(),
|
||||
EndTime: vestingStart.Add(1 * time.Hour).Unix(),
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"valid basic account with invalid vesting end time",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: baseAcc,
|
||||
OriginalVesting: coins,
|
||||
StartTime: vestingStart.Add(2 * time.Hour).Unix(),
|
||||
EndTime: vestingStart.Add(1 * time.Hour).Unix(),
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"valid basic account with invalid original vesting coins",
|
||||
simapp.SimGenesisAccount{
|
||||
BaseAccount: baseAcc,
|
||||
OriginalVesting: coins.Add(coins),
|
||||
StartTime: vestingStart.Unix(),
|
||||
EndTime: vestingStart.Add(1 * time.Hour).Unix(),
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
require.Equal(t, tc.wantErr, tc.sga.Validate() != nil)
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -12,7 +12,7 @@ import (
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
@ -126,9 +126,12 @@ func AppStateFromGenesisFileFn(r *rand.Rand, cdc *codec.Codec, genesisFile strin
|
||||
var appState GenesisState
|
||||
cdc.MustUnmarshalJSON(genesis.AppState, &appState)
|
||||
|
||||
accounts := genaccounts.GetGenesisStateFromAppState(cdc, appState)
|
||||
var authGenesis auth.GenesisState
|
||||
if appState[auth.ModuleName] != nil {
|
||||
cdc.MustUnmarshalJSON(appState[auth.ModuleName], &authGenesis)
|
||||
}
|
||||
|
||||
for _, acc := range accounts {
|
||||
for _, acc := range authGenesis.Accounts {
|
||||
// Pick a random private key, since we don't know the actual key
|
||||
// This should be fine as it's only used for mock Tendermint validators
|
||||
// and these keys are never actually used to sign by mock Tendermint.
|
||||
@ -140,7 +143,7 @@ func AppStateFromGenesisFileFn(r *rand.Rand, cdc *codec.Codec, genesisFile strin
|
||||
privKey := secp256k1.GenPrivKeySecp256k1(privkeySeed)
|
||||
|
||||
// create simulator accounts
|
||||
simAcc := simulation.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: acc.Address}
|
||||
simAcc := simulation.Account{PrivKey: privKey, PubKey: privKey.PubKey(), Address: acc.GetAddress()}
|
||||
newAccs = append(newAccs, simAcc)
|
||||
}
|
||||
|
||||
|
||||
@ -15,7 +15,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
@ -45,13 +45,17 @@ func Setup(isCheckTx bool) *SimApp {
|
||||
|
||||
// SetupWithGenesisAccounts initializes a new SimApp with the passed in
|
||||
// genesis accounts.
|
||||
func SetupWithGenesisAccounts(genAccs genaccounts.GenesisAccounts) *SimApp {
|
||||
func SetupWithGenesisAccounts(genAccs []authexported.GenesisAccount) *SimApp {
|
||||
db := dbm.NewMemDB()
|
||||
app := NewSimApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
|
||||
|
||||
// initialize the chain with the passed in genesis accounts
|
||||
genesisState := NewDefaultGenesisState()
|
||||
genesisState = genaccounts.SetGenesisStateInAppState(app.Codec(), genesisState, genaccounts.GenesisState(genAccs))
|
||||
|
||||
authGenesis := auth.NewGenesisState(auth.DefaultParams(), genAccs)
|
||||
genesisStateBz := app.cdc.MustMarshalJSON(authGenesis)
|
||||
genesisState[auth.ModuleName] = genesisStateBz
|
||||
|
||||
stateBytes, err := codec.MarshalJSONIndent(app.cdc, genesisState)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
@ -51,9 +51,11 @@ var (
|
||||
NewDelayedVestingAccount = types.NewDelayedVestingAccount
|
||||
NewAccountRetriever = types.NewAccountRetriever
|
||||
RegisterCodec = types.RegisterCodec
|
||||
RegisterAccountTypeCodec = types.RegisterAccountTypeCodec
|
||||
NewGenesisState = types.NewGenesisState
|
||||
DefaultGenesisState = types.DefaultGenesisState
|
||||
ValidateGenesis = types.ValidateGenesis
|
||||
Sanitize = types.Sanitize
|
||||
AddressStoreKey = types.AddressStoreKey
|
||||
NewParams = types.NewParams
|
||||
ParamKeyTable = types.ParamKeyTable
|
||||
|
||||
@ -57,3 +57,9 @@ type VestingAccount interface {
|
||||
GetDelegatedFree() sdk.Coins
|
||||
GetDelegatedVesting() sdk.Coins
|
||||
}
|
||||
|
||||
// GenesisAccount defines a genesis account that embeds an Account with validation capabilities.
|
||||
type GenesisAccount interface {
|
||||
Account
|
||||
Validate() error
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package auth
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
// InitGenesis - Init store state from genesis data
|
||||
@ -10,10 +11,24 @@ import (
|
||||
// a genesis port script to the new fee collector account
|
||||
func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) {
|
||||
ak.SetParams(ctx, data.Params)
|
||||
data.Accounts = Sanitize(data.Accounts)
|
||||
|
||||
for _, a := range data.Accounts {
|
||||
acc := ak.NewAccount(ctx, a)
|
||||
ak.SetAccount(ctx, acc)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis returns a GenesisState for a given context and keeper
|
||||
func ExportGenesis(ctx sdk.Context, ak AccountKeeper) GenesisState {
|
||||
params := ak.GetParams(ctx)
|
||||
return NewGenesisState(params)
|
||||
|
||||
var genAccounts []exported.GenesisAccount
|
||||
ak.IterateAccounts(ctx, func(account exported.Account) bool {
|
||||
genAccount := account.(exported.GenesisAccount)
|
||||
genAccounts = append(genAccounts, genAccount)
|
||||
return false
|
||||
})
|
||||
|
||||
return NewGenesisState(params, genAccounts)
|
||||
}
|
||||
|
||||
13
x/auth/legacy/v0_38/migrate.go
Normal file
13
x/auth/legacy/v0_38/migrate.go
Normal file
@ -0,0 +1,13 @@
|
||||
package v038
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_36"
|
||||
)
|
||||
|
||||
// Migrate accepts exported genesis state from v0.34 and migrates it to v0.38
|
||||
// genesis state.
|
||||
func Migrate(oldGenState v036auth.GenesisState, accounts json.RawMessage) GenesisState {
|
||||
return NewGenesisState(oldGenState.Params, accounts)
|
||||
}
|
||||
124
x/auth/legacy/v0_38/migrate_test.go
Normal file
124
x/auth/legacy/v0_38/migrate_test.go
Normal file
@ -0,0 +1,124 @@
|
||||
package v038
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34"
|
||||
v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_36"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestMigrate(t *testing.T) {
|
||||
var genesisState GenesisState
|
||||
|
||||
params := v034auth.Params{
|
||||
MaxMemoCharacters: 10,
|
||||
TxSigLimit: 10,
|
||||
TxSizeCostPerByte: 10,
|
||||
SigVerifyCostED25519: 10,
|
||||
SigVerifyCostSecp256k1: 10,
|
||||
}
|
||||
rawAccounts := `[
|
||||
{
|
||||
"address": "cosmos1dfp05pasnts7a4lupn889vptjtrxzkk5f7027f",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "node0token",
|
||||
"amount": "1000000000"
|
||||
},
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "500000000"
|
||||
}
|
||||
],
|
||||
"sequence_number": "0",
|
||||
"account_number": "0",
|
||||
"original_vesting": [],
|
||||
"delegated_free": [],
|
||||
"delegated_vesting": [],
|
||||
"start_time": "0",
|
||||
"end_time": "0",
|
||||
"module_name": "",
|
||||
"module_permissions": null
|
||||
},
|
||||
{
|
||||
"address": "cosmos1f6dangl9ggdhuvkcwhswserr8fzra6vfzfjvh2",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "node1token",
|
||||
"amount": "1000000000"
|
||||
},
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "500000000"
|
||||
}
|
||||
],
|
||||
"sequence_number": "0",
|
||||
"account_number": "0",
|
||||
"original_vesting": [],
|
||||
"delegated_free": [],
|
||||
"delegated_vesting": [],
|
||||
"start_time": "0",
|
||||
"end_time": "0",
|
||||
"module_name": "",
|
||||
"module_permissions": null
|
||||
},
|
||||
{
|
||||
"address": "cosmos1gudmxhn5anh5m6m2rr4rsfhgvps8fchtgmk7a6",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "node2token",
|
||||
"amount": "1000000000"
|
||||
},
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "500000000"
|
||||
}
|
||||
],
|
||||
"sequence_number": "0",
|
||||
"account_number": "0",
|
||||
"original_vesting": [],
|
||||
"delegated_free": [],
|
||||
"delegated_vesting": [],
|
||||
"start_time": "0",
|
||||
"end_time": "0",
|
||||
"module_name": "",
|
||||
"module_permissions": null
|
||||
},
|
||||
{
|
||||
"address": "cosmos1kluvs8ff2s3hxad4jpmhvca4crqpcwn9xyhchv",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "node3token",
|
||||
"amount": "1000000000"
|
||||
},
|
||||
{
|
||||
"denom": "stake",
|
||||
"amount": "500000000"
|
||||
}
|
||||
],
|
||||
"sequence_number": "0",
|
||||
"account_number": "0",
|
||||
"original_vesting": [],
|
||||
"delegated_free": [],
|
||||
"delegated_vesting": [],
|
||||
"start_time": "0",
|
||||
"end_time": "0",
|
||||
"module_name": "",
|
||||
"module_permissions": null
|
||||
}
|
||||
]`
|
||||
|
||||
require.NotPanics(t, func() {
|
||||
genesisState = Migrate(
|
||||
v036auth.GenesisState{
|
||||
Params: params,
|
||||
},
|
||||
json.RawMessage(rawAccounts),
|
||||
)
|
||||
})
|
||||
|
||||
require.Equal(t, genesisState, GenesisState{Params: params, Accounts: json.RawMessage(rawAccounts)})
|
||||
}
|
||||
26
x/auth/legacy/v0_38/types.go
Normal file
26
x/auth/legacy/v0_38/types.go
Normal file
@ -0,0 +1,26 @@
|
||||
package v038
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
v034auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_34"
|
||||
)
|
||||
|
||||
// DONTCOVER
|
||||
|
||||
// nolint
|
||||
const (
|
||||
ModuleName = "auth"
|
||||
)
|
||||
|
||||
type GenesisState struct {
|
||||
Params v034auth.Params `json:"params"`
|
||||
Accounts json.RawMessage `json:"accounts"`
|
||||
}
|
||||
|
||||
func NewGenesisState(params v034auth.Params, accounts json.RawMessage) GenesisState {
|
||||
return GenesisState{
|
||||
Params: params,
|
||||
Accounts: accounts,
|
||||
}
|
||||
}
|
||||
@ -7,7 +7,9 @@ import (
|
||||
"math/rand"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
@ -78,11 +80,50 @@ func RandomizedGenState(simState *module.SimulationState) {
|
||||
func(r *rand.Rand) { sigVerifyCostED25519 = GenSigVerifyCostSECP256K1(r) },
|
||||
)
|
||||
|
||||
authGenesis := types.NewGenesisState(
|
||||
types.NewParams(maxMemoChars, txSigLimit, txSizeCostPerByte,
|
||||
sigVerifyCostED25519, sigVerifyCostSECP256K1),
|
||||
)
|
||||
params := types.NewParams(maxMemoChars, txSigLimit, txSizeCostPerByte,
|
||||
sigVerifyCostED25519, sigVerifyCostSECP256K1)
|
||||
genesisAccs := RandomGenesisAccounts(simState)
|
||||
|
||||
authGenesis := types.NewGenesisState(params, genesisAccs)
|
||||
|
||||
fmt.Printf("Selected randomly generated auth parameters:\n%s\n", codec.MustMarshalJSONIndent(simState.Cdc, authGenesis.Params))
|
||||
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(authGenesis)
|
||||
}
|
||||
|
||||
// RandomGenesisAccounts returns randomly generated genesis accounts
|
||||
func RandomGenesisAccounts(simState *module.SimulationState) (genesisAccs []exported.GenesisAccount) {
|
||||
for i, acc := range simState.Accounts {
|
||||
coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))}
|
||||
bacc := types.NewBaseAccountWithAddress(acc.Address)
|
||||
if err := bacc.SetCoins(coins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var gacc exported.GenesisAccount
|
||||
gacc = &bacc
|
||||
|
||||
// Only consider making a vesting account once the initial bonded validator
|
||||
// set is exhausted due to needing to track DelegatedVesting.
|
||||
if int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50 {
|
||||
var endTime int64
|
||||
|
||||
startTime := simState.GenTimestamp.Unix()
|
||||
|
||||
// Allow for some vesting accounts to vest very quickly while others very slowly.
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*24*30))))
|
||||
} else {
|
||||
endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime)+1, int(startTime+(60*60*12))))
|
||||
}
|
||||
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
gacc = types.NewContinuousVestingAccount(&bacc, startTime, endTime)
|
||||
} else {
|
||||
gacc = types.NewDelayedVestingAccount(&bacc, endTime)
|
||||
}
|
||||
}
|
||||
genesisAccs = append(genesisAccs, gacc)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
@ -16,6 +17,7 @@ import (
|
||||
// BaseAccount
|
||||
|
||||
var _ exported.Account = (*BaseAccount)(nil)
|
||||
var _ exported.GenesisAccount = (*BaseAccount)(nil)
|
||||
|
||||
// BaseAccount - a base account structure.
|
||||
// This can be extended by embedding within in your AppAccount.
|
||||
@ -169,6 +171,16 @@ func (acc BaseAccount) MarshalYAML() (interface{}, error) {
|
||||
return string(bs), err
|
||||
}
|
||||
|
||||
// Validate checks for errors on the account fields
|
||||
func (acc BaseAccount) Validate() error {
|
||||
if acc.PubKey != nil && acc.Address != nil &&
|
||||
!bytes.Equal(acc.PubKey.Address().Bytes(), acc.Address.Bytes()) {
|
||||
return errors.New("pubkey and address pair is invalid")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Base Vesting Account
|
||||
|
||||
@ -346,10 +358,20 @@ func (bva BaseVestingAccount) GetDelegatedVesting() sdk.Coins {
|
||||
return bva.DelegatedVesting
|
||||
}
|
||||
|
||||
// Validate checks for errors on the account fields
|
||||
func (bva BaseVestingAccount) Validate() error {
|
||||
if (bva.Coins.IsZero() && !bva.OriginalVesting.IsZero()) ||
|
||||
bva.OriginalVesting.IsAnyGT(bva.Coins) {
|
||||
return errors.New("vesting amount cannot be greater than total amount")
|
||||
}
|
||||
return bva.BaseAccount.Validate()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Continuous Vesting Account
|
||||
|
||||
var _ exported.VestingAccount = (*ContinuousVestingAccount)(nil)
|
||||
var _ exported.GenesisAccount = (*ContinuousVestingAccount)(nil)
|
||||
|
||||
// ContinuousVestingAccount implements the VestingAccount interface. It
|
||||
// continuously vests by unlocking coins linearly with respect to time.
|
||||
@ -467,10 +489,20 @@ func (cva *ContinuousVestingAccount) GetEndTime() int64 {
|
||||
return cva.EndTime
|
||||
}
|
||||
|
||||
// Validate checks for errors on the account fields
|
||||
func (cva ContinuousVestingAccount) Validate() error {
|
||||
if cva.GetStartTime() >= cva.GetEndTime() {
|
||||
return errors.New("vesting start-time cannot be before end-time")
|
||||
}
|
||||
|
||||
return cva.BaseVestingAccount.Validate()
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Delayed Vesting Account
|
||||
|
||||
var _ exported.VestingAccount = (*DelayedVestingAccount)(nil)
|
||||
var _ exported.GenesisAccount = (*DelayedVestingAccount)(nil)
|
||||
|
||||
// DelayedVestingAccount implements the VestingAccount interface. It vests all
|
||||
// coins after a specific time, but non prior. In other words, it keeps them
|
||||
@ -535,3 +567,8 @@ func (dva *DelayedVestingAccount) GetStartTime() int64 {
|
||||
func (dva *DelayedVestingAccount) GetEndTime() int64 {
|
||||
return dva.EndTime
|
||||
}
|
||||
|
||||
// Validate checks for errors on the account fields
|
||||
func (dva DelayedVestingAccount) Validate() error {
|
||||
return dva.BaseVestingAccount.Validate()
|
||||
}
|
||||
|
||||
@ -1,14 +1,17 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
tmtime "github.com/tendermint/tendermint/types/time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -479,3 +482,73 @@ func TestTrackUndelegationDelVestingAcc(t *testing.T) {
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(stakeDenom, 25)}, dva.DelegatedVesting)
|
||||
require.Equal(t, sdk.Coins{sdk.NewInt64Coin(feeDenom, 1000), sdk.NewInt64Coin(stakeDenom, 75)}, dva.GetCoins())
|
||||
}
|
||||
|
||||
func TestGenesisAccountValidate(t *testing.T) {
|
||||
pubkey := secp256k1.GenPrivKey().PubKey()
|
||||
addr := sdk.AccAddress(pubkey.Address())
|
||||
baseAcc := NewBaseAccount(addr, nil, pubkey, 0, 0)
|
||||
tests := []struct {
|
||||
name string
|
||||
acc exported.GenesisAccount
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
"valid base account",
|
||||
baseAcc,
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid base valid account",
|
||||
NewBaseAccount(addr, sdk.NewCoins(), secp256k1.GenPrivKey().PubKey(), 0, 0),
|
||||
errors.New("pubkey and address pair is invalid"),
|
||||
},
|
||||
{
|
||||
"valid base vesting account",
|
||||
NewBaseVestingAccount(baseAcc, sdk.NewCoins(), nil, nil, 100),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid vesting amount; empty Coins",
|
||||
NewBaseVestingAccount(
|
||||
NewBaseAccount(addr, sdk.NewCoins(), pubkey, 0, 0),
|
||||
sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)},
|
||||
nil, nil, 100,
|
||||
),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"invalid vesting amount; OriginalVesting > Coins",
|
||||
NewBaseVestingAccount(
|
||||
NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)), pubkey, 0, 0),
|
||||
sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)},
|
||||
nil, nil, 100,
|
||||
),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"invalid vesting amount with multi coins",
|
||||
NewBaseVestingAccount(
|
||||
NewBaseAccount(addr, sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)), pubkey, 0, 0),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)),
|
||||
nil, nil, 100,
|
||||
),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"valid continuous vesting account",
|
||||
NewContinuousVestingAccount(baseAcc, 100, 200),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid vesting times",
|
||||
NewContinuousVestingAccount(baseAcc, 1654668078, 1554668078),
|
||||
errors.New("vesting start-time cannot be before end-time"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.acc.Validate()
|
||||
require.Equal(t, tt.expErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,8 +5,12 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
// ModuleCdc auth module wide codec
|
||||
var ModuleCdc = codec.New()
|
||||
|
||||
// RegisterCodec registers concrete types on the codec
|
||||
func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterInterface((*exported.GenesisAccount)(nil), nil)
|
||||
cdc.RegisterInterface((*exported.Account)(nil), nil)
|
||||
cdc.RegisterConcrete(&BaseAccount{}, "cosmos-sdk/Account", nil)
|
||||
cdc.RegisterInterface((*exported.VestingAccount)(nil), nil)
|
||||
@ -16,12 +20,13 @@ func RegisterCodec(cdc *codec.Codec) {
|
||||
cdc.RegisterConcrete(StdTx{}, "cosmos-sdk/StdTx", nil)
|
||||
}
|
||||
|
||||
// module wide codec
|
||||
var ModuleCdc *codec.Codec
|
||||
// RegisterAccountTypeCodec registers an external account type defined in
|
||||
// another module for the internal ModuleCdc.
|
||||
func RegisterAccountTypeCodec(o interface{}, name string) {
|
||||
ModuleCdc.RegisterConcrete(o, name, nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
ModuleCdc = codec.New()
|
||||
RegisterCodec(ModuleCdc)
|
||||
codec.RegisterCrypto(ModuleCdc)
|
||||
ModuleCdc.Seal()
|
||||
}
|
||||
|
||||
@ -2,40 +2,71 @@ package types
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
// GenesisState - all auth state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
Params Params `json:"params" yaml:"params"`
|
||||
Params Params `json:"params" yaml:"params"`
|
||||
Accounts []exported.GenesisAccount `json:"accounts" yaml:"accounts"`
|
||||
}
|
||||
|
||||
// NewGenesisState - Create a new genesis state
|
||||
func NewGenesisState(params Params) GenesisState {
|
||||
return GenesisState{params}
|
||||
func NewGenesisState(params Params, accounts []exported.GenesisAccount) GenesisState {
|
||||
return GenesisState{
|
||||
Params: params,
|
||||
Accounts: accounts,
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultGenesisState - Return a default genesis state
|
||||
func DefaultGenesisState() GenesisState {
|
||||
return NewGenesisState(DefaultParams())
|
||||
return NewGenesisState(DefaultParams(), []exported.GenesisAccount{})
|
||||
}
|
||||
|
||||
// ValidateGenesis performs basic validation of auth genesis data returning an
|
||||
// error for any failed validation criteria.
|
||||
func ValidateGenesis(data GenesisState) error {
|
||||
if data.Params.TxSigLimit == 0 {
|
||||
return fmt.Errorf("invalid tx signature limit: %d", data.Params.TxSigLimit)
|
||||
if err := data.Params.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
if data.Params.SigVerifyCostED25519 == 0 {
|
||||
return fmt.Errorf("invalid ED25519 signature verification cost: %d", data.Params.SigVerifyCostED25519)
|
||||
|
||||
return validateGenAccounts(data.Accounts)
|
||||
}
|
||||
|
||||
// Sanitize sorts accounts and coin sets.
|
||||
func Sanitize(genAccs []exported.GenesisAccount) []exported.GenesisAccount {
|
||||
sort.Slice(genAccs, func(i, j int) bool {
|
||||
return genAccs[i].GetAccountNumber() < genAccs[j].GetAccountNumber()
|
||||
})
|
||||
|
||||
for _, acc := range genAccs {
|
||||
if err := acc.SetCoins(acc.GetCoins().Sort()); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
if data.Params.SigVerifyCostSecp256k1 == 0 {
|
||||
return fmt.Errorf("invalid SECK256k1 signature verification cost: %d", data.Params.SigVerifyCostSecp256k1)
|
||||
}
|
||||
if data.Params.MaxMemoCharacters == 0 {
|
||||
return fmt.Errorf("invalid max memo characters: %d", data.Params.MaxMemoCharacters)
|
||||
}
|
||||
if data.Params.TxSizeCostPerByte == 0 {
|
||||
return fmt.Errorf("invalid tx size cost per byte: %d", data.Params.TxSizeCostPerByte)
|
||||
|
||||
return genAccs
|
||||
}
|
||||
|
||||
func validateGenAccounts(accounts []exported.GenesisAccount) error {
|
||||
addrMap := make(map[string]bool, len(accounts))
|
||||
for _, acc := range accounts {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
82
x/auth/types/genesis_test.go
Normal file
82
x/auth/types/genesis_test.go
Normal file
@ -0,0 +1,82 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
func TestSanitize(t *testing.T) {
|
||||
addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
authAcc1 := NewBaseAccountWithAddress(addr1)
|
||||
authAcc1.SetCoins(sdk.Coins{
|
||||
sdk.NewInt64Coin("bcoin", 150),
|
||||
sdk.NewInt64Coin("acoin", 150),
|
||||
})
|
||||
authAcc1.SetAccountNumber(1)
|
||||
|
||||
addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
authAcc2 := NewBaseAccountWithAddress(addr2)
|
||||
authAcc2.SetCoins(sdk.Coins{
|
||||
sdk.NewInt64Coin("acoin", 150),
|
||||
sdk.NewInt64Coin("bcoin", 150),
|
||||
})
|
||||
|
||||
genAccs := []exported.GenesisAccount{&authAcc1, &authAcc2}
|
||||
|
||||
require.True(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber())
|
||||
require.Equal(t, genAccs[0].GetCoins()[0].Denom, "bcoin")
|
||||
require.Equal(t, genAccs[0].GetCoins()[1].Denom, "acoin")
|
||||
require.Equal(t, genAccs[1].GetAddress(), addr2)
|
||||
genAccs = Sanitize(genAccs)
|
||||
|
||||
require.False(t, genAccs[0].GetAccountNumber() > genAccs[1].GetAccountNumber())
|
||||
require.Equal(t, genAccs[1].GetAddress(), addr1)
|
||||
require.Equal(t, genAccs[1].GetCoins()[0].Denom, "acoin")
|
||||
require.Equal(t, genAccs[1].GetCoins()[1].Denom, "bcoin")
|
||||
}
|
||||
|
||||
var (
|
||||
pk1 = ed25519.GenPrivKey().PubKey()
|
||||
pk2 = ed25519.GenPrivKey().PubKey()
|
||||
addr1 = sdk.ValAddress(pk1.Address())
|
||||
addr2 = sdk.ValAddress(pk2.Address())
|
||||
)
|
||||
|
||||
// require duplicate accounts fails validation
|
||||
func TestValidateGenesisDuplicateAccounts(t *testing.T) {
|
||||
acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1))
|
||||
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
|
||||
genAccs := make([]exported.GenesisAccount, 2)
|
||||
genAccs[0] = &acc1
|
||||
genAccs[1] = &acc1
|
||||
|
||||
require.Error(t, validateGenAccounts(genAccs))
|
||||
}
|
||||
|
||||
// require invalid vesting account fails validation (invalid end time)
|
||||
func TestValidateGenesisInvalidAccounts(t *testing.T) {
|
||||
acc1 := NewBaseAccountWithAddress(sdk.AccAddress(addr1))
|
||||
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
baseVestingAcc := NewBaseVestingAccount(&acc1, acc1.Coins.Add(acc1.Coins), nil, nil, 1548775410)
|
||||
|
||||
acc2 := NewBaseAccountWithAddress(sdk.AccAddress(addr2))
|
||||
acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
|
||||
genAccs := make([]exported.GenesisAccount, 2)
|
||||
genAccs[0] = baseVestingAcc
|
||||
genAccs[1] = &acc2
|
||||
|
||||
require.Error(t, validateGenAccounts(genAccs))
|
||||
baseVestingAcc.OriginalVesting = acc1.Coins
|
||||
genAccs[0] = baseVestingAcc
|
||||
require.NoError(t, validateGenAccounts(genAccs))
|
||||
|
||||
genAccs[0] = NewContinuousVestingAccountRaw(baseVestingAcc, 1548888000)
|
||||
require.Error(t, validateGenAccounts(genAccs))
|
||||
}
|
||||
@ -100,3 +100,23 @@ func (p Params) String() string {
|
||||
sb.WriteString(fmt.Sprintf("SigVerifyCostSecp256k1: %d\n", p.SigVerifyCostSecp256k1))
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// Validate checks that the parameters have valid values.
|
||||
func (p Params) Validate() error {
|
||||
if p.TxSigLimit == 0 {
|
||||
return fmt.Errorf("invalid tx signature limit: %d", p.TxSigLimit)
|
||||
}
|
||||
if p.SigVerifyCostED25519 == 0 {
|
||||
return fmt.Errorf("invalid ED25519 signature verification cost: %d", p.SigVerifyCostED25519)
|
||||
}
|
||||
if p.SigVerifyCostSecp256k1 == 0 {
|
||||
return fmt.Errorf("invalid SECK256k1 signature verification cost: %d", p.SigVerifyCostSecp256k1)
|
||||
}
|
||||
if p.MaxMemoCharacters == 0 {
|
||||
return fmt.Errorf("invalid max memo characters: %d", p.MaxMemoCharacters)
|
||||
}
|
||||
if p.TxSizeCostPerByte == 0 {
|
||||
return fmt.Errorf("invalid tx size cost per byte: %d", p.TxSizeCostPerByte)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -12,8 +12,8 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
)
|
||||
|
||||
type (
|
||||
@ -93,7 +93,7 @@ func TestSendNotEnoughBalance(t *testing.T) {
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)},
|
||||
}
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc)}
|
||||
genAccs := []authexported.GenesisAccount{acc}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
|
||||
@ -125,7 +125,7 @@ func TestSendToModuleAcc(t *testing.T) {
|
||||
Coins: coins,
|
||||
}
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc)}
|
||||
genAccs := []authexported.GenesisAccount{acc}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
|
||||
@ -156,7 +156,7 @@ func TestMsgMultiSendWithAccounts(t *testing.T) {
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 67)},
|
||||
}
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc)}
|
||||
genAccs := []authexported.GenesisAccount{acc}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
ctxCheck := app.BaseApp.NewContext(true, abci.Header{})
|
||||
@ -217,7 +217,7 @@ func TestMsgMultiSendMultipleOut(t *testing.T) {
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)},
|
||||
}
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc1), genaccounts.NewGenesisAccount(acc2)}
|
||||
genAccs := []authexported.GenesisAccount{acc1, acc2}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
testCases := []appTestCase{
|
||||
@ -261,7 +261,7 @@ func TestMsgMultiSendMultipleInOut(t *testing.T) {
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 42)},
|
||||
}
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc1), genaccounts.NewGenesisAccount(acc2), genaccounts.NewGenesisAccount(acc4)}
|
||||
genAccs := []authexported.GenesisAccount{acc1, acc2, acc4}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
testCases := []appTestCase{
|
||||
@ -299,7 +299,7 @@ func TestMsgMultiSendDependent(t *testing.T) {
|
||||
err = acc2.SetAccountNumber(1)
|
||||
require.NoError(t, err)
|
||||
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(&acc1), genaccounts.NewGenesisAccount(&acc2)}
|
||||
genAccs := []authexported.GenesisAccount{&acc1, &acc2}
|
||||
app := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
testCases := []appTestCase{
|
||||
|
||||
@ -8,7 +8,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/simapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
@ -17,14 +17,14 @@ var moduleAccAddr = supply.NewModuleAddress(staking.BondedPoolName)
|
||||
|
||||
func BenchmarkOneBankSendTxPerBlock(b *testing.B) {
|
||||
// Add an account at genesis
|
||||
acc := &auth.BaseAccount{
|
||||
acc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
// Some value conceivably higher than the benchmarks would ever go
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)},
|
||||
}
|
||||
|
||||
// Construct genesis state
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc)}
|
||||
genAccs := []authexported.GenesisAccount{&acc}
|
||||
benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
// Precompute all txs
|
||||
@ -46,14 +46,14 @@ func BenchmarkOneBankSendTxPerBlock(b *testing.B) {
|
||||
|
||||
func BenchmarkOneBankMultiSendTxPerBlock(b *testing.B) {
|
||||
// Add an account at genesis
|
||||
acc := &auth.BaseAccount{
|
||||
acc := auth.BaseAccount{
|
||||
Address: addr1,
|
||||
// Some value conceivably higher than the benchmarks would ever go
|
||||
Coins: sdk.Coins{sdk.NewInt64Coin("foocoin", 100000000000)},
|
||||
}
|
||||
|
||||
// Construct genesis state
|
||||
genAccs := []genaccounts.GenesisAccount{genaccounts.NewGenesisAccount(acc)}
|
||||
genAccs := []authexported.GenesisAccount{&acc}
|
||||
benchmarkApp := simapp.SetupWithGenesisAccounts(genAccs)
|
||||
|
||||
// Precompute all txs
|
||||
|
||||
@ -1,32 +0,0 @@
|
||||
// nolint
|
||||
// autogenerated code using github.com/rigelrozanski/multitool
|
||||
// aliases generated for the following subdirectories:
|
||||
// ALIASGEN: github.com/cosmos/cosmos-sdk/x/genaccounts/internal/types
|
||||
package genaccounts
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts/internal/types"
|
||||
)
|
||||
|
||||
const (
|
||||
ModuleName = types.ModuleName
|
||||
)
|
||||
|
||||
var (
|
||||
// functions aliases
|
||||
NewGenesisAccountRaw = types.NewGenesisAccountRaw
|
||||
NewGenesisAccount = types.NewGenesisAccount
|
||||
NewGenesisAccountI = types.NewGenesisAccountI
|
||||
GetGenesisStateFromAppState = types.GetGenesisStateFromAppState
|
||||
SetGenesisStateInAppState = types.SetGenesisStateInAppState
|
||||
ValidateGenesis = types.ValidateGenesis
|
||||
|
||||
// variable aliases
|
||||
ModuleCdc = types.ModuleCdc
|
||||
)
|
||||
|
||||
type (
|
||||
GenesisAccount = types.GenesisAccount
|
||||
GenesisAccounts = types.GenesisAccounts
|
||||
GenesisState = types.GenesisState
|
||||
)
|
||||
@ -1,107 +0,0 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
)
|
||||
|
||||
const (
|
||||
flagClientHome = "home-client"
|
||||
flagVestingStart = "vesting-start-time"
|
||||
flagVestingEnd = "vesting-end-time"
|
||||
flagVestingAmt = "vesting-amount"
|
||||
)
|
||||
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||
func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec,
|
||||
defaultNodeHome, defaultClientHome string) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
|
||||
Short: "Add genesis account to genesis.json",
|
||||
Args: cobra.ExactArgs(2),
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
addr, err := sdk.AccAddressFromBech32(args[0])
|
||||
if err != nil {
|
||||
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
info, err := kb.Get(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr = info.GetAddress()
|
||||
}
|
||||
|
||||
coins, err := sdk.ParseCoins(args[1])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vestingStart := viper.GetInt64(flagVestingStart)
|
||||
vestingEnd := viper.GetInt64(flagVestingEnd)
|
||||
vestingAmt, err := sdk.ParseCoins(viper.GetString(flagVestingAmt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd, "", "")
|
||||
if err := genAcc.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// retrieve the app state
|
||||
genFile := config.GenesisFile()
|
||||
appState, genDoc, err := genutil.GenesisStateFromGenFile(cdc, genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// add genesis account to the app state
|
||||
var genesisAccounts genaccounts.GenesisAccounts
|
||||
|
||||
cdc.MustUnmarshalJSON(appState[genaccounts.ModuleName], &genesisAccounts)
|
||||
|
||||
if genesisAccounts.Contains(addr) {
|
||||
return fmt.Errorf("cannot add account at existing address %v", addr)
|
||||
}
|
||||
|
||||
genesisAccounts = append(genesisAccounts, genAcc)
|
||||
|
||||
genesisStateBz := cdc.MustMarshalJSON(genaccounts.GenesisState(genesisAccounts))
|
||||
appState[genaccounts.ModuleName] = genesisStateBz
|
||||
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// export app state
|
||||
genDoc.AppState = appStateJSON
|
||||
|
||||
return genutil.ExportGenesisFile(genDoc, genFile)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, defaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, defaultClientHome, "client's home directory")
|
||||
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
|
||||
return cmd
|
||||
}
|
||||
@ -1,9 +1,15 @@
|
||||
/*
|
||||
Package genaccounts contains specialized functionality for initializing
|
||||
accounts from genesis including:
|
||||
- genesis account validation,
|
||||
- initchain processing of genesis accounts,
|
||||
- export processing (to genesis) of accounts,
|
||||
- server command for adding accounts to the genesis file.
|
||||
Package genaccounts is now deprecated.
|
||||
|
||||
IMPORTANT: This module has been replaced by ADR 011: Generalize Module Accounts.
|
||||
The ADR can be found here: https://github.com/cosmos/cosmos-sdk/blob/master/docs/architecture/adr-011-generalize-genesis-accounts.md.
|
||||
|
||||
Genesis accounts that existed in the genesis application state under `app_state.accounts`
|
||||
now exists under the x/auth module's genesis state under the `app_state.auth.accounts` key.
|
||||
Migration can be performed via x/auth/legacy/v0_38/migrate.go. In addition, because genesis
|
||||
accounts are now generalized via an interface, it is now up to the application to
|
||||
define the concrete types and the respective client logic to add them to a genesis
|
||||
state/file. For an example implementation of the `add-genesis-account` command please
|
||||
refer to https://github.com/cosmos/gaia/pull/122.
|
||||
*/
|
||||
package genaccounts
|
||||
|
||||
@ -1,39 +0,0 @@
|
||||
package genaccounts
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts/internal/types"
|
||||
)
|
||||
|
||||
// InitGenesis initializes accounts and deliver genesis transactions
|
||||
func InitGenesis(ctx sdk.Context, _ *codec.Codec, accountKeeper types.AccountKeeper, genesisState GenesisState) {
|
||||
genesisState.Sanitize()
|
||||
|
||||
// load the accounts
|
||||
for _, gacc := range genesisState {
|
||||
acc := gacc.ToAccount()
|
||||
acc = accountKeeper.NewAccount(ctx, acc) // set account number
|
||||
accountKeeper.SetAccount(ctx, acc)
|
||||
}
|
||||
}
|
||||
|
||||
// ExportGenesis exports genesis for all accounts
|
||||
func ExportGenesis(ctx sdk.Context, accountKeeper types.AccountKeeper) GenesisState {
|
||||
|
||||
// iterate to get the accounts
|
||||
accounts := []GenesisAccount{}
|
||||
accountKeeper.IterateAccounts(ctx,
|
||||
func(acc authexported.Account) (stop bool) {
|
||||
account, err := NewGenesisAccountI(acc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
accounts = append(accounts, account)
|
||||
return false
|
||||
},
|
||||
)
|
||||
|
||||
return accounts
|
||||
}
|
||||
@ -1,17 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
// ModuleName is "accounts"
|
||||
const ModuleName = "accounts"
|
||||
|
||||
// ModuleCdc - generic sealed codec to be used throughout this module
|
||||
var ModuleCdc *codec.Codec
|
||||
|
||||
func init() {
|
||||
ModuleCdc = codec.New()
|
||||
codec.RegisterCrypto(ModuleCdc)
|
||||
ModuleCdc.Seal()
|
||||
}
|
||||
@ -1,13 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
)
|
||||
|
||||
// AccountKeeper defines the expected account keeper (noalias)
|
||||
type AccountKeeper interface {
|
||||
NewAccount(sdk.Context, authexported.Account) authexported.Account
|
||||
SetAccount(sdk.Context, authexported.Account)
|
||||
IterateAccounts(ctx sdk.Context, process func(authexported.Account) (stop bool))
|
||||
}
|
||||
@ -1,151 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
supplyexported "github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
// GenesisAccount is a struct for account initialization used exclusively during genesis
|
||||
type GenesisAccount struct {
|
||||
Address sdk.AccAddress `json:"address" yaml:"address"`
|
||||
Coins sdk.Coins `json:"coins" yaml:"coins"`
|
||||
Sequence uint64 `json:"sequence_number" yaml:"sequence_number"`
|
||||
AccountNumber uint64 `json:"account_number" yaml:"account_number"`
|
||||
|
||||
// vesting account fields
|
||||
OriginalVesting sdk.Coins `json:"original_vesting" yaml:"original_vesting"` // total vesting coins upon initialization
|
||||
DelegatedFree sdk.Coins `json:"delegated_free" yaml:"delegated_free"` // delegated vested coins at time of delegation
|
||||
DelegatedVesting sdk.Coins `json:"delegated_vesting" yaml:"delegated_vesting"` // delegated vesting coins at time of delegation
|
||||
StartTime int64 `json:"start_time" yaml:"start_time"` // vesting start time (UNIX Epoch time)
|
||||
EndTime int64 `json:"end_time" yaml:"end_time"` // vesting end time (UNIX Epoch time)
|
||||
|
||||
// module account fields
|
||||
ModuleName string `json:"module_name" yaml:"module_name"` // name of the module account
|
||||
ModulePermissions []string `json:"module_permissions" yaml:"module_permissions"` // permissions of module account
|
||||
}
|
||||
|
||||
// Validate checks for errors on the vesting and module account parameters
|
||||
func (ga GenesisAccount) Validate() error {
|
||||
if !ga.OriginalVesting.IsZero() {
|
||||
if ga.OriginalVesting.IsAnyGT(ga.Coins) {
|
||||
return errors.New("vesting amount cannot be greater than total amount")
|
||||
}
|
||||
if ga.StartTime >= ga.EndTime {
|
||||
return errors.New("vesting start-time cannot be before end-time")
|
||||
}
|
||||
}
|
||||
|
||||
// don't allow blank (i.e just whitespaces) on the module name
|
||||
if ga.ModuleName != "" && strings.TrimSpace(ga.ModuleName) == "" {
|
||||
return errors.New("module account name cannot be blank")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// NewGenesisAccountRaw creates a new GenesisAccount object
|
||||
func NewGenesisAccountRaw(address sdk.AccAddress, coins,
|
||||
vestingAmount sdk.Coins, vestingStartTime, vestingEndTime int64,
|
||||
module string, permissions ...string) GenesisAccount {
|
||||
|
||||
return GenesisAccount{
|
||||
Address: address,
|
||||
Coins: coins,
|
||||
Sequence: 0,
|
||||
AccountNumber: 0, // ignored set by the account keeper during InitGenesis
|
||||
OriginalVesting: vestingAmount,
|
||||
DelegatedFree: sdk.Coins{}, // ignored
|
||||
DelegatedVesting: sdk.Coins{}, // ignored
|
||||
StartTime: vestingStartTime,
|
||||
EndTime: vestingEndTime,
|
||||
ModuleName: module,
|
||||
ModulePermissions: permissions,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenesisAccount creates a GenesisAccount instance from a BaseAccount.
|
||||
func NewGenesisAccount(acc *authtypes.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
AccountNumber: acc.AccountNumber,
|
||||
Sequence: acc.Sequence,
|
||||
}
|
||||
}
|
||||
|
||||
// NewGenesisAccountI creates a GenesisAccount instance from an Account interface.
|
||||
func NewGenesisAccountI(acc authexported.Account) (GenesisAccount, error) {
|
||||
gacc := GenesisAccount{
|
||||
Address: acc.GetAddress(),
|
||||
Coins: acc.GetCoins(),
|
||||
AccountNumber: acc.GetAccountNumber(),
|
||||
Sequence: acc.GetSequence(),
|
||||
}
|
||||
|
||||
if err := gacc.Validate(); err != nil {
|
||||
return gacc, err
|
||||
}
|
||||
|
||||
switch acc := acc.(type) {
|
||||
case authexported.VestingAccount:
|
||||
gacc.OriginalVesting = acc.GetOriginalVesting()
|
||||
gacc.DelegatedFree = acc.GetDelegatedFree()
|
||||
gacc.DelegatedVesting = acc.GetDelegatedVesting()
|
||||
gacc.StartTime = acc.GetStartTime()
|
||||
gacc.EndTime = acc.GetEndTime()
|
||||
case supplyexported.ModuleAccountI:
|
||||
gacc.ModuleName = acc.GetName()
|
||||
gacc.ModulePermissions = acc.GetPermissions()
|
||||
}
|
||||
|
||||
return gacc, nil
|
||||
}
|
||||
|
||||
// ToAccount converts a GenesisAccount to an Account interface
|
||||
func (ga *GenesisAccount) ToAccount() authexported.Account {
|
||||
bacc := authtypes.NewBaseAccount(ga.Address, ga.Coins.Sort(), nil, ga.AccountNumber, ga.Sequence)
|
||||
|
||||
// vesting accounts
|
||||
if !ga.OriginalVesting.IsZero() {
|
||||
baseVestingAcc := authtypes.NewBaseVestingAccount(
|
||||
bacc, ga.OriginalVesting, ga.DelegatedFree,
|
||||
ga.DelegatedVesting, ga.EndTime,
|
||||
)
|
||||
|
||||
switch {
|
||||
case ga.StartTime != 0 && ga.EndTime != 0:
|
||||
return authtypes.NewContinuousVestingAccountRaw(baseVestingAcc, ga.StartTime)
|
||||
case ga.EndTime != 0:
|
||||
return authtypes.NewDelayedVestingAccountRaw(baseVestingAcc)
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
|
||||
}
|
||||
}
|
||||
|
||||
// module accounts
|
||||
if ga.ModuleName != "" {
|
||||
return supply.NewModuleAccount(bacc, ga.ModuleName, ga.ModulePermissions...)
|
||||
}
|
||||
|
||||
return bacc
|
||||
}
|
||||
|
||||
// GenesisAccounts defines a set of genesis account
|
||||
type GenesisAccounts []GenesisAccount
|
||||
|
||||
// Contains checks if a set of genesis accounts contain an address
|
||||
func (gaccs GenesisAccounts) Contains(acc sdk.AccAddress) bool {
|
||||
for _, gacc := range gaccs {
|
||||
if gacc.Address.Equals(acc) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
@ -1,97 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply"
|
||||
)
|
||||
|
||||
func TestGenesisAccountValidate(t *testing.T) {
|
||||
addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
|
||||
tests := []struct {
|
||||
name string
|
||||
acc GenesisAccount
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
"valid account",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, "", ""),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"valid module account",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, "mint", supply.Minter),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid vesting amount",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), 0, 0, "", ""),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"invalid vesting amount with multi coins",
|
||||
NewGenesisAccountRaw(addr,
|
||||
sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)),
|
||||
0, 0, "", ""),
|
||||
errors.New("vesting amount cannot be greater than total amount"),
|
||||
},
|
||||
{
|
||||
"invalid vesting times",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
|
||||
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)), 1654668078, 1554668078, "", ""),
|
||||
errors.New("vesting start-time cannot be before end-time"),
|
||||
},
|
||||
{
|
||||
"invalid module account name",
|
||||
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0, " ", ""),
|
||||
errors.New("module account name cannot be blank"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.acc.Validate()
|
||||
require.Equal(t, tt.expErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestToAccount(t *testing.T) {
|
||||
priv := ed25519.GenPrivKey()
|
||||
addr := sdk.AccAddress(priv.PubKey().Address())
|
||||
|
||||
// base account
|
||||
authAcc := authtypes.NewBaseAccountWithAddress(addr)
|
||||
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150)))
|
||||
genAcc := NewGenesisAccount(&authAcc)
|
||||
acc := genAcc.ToAccount()
|
||||
require.IsType(t, &authtypes.BaseAccount{}, acc)
|
||||
require.Equal(t, &authAcc, acc.(*authtypes.BaseAccount))
|
||||
|
||||
// vesting account
|
||||
vacc := authtypes.NewContinuousVestingAccount(
|
||||
&authAcc, time.Now().Unix(), time.Now().Add(24*time.Hour).Unix(),
|
||||
)
|
||||
genAcc, err := NewGenesisAccountI(vacc)
|
||||
require.NoError(t, err)
|
||||
acc = genAcc.ToAccount()
|
||||
require.IsType(t, &authtypes.ContinuousVestingAccount{}, acc)
|
||||
require.Equal(t, vacc, acc.(*authtypes.ContinuousVestingAccount))
|
||||
|
||||
// module account
|
||||
macc := supply.NewEmptyModuleAccount("mint", supply.Minter)
|
||||
genAcc, err = NewGenesisAccountI(macc)
|
||||
require.NoError(t, err)
|
||||
acc = genAcc.ToAccount()
|
||||
require.IsType(t, &supply.ModuleAccount{}, acc)
|
||||
require.Equal(t, macc, acc.(*supply.ModuleAccount))
|
||||
}
|
||||
@ -1,77 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
// GenesisState is a wrapper for GenAccounts
|
||||
type GenesisState GenesisAccounts
|
||||
|
||||
// GetGenesisStateFromAppState gets the genesis state from the expected app state
|
||||
func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState {
|
||||
var genesisState GenesisState
|
||||
if appState[ModuleName] != nil {
|
||||
cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState)
|
||||
}
|
||||
|
||||
return genesisState
|
||||
}
|
||||
|
||||
// SetGenesisStateInAppState sets the genesis state within the expected app state
|
||||
func SetGenesisStateInAppState(cdc *codec.Codec,
|
||||
appState map[string]json.RawMessage, genesisState GenesisState) map[string]json.RawMessage {
|
||||
|
||||
genesisStateBz := cdc.MustMarshalJSON(genesisState)
|
||||
appState[ModuleName] = genesisStateBz
|
||||
return appState
|
||||
}
|
||||
|
||||
// Sanitize sorts accounts and coin sets.
|
||||
func (gs GenesisState) Sanitize() {
|
||||
sort.Slice(gs, func(i, j int) bool {
|
||||
return gs[i].AccountNumber < gs[j].AccountNumber
|
||||
})
|
||||
|
||||
for _, acc := range gs {
|
||||
acc.Coins = acc.Coins.Sort()
|
||||
}
|
||||
}
|
||||
|
||||
// ValidateGenesis performs validation of genesis accounts. It
|
||||
// ensures that there are no duplicate accounts in the genesis state and any
|
||||
// provided vesting accounts are valid.
|
||||
func ValidateGenesis(genesisState GenesisState) error {
|
||||
addrMap := make(map[string]bool, len(genesisState))
|
||||
for _, acc := range genesisState {
|
||||
addrStr := acc.Address.String()
|
||||
|
||||
// disallow any duplicate accounts
|
||||
if _, ok := addrMap[addrStr]; ok {
|
||||
return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr)
|
||||
}
|
||||
|
||||
// validate any vesting fields
|
||||
if !acc.OriginalVesting.IsZero() {
|
||||
if acc.EndTime == 0 {
|
||||
return fmt.Errorf("missing end time for vesting account; address: %s", addrStr)
|
||||
}
|
||||
|
||||
if acc.StartTime >= acc.EndTime {
|
||||
return fmt.Errorf(
|
||||
"vesting start time must before end time; address: %s, start: %s, end: %s",
|
||||
addrStr,
|
||||
time.Unix(acc.StartTime, 0).UTC().Format(time.RFC3339),
|
||||
time.Unix(acc.EndTime, 0).UTC().Format(time.RFC3339),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
addrMap[addrStr] = true
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@ -1,86 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
)
|
||||
|
||||
func TestSanitize(t *testing.T) {
|
||||
|
||||
addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
authAcc1 := authtypes.NewBaseAccountWithAddress(addr1)
|
||||
authAcc1.SetCoins(sdk.Coins{
|
||||
sdk.NewInt64Coin("bcoin", 150),
|
||||
sdk.NewInt64Coin("acoin", 150),
|
||||
})
|
||||
authAcc1.SetAccountNumber(1)
|
||||
genAcc1 := NewGenesisAccount(&authAcc1)
|
||||
|
||||
addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
|
||||
authAcc2 := authtypes.NewBaseAccountWithAddress(addr2)
|
||||
authAcc2.SetCoins(sdk.Coins{
|
||||
sdk.NewInt64Coin("acoin", 150),
|
||||
sdk.NewInt64Coin("bcoin", 150),
|
||||
})
|
||||
genAcc2 := NewGenesisAccount(&authAcc2)
|
||||
|
||||
genesisState := GenesisState([]GenesisAccount{genAcc1, genAcc2})
|
||||
require.NoError(t, ValidateGenesis(genesisState))
|
||||
require.True(t, genesisState[0].AccountNumber > genesisState[1].AccountNumber)
|
||||
require.Equal(t, genesisState[0].Coins[0].Denom, "bcoin")
|
||||
require.Equal(t, genesisState[0].Coins[1].Denom, "acoin")
|
||||
require.Equal(t, genesisState[1].Address, addr2)
|
||||
genesisState.Sanitize()
|
||||
require.False(t, genesisState[0].AccountNumber > genesisState[1].AccountNumber)
|
||||
require.Equal(t, genesisState[1].Address, addr1)
|
||||
require.Equal(t, genesisState[1].Coins[0].Denom, "acoin")
|
||||
require.Equal(t, genesisState[1].Coins[1].Denom, "bcoin")
|
||||
}
|
||||
|
||||
var (
|
||||
pk1 = ed25519.GenPrivKey().PubKey()
|
||||
pk2 = ed25519.GenPrivKey().PubKey()
|
||||
addr1 = sdk.ValAddress(pk1.Address())
|
||||
addr2 = sdk.ValAddress(pk2.Address())
|
||||
)
|
||||
|
||||
// require duplicate accounts fails validation
|
||||
func TestValidateGenesisDuplicateAccounts(t *testing.T) {
|
||||
acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1))
|
||||
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
|
||||
genAccs := make([]GenesisAccount, 2)
|
||||
genAccs[0] = NewGenesisAccount(&acc1)
|
||||
genAccs[1] = NewGenesisAccount(&acc1)
|
||||
|
||||
genesisState := GenesisState(genAccs)
|
||||
err := ValidateGenesis(genesisState)
|
||||
require.Error(t, err)
|
||||
}
|
||||
|
||||
// require invalid vesting account fails validation (invalid end time)
|
||||
func TestValidateGenesisInvalidAccounts(t *testing.T) {
|
||||
acc1 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr1))
|
||||
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
acc2 := authtypes.NewBaseAccountWithAddress(sdk.AccAddress(addr2))
|
||||
acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
|
||||
|
||||
genAccs := make([]GenesisAccount, 2)
|
||||
genAccs[0] = NewGenesisAccount(&acc1)
|
||||
genAccs[1] = NewGenesisAccount(&acc2)
|
||||
|
||||
genesisState := GenesisState(genAccs)
|
||||
genesisState[0].OriginalVesting = genesisState[0].Coins
|
||||
err := ValidateGenesis(genesisState)
|
||||
require.Error(t, err)
|
||||
|
||||
genesisState[0].StartTime = 1548888000
|
||||
genesisState[0].EndTime = 1548775410
|
||||
err = ValidateGenesis(genesisState)
|
||||
require.Error(t, err)
|
||||
}
|
||||
@ -1,155 +0,0 @@
|
||||
package genaccounts
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"math/rand"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts/simulation"
|
||||
sim "github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
var (
|
||||
_ module.AppModuleGenesis = AppModule{}
|
||||
_ module.AppModuleBasic = AppModuleBasic{}
|
||||
_ module.AppModuleSimulation = AppModuleSimulation{}
|
||||
)
|
||||
|
||||
// AppModuleBasic defines the basic application module used by the genesis accounts module.
|
||||
type AppModuleBasic struct{}
|
||||
|
||||
// Name returns the genesis accounts module's name.
|
||||
func (AppModuleBasic) Name() string {
|
||||
return ModuleName
|
||||
}
|
||||
|
||||
// RegisterCodec performs a no-op.
|
||||
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {}
|
||||
|
||||
// DefaultGenesis returns default genesis state as raw bytes for the genesis accounts
|
||||
// module.
|
||||
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
|
||||
return ModuleCdc.MustMarshalJSON(GenesisState{})
|
||||
}
|
||||
|
||||
// ValidateGenesis performs genesis state validation for the genesis accounts module.
|
||||
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
|
||||
var data GenesisState
|
||||
err := ModuleCdc.UnmarshalJSON(bz, &data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return ValidateGenesis(data)
|
||||
}
|
||||
|
||||
// RegisterRESTRoutes registers no REST routes for the genesis accounts module.
|
||||
func (AppModuleBasic) RegisterRESTRoutes(_ context.CLIContext, _ *mux.Router) {}
|
||||
|
||||
// GetTxCmd returns no root tx command for the genesis accounts module.
|
||||
func (AppModuleBasic) GetTxCmd(_ *codec.Codec) *cobra.Command { return nil }
|
||||
|
||||
// GetQueryCmd returns no root query command for the genesis accounts module.
|
||||
func (AppModuleBasic) GetQueryCmd(_ *codec.Codec) *cobra.Command { return nil }
|
||||
|
||||
// extra function from sdk.AppModuleBasic
|
||||
|
||||
// IterateGenesisAccounts iterates over the genesis accounts and perform an operation at each of them
|
||||
// - to used by other modules
|
||||
func (AppModuleBasic) IterateGenesisAccounts(cdc *codec.Codec, appGenesis map[string]json.RawMessage,
|
||||
iterateFn func(exported.Account) (stop bool)) {
|
||||
|
||||
genesisState := GetGenesisStateFromAppState(cdc, appGenesis)
|
||||
for _, genAcc := range genesisState {
|
||||
acc := genAcc.ToAccount()
|
||||
if iterateFn(acc) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
|
||||
// AppModuleSimulation defines the module simulation functions used by the genesis accounts module.
|
||||
type AppModuleSimulation struct{}
|
||||
|
||||
// RegisterStoreDecoder performs a no-op.
|
||||
func (AppModuleSimulation) RegisterStoreDecoder(_ sdk.StoreDecoderRegistry) {}
|
||||
|
||||
// GenerateGenesisState creates a randomized GenState of the genesis accounts module.
|
||||
func (AppModuleSimulation) GenerateGenesisState(simState *module.SimulationState) {
|
||||
simulation.RandomizedGenState(simState)
|
||||
}
|
||||
|
||||
// RandomizedParams doesn't create randomized genaccounts param changes for the simulator.
|
||||
func (AppModuleSimulation) RandomizedParams(_ *rand.Rand) []sim.ParamChange {
|
||||
return nil
|
||||
}
|
||||
|
||||
//____________________________________________________________________________
|
||||
|
||||
// AppModule implements an application module for the genesis accounts module.
|
||||
type AppModule struct {
|
||||
AppModuleBasic
|
||||
AppModuleSimulation
|
||||
|
||||
accountKeeper types.AccountKeeper
|
||||
}
|
||||
|
||||
// NewAppModule creates a new AppModule object
|
||||
func NewAppModule(accountKeeper types.AccountKeeper) AppModule {
|
||||
|
||||
return AppModule{
|
||||
AppModuleBasic: AppModuleBasic{},
|
||||
AppModuleSimulation: AppModuleSimulation{},
|
||||
accountKeeper: accountKeeper,
|
||||
}
|
||||
}
|
||||
|
||||
// RegisterInvariants is a placeholder function register no invariants
|
||||
func (AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {}
|
||||
|
||||
// Route empty module message route
|
||||
func (AppModule) Route() string { return "" }
|
||||
|
||||
// NewHandler returns an empty module handler
|
||||
func (AppModule) NewHandler() sdk.Handler { return nil }
|
||||
|
||||
// QuerierRoute returns an empty module querier route
|
||||
func (AppModule) QuerierRoute() string { return "" }
|
||||
|
||||
// NewQuerierHandler returns an empty module querier
|
||||
func (AppModule) NewQuerierHandler() sdk.Querier { return nil }
|
||||
|
||||
// InitGenesis performs genesis initialization for the genesis accounts module. It returns
|
||||
// no validator updates.
|
||||
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
|
||||
var genesisState GenesisState
|
||||
ModuleCdc.MustUnmarshalJSON(data, &genesisState)
|
||||
InitGenesis(ctx, ModuleCdc, am.accountKeeper, genesisState)
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
|
||||
// ExportGenesis returns the exported genesis state as raw bytes for the genesis accounts
|
||||
// module.
|
||||
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
|
||||
gs := ExportGenesis(ctx, am.accountKeeper)
|
||||
return ModuleCdc.MustMarshalJSON(gs)
|
||||
}
|
||||
|
||||
// BeginBlock returns an empty module begin-block
|
||||
func (AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) {}
|
||||
|
||||
// EndBlock returns an empty module end-block
|
||||
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) []abci.ValidatorUpdate {
|
||||
return []abci.ValidatorUpdate{}
|
||||
}
|
||||
@ -1,68 +0,0 @@
|
||||
package simulation
|
||||
|
||||
// DONTCOVER
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/types/module"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/genaccounts/internal/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/simulation"
|
||||
)
|
||||
|
||||
// RandomizedGenState generates a random GenesisState for the genesis accounts
|
||||
func RandomizedGenState(simState *module.SimulationState) {
|
||||
var genesisAccounts []types.GenesisAccount
|
||||
|
||||
// randomly generate some genesis accounts
|
||||
for i, acc := range simState.Accounts {
|
||||
coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(simState.InitialStake))}
|
||||
bacc := authtypes.NewBaseAccountWithAddress(acc.Address)
|
||||
if err := bacc.SetCoins(coins); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
var gacc types.GenesisAccount
|
||||
|
||||
// Only consider making a vesting account once the initial bonded validator
|
||||
// set is exhausted due to needing to track DelegatedVesting.
|
||||
if int64(i) > simState.NumBonded && simState.Rand.Intn(100) < 50 {
|
||||
var (
|
||||
vacc authexported.VestingAccount
|
||||
endTime int64
|
||||
)
|
||||
|
||||
startTime := simState.GenTimestamp.Unix()
|
||||
|
||||
// Allow for some vesting accounts to vest very quickly while others very slowly.
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime), int(startTime+(60*60*24*30))))
|
||||
} else {
|
||||
endTime = int64(simulation.RandIntBetween(simState.Rand, int(startTime), int(startTime+(60*60*12))))
|
||||
}
|
||||
|
||||
if startTime == endTime {
|
||||
endTime++
|
||||
}
|
||||
|
||||
if simState.Rand.Intn(100) < 50 {
|
||||
vacc = authtypes.NewContinuousVestingAccount(&bacc, startTime, endTime)
|
||||
} else {
|
||||
vacc = authtypes.NewDelayedVestingAccount(&bacc, endTime)
|
||||
}
|
||||
|
||||
var err error
|
||||
gacc, err = types.NewGenesisAccountI(vacc)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
} else {
|
||||
gacc = types.NewGenesisAccount(&bacc)
|
||||
}
|
||||
|
||||
genesisAccounts = append(genesisAccounts, gacc)
|
||||
}
|
||||
|
||||
simState.GenState[types.ModuleName] = simState.Cdc.MustMarshalJSON(genesisAccounts)
|
||||
}
|
||||
@ -15,10 +15,15 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
extypes "github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
v036 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_36"
|
||||
v038 "github.com/cosmos/cosmos-sdk/x/genutil/legacy/v0_38"
|
||||
)
|
||||
|
||||
// Allow applications to extend and modify the migration process.
|
||||
//
|
||||
// Ref: https://github.com/cosmos/cosmos-sdk/issues/5041
|
||||
var migrationMap = extypes.MigrationMap{
|
||||
"v0.36": v036.Migrate,
|
||||
"v0.38": v038.Migrate,
|
||||
}
|
||||
|
||||
const (
|
||||
|
||||
@ -20,10 +20,10 @@ import (
|
||||
func Migrate(appState genutil.AppMap) genutil.AppMap {
|
||||
v034Codec := codec.New()
|
||||
codec.RegisterCrypto(v034Codec)
|
||||
v034gov.RegisterCodec(v034Codec)
|
||||
|
||||
v036Codec := codec.New()
|
||||
codec.RegisterCrypto(v036Codec)
|
||||
v034gov.RegisterCodec(v034Codec)
|
||||
v036gov.RegisterCodec(v036Codec)
|
||||
|
||||
// migrate genesis accounts state
|
||||
|
||||
32
x/genutil/legacy/v0_38/migrate.go
Normal file
32
x/genutil/legacy/v0_38/migrate.go
Normal file
@ -0,0 +1,32 @@
|
||||
package v038
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
v036auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_36"
|
||||
v038auth "github.com/cosmos/cosmos-sdk/x/auth/legacy/v0_38"
|
||||
v036genaccounts "github.com/cosmos/cosmos-sdk/x/genaccounts/legacy/v0_36"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
)
|
||||
|
||||
// Migrate migrates exported state from v0.34 to a v0.36 genesis state.
|
||||
func Migrate(appState genutil.AppMap) genutil.AppMap {
|
||||
v036Codec := codec.New()
|
||||
codec.RegisterCrypto(v036Codec)
|
||||
|
||||
v038Codec := codec.New()
|
||||
codec.RegisterCrypto(v038Codec)
|
||||
|
||||
if appState[v036genaccounts.ModuleName] != nil {
|
||||
var authGenState v036auth.GenesisState
|
||||
v036Codec.MustUnmarshalJSON(appState[v036auth.ModuleName], &authGenState)
|
||||
|
||||
appState[v038auth.ModuleName] = v038Codec.MustMarshalJSON(
|
||||
v038auth.Migrate(authGenState, appState[v036genaccounts.ModuleName]),
|
||||
)
|
||||
|
||||
// delete deprecated genaccounts genesis state
|
||||
delete(appState, v036genaccounts.ModuleName)
|
||||
}
|
||||
|
||||
return appState
|
||||
}
|
||||
@ -1,18 +1,31 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/supply/exported"
|
||||
)
|
||||
|
||||
var _ exported.ModuleAccountI = (*ModuleAccount)(nil)
|
||||
var (
|
||||
_ authexported.GenesisAccount = (*ModuleAccount)(nil)
|
||||
_ exported.ModuleAccountI = (*ModuleAccount)(nil)
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Register the ModuleAccount type as a GenesisAccount so that when no
|
||||
// concrete GenesisAccount types exist and **default** genesis state is used,
|
||||
// the genesis state will serialize correctly.
|
||||
authtypes.RegisterAccountTypeCodec(&ModuleAccount{}, "cosmos-sdk/ModuleAccount")
|
||||
}
|
||||
|
||||
// ModuleAccount defines an account for modules that holds coins on a pool
|
||||
type ModuleAccount struct {
|
||||
@ -26,6 +39,7 @@ func NewModuleAddress(name string) sdk.AccAddress {
|
||||
return sdk.AccAddress(crypto.AddressHash([]byte(name)))
|
||||
}
|
||||
|
||||
// NewEmptyModuleAccount creates a empty ModuleAccount from a string
|
||||
func NewEmptyModuleAccount(name string, permissions ...string) *ModuleAccount {
|
||||
moduleAddress := NewModuleAddress(name)
|
||||
baseAcc := authtypes.NewBaseAccountWithAddress(moduleAddress)
|
||||
@ -95,6 +109,18 @@ func (ma ModuleAccount) String() string {
|
||||
return string(b)
|
||||
}
|
||||
|
||||
// Validate checks for errors on the account fields
|
||||
func (ma ModuleAccount) Validate() error {
|
||||
if strings.TrimSpace(ma.Name) == "" {
|
||||
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)
|
||||
}
|
||||
|
||||
return ma.BaseAccount.Validate()
|
||||
}
|
||||
|
||||
// MarshalYAML returns the YAML representation of a ModuleAccount.
|
||||
func (ma ModuleAccount) MarshalYAML() (interface{}, error) {
|
||||
bs, err := yaml.Marshal(struct {
|
||||
|
||||
@ -1,13 +1,18 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
authexported "github.com/cosmos/cosmos-sdk/x/auth/exported"
|
||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
@ -58,3 +63,35 @@ func TestHasPermissions(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestValidate(t *testing.T) {
|
||||
addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
|
||||
baseAcc := authtypes.NewBaseAccount(addr, sdk.Coins{}, nil, 0, 0)
|
||||
tests := []struct {
|
||||
name string
|
||||
acc authexported.GenesisAccount
|
||||
expErr error
|
||||
}{
|
||||
{
|
||||
"valid module account",
|
||||
NewEmptyModuleAccount("test"),
|
||||
nil,
|
||||
},
|
||||
{
|
||||
"invalid name and address pair",
|
||||
NewModuleAccount(baseAcc, "test"),
|
||||
fmt.Errorf("address %s cannot be derived from the module name 'test'", addr),
|
||||
},
|
||||
{
|
||||
"empty module account name",
|
||||
NewModuleAccount(baseAcc, " "),
|
||||
errors.New("module account name cannot be blank"),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := tt.acc.Validate()
|
||||
require.Equal(t, tt.expErr, err)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user