diff --git a/app/app.go b/app/app.go index 6154cb73..b1d298a7 100644 --- a/app/app.go +++ b/app/app.go @@ -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" @@ -41,7 +40,6 @@ var ( // ModuleBasics manages simple versions of full app modules. It's used for things such as codec registration and genesis file verification. ModuleBasics = module.NewBasicManager( - genaccounts.AppModuleBasic{}, genutil.AppModuleBasic{}, auth.AppModuleBasic{}, bank.AppModuleBasic{}, @@ -206,7 +204,6 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, // create the module manager (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), @@ -228,7 +225,7 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, // genutils must occur after staking so that pools are properly // initialized with tokens from genesis accounts. - app.mm.SetOrderInitGenesis(genaccounts.ModuleName, distr.ModuleName, + app.mm.SetOrderInitGenesis(auth.ModuleName, distr.ModuleName, staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, supply.ModuleName, crisis.ModuleName, genutil.ModuleName) @@ -240,7 +237,6 @@ func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool, // NOTE: This is not required for 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), diff --git a/app/genesis.go b/app/genesis.go index d6af7e32..5602b64f 100644 --- a/app/genesis.go +++ b/app/genesis.go @@ -2,6 +2,9 @@ package app import ( "encoding/json" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/exported" ) // GenesisState represents the genesis state of the blockchain. It is a map from module names to module genesis states. @@ -11,3 +14,22 @@ type GenesisState map[string]json.RawMessage func NewDefaultGenesisState() GenesisState { return ModuleBasics.DefaultGenesis() } + +// TODO remove iterator once merged into sdk master +type GenesisAccountIterator struct{} +// IterateGenesisAccounts iterates over all the genesis accounts found in +// appGenesis and invokes a callback on each genesis account. If any call +// returns true, iteration stops. +func (GenesisAccountIterator) IterateGenesisAccounts( + cdc *codec.Codec, appGenesis map[string]json.RawMessage, cb func(exported.Account) (stop bool), +) { + + var authGenState auth.GenesisState + cdc.MustUnmarshalJSON(appGenesis[auth.ModuleName], &authGenState) + + for _, genAcc := range authGenState.Accounts { + if cb(genAcc) { + break + } + } +} \ No newline at end of file diff --git a/cli_test/cli_test.go b/cli_test/cli_test.go index a242a6ef..9e7df17d 100644 --- a/cli_test/cli_test.go +++ b/cli_test/cli_test.go @@ -23,7 +23,6 @@ import ( "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/genaccounts" "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/mint" @@ -1307,12 +1306,16 @@ func TestGaiadAddGenesisAccount(t *testing.T) { genesisState := f.GenesisState() cdc := app.MakeCodec() - accounts := genaccounts.GetGenesisStateFromAppState(cdc, genesisState) - require.Equal(t, accounts[0].Address, f.KeyAddress(keyFoo)) - require.Equal(t, accounts[1].Address, f.KeyAddress(keyBar)) - require.True(t, accounts[0].Coins.IsEqual(startCoins)) - require.True(t, accounts[1].Coins.IsEqual(bazCoins)) + // TODO maybe replace once sdk updated + var authGenState auth.GenesisState + cdc.MustUnmarshalJSON(genesisState[auth.ModuleName], &authGenState) + accounts := authGenState.Accounts + + require.Equal(t, accounts[0].GetAddress(), f.KeyAddress(keyFoo)) + require.Equal(t, accounts[1].GetAddress(), f.KeyAddress(keyBar)) + require.True(t, accounts[0].GetCoins().IsEqual(startCoins)) + require.True(t, accounts[1].GetCoins().IsEqual(bazCoins)) // Cleanup testing directories f.Cleanup() diff --git a/cmd/kvd/add_account.go b/cmd/kvd/add_account.go new file mode 100644 index 00000000..a9fc9a2d --- /dev/null +++ b/cmd/kvd/add_account.go @@ -0,0 +1,150 @@ +package main + +import ( + "errors" + "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/auth" + authexported "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/genutil" +) + +const ( + flagClientHome = "home-client" + flagVestingStart = "vesting-start-time" + flagVestingEnd = "vesting-end-time" + flagVestingAmt = "vesting-amount" +) + +// AddGenesisAccountCmd returns an 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 a genesis account to genesis.json", + Long: `Add a genesis account to genesis.json. The provided account must specify + the account address or key name and a list of initial coins. If a key name is given, + the address will be looked up in the local Keybase. The list of initial tokens must + contain valid denominations. Accounts may optionally be supplied with vesting parameters. + `, + 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 { + // attempt to lookup address from Keybase if no address was provided + kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome)) + if err != nil { + return err + } + + info, err := kb.Get(args[0]) + if err != nil { + return fmt.Errorf("failed to get address from Keybase: %w", err) + } + + addr = info.GetAddress() + } + + coins, err := sdk.ParseCoins(args[1]) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + vestingStart := viper.GetInt64(flagVestingStart) + vestingEnd := viper.GetInt64(flagVestingEnd) + vestingAmt, err := sdk.ParseCoins(viper.GetString(flagVestingAmt)) + if err != nil { + return fmt.Errorf("failed to parse vesting amount: %w", err) + } + + // create concrete account type based on input parameters + var genAccount authexported.GenesisAccount + + baseAccount := auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0) + if !vestingAmt.IsZero() { + baseVestingAccount := auth.NewBaseVestingAccount( + baseAccount, vestingAmt.Sort(), sdk.Coins{}, sdk.Coins{}, vestingEnd, + ) + + switch { + case vestingStart != 0 && vestingEnd != 0: + genAccount = auth.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) + + case vestingEnd != 0: + genAccount = auth.NewDelayedVestingAccountRaw(baseVestingAccount) + + default: + return errors.New("invalid vesting parameters; must supply start and end time or end time") + } + } else { + genAccount = baseAccount + } + + if err := genAccount.Validate(); err != nil { + return fmt.Errorf("failed to validate new genesis account: %w", err) + } + + genFile := config.GenesisFile() + appState, genDoc, err := genutil.GenesisStateFromGenFile(cdc, genFile) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + // authGenState := auth.GetGenesisStateFromAppState(cdc, appState) + // TODO replace 2 following lines with above once sdk updated + var authGenState auth.GenesisState + cdc.MustUnmarshalJSON(appState[auth.ModuleName], &authGenState) + + // if authGenState.Accounts.Contains(addr) { + // TODO replace loop below with above once sdk is updated + for _, acc := range authGenState.Accounts { + if acc.GetAddress().Equals(addr) { + return fmt.Errorf("cannot add account at existing address %s", addr) + } + } + + // Add the new account to the set of genesis accounts and sanitize the + // accounts afterwards. + authGenState.Accounts = append(authGenState.Accounts, genAccount) + // TODO uncomment following line once merged into master + // authGenState.Accounts = auth.SanitizeGenesisAccounts(authGenState.Accounts) + + authGenStateBz, err := cdc.MarshalJSON(authGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + + appState[auth.ModuleName] = authGenStateBz + + appStateJSON, err := cdc.MarshalJSON(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + 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 +} diff --git a/cmd/kvd/main.go b/cmd/kvd/main.go index cfffa083..0b9324d4 100644 --- a/cmd/kvd/main.go +++ b/cmd/kvd/main.go @@ -18,8 +18,6 @@ import ( "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/store" sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/genaccounts" - genaccscli "github.com/cosmos/cosmos-sdk/x/genaccounts/client/cli" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" "github.com/cosmos/cosmos-sdk/x/staking" @@ -47,18 +45,18 @@ func main() { } rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome)) - rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, genaccounts.AppModuleBasic{}, app.DefaultNodeHome)) + rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, app.GenesisAccountIterator{}, app.DefaultNodeHome)) rootCmd.AddCommand(genutilcli.MigrateGenesisCmd(ctx, cdc)) rootCmd.AddCommand(genutilcli.GenTxCmd( ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{}, - genaccounts.AppModuleBasic{}, + app.GenesisAccountIterator{}, app.DefaultNodeHome, app.DefaultCLIHome)) rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics)) - rootCmd.AddCommand(genaccscli.AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) + rootCmd.AddCommand(AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true)) server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators) diff --git a/go.mod b/go.mod index fc66793d..f30c4997 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/kava-labs/kava go 1.13 require ( - github.com/cosmos/cosmos-sdk v0.34.4-0.20190910181238-84627faf79eb + github.com/cosmos/cosmos-sdk v0.34.4-0.20190912192225-ed6366679c38 github.com/spf13/cobra v0.0.5 github.com/spf13/viper v1.4.0 github.com/stretchr/testify v1.4.0 diff --git a/go.sum b/go.sum index 6f596edc..3d286f74 100644 --- a/go.sum +++ b/go.sum @@ -41,9 +41,12 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc github.com/cosmos/cosmos-sdk v0.34.4-0.20190910181238-84627faf79eb h1:VKEfR1unkvgquOUgGcuXq6gPXDd7L125MSuCSEmthNM= github.com/cosmos/cosmos-sdk v0.34.4-0.20190910181238-84627faf79eb/go.mod h1:De67lt7tcfjIhSv58L/96UEdMvR3GZhOtvHntfEglDA= github.com/cosmos/cosmos-sdk v0.34.4-0.20190911185636-5bcab79e8aef/go.mod h1:WFgmzqlpCWWhon5UF59Nu3olrxCUB3+S/GzTeUyfs1U= +github.com/cosmos/cosmos-sdk v0.34.4-0.20190912192225-ed6366679c38 h1:c9YDbAZ92KeCxGQQ54GsCcrqNbnNLHrVgJoWDI81qxs= +github.com/cosmos/cosmos-sdk v0.34.4-0.20190912192225-ed6366679c38/go.mod h1:WFgmzqlpCWWhon5UF59Nu3olrxCUB3+S/GzTeUyfs1U= github.com/cosmos/cosmos-sdk v0.36.0 h1:nDHhZDeucmv/PoThz89Q8cj9S8OH2EUutgertz2pZ90= github.com/cosmos/cosmos-sdk v0.36.0/go.mod h1:3b/k/Zd+YDuttSmEJdNkxga1H5EIiDUhSYeErAHQN7A= github.com/cosmos/cosmos-sdk v0.37.0 h1:S2I3NDGN2wqfGlY5KqkAHTpfezjhgeqDxrCxhlhd528= +github.com/cosmos/cosmos-sdk v0.37.0/go.mod h1:3b/k/Zd+YDuttSmEJdNkxga1H5EIiDUhSYeErAHQN7A= github.com/cosmos/gaia v1.0.0 h1:Wu4nH0t5hpKiU5WeIPDnun7kHcO8ijMXvMjF+yb9wS4= github.com/cosmos/gaia v1.0.0/go.mod h1:hqavT29EEm4CBBe1ONUggGWecpPTcolOlkqv93C6yAQ= github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=