From 09b0f589321decea297ed35b79401db949025943 Mon Sep 17 00:00:00 2001 From: likhita-809 <78951027+likhita-809@users.noreply.github.com> Date: Sat, 24 Sep 2022 00:55:36 +0530 Subject: [PATCH] feat: make helper function for adding accounts to genesis state (#13298) --- CHANGELOG.md | 1 + simapp/simd/cmd/genaccounts.go | 119 +--------------------------- x/auth/helpers/genaccounts.go | 137 +++++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 116 deletions(-) create mode 100644 x/auth/helpers/genaccounts.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 42b560b67068..b36753c1e5af 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### Features +* [#13298](https://github.com/cosmos/cosmos-sdk/pull/13298) Add `AddGenesisAccount` helper func in x/auth module which helps adding accounts to genesis state. * (cli) [#13353](https://github.com/cosmos/cosmos-sdk/pull/13353) Add `tx group draft-proposal` command for generating group proposal JSONs (skeleton). * (cli) [#13304](https://github.com/cosmos/cosmos-sdk/pull/13304) Add `tx gov draft-proposal` command for generating proposal JSONs (skeleton). * (cli) [#13207](https://github.com/cosmos/cosmos-sdk/pull/13207) Reduce user's password prompts when calling keyring `List()` function diff --git a/simapp/simd/cmd/genaccounts.go b/simapp/simd/cmd/genaccounts.go index 862a061a4e20..d04f36d62d20 100644 --- a/simapp/simd/cmd/genaccounts.go +++ b/simapp/simd/cmd/genaccounts.go @@ -2,8 +2,6 @@ package cmd import ( "bufio" - "encoding/json" - "errors" "fmt" "github.com/spf13/cobra" @@ -13,11 +11,7 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keyring" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" - authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" - banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" - "github.com/cosmos/cosmos-sdk/x/genutil" - genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + auth "github.com/cosmos/cosmos-sdk/x/auth/helpers" ) const ( @@ -72,119 +66,12 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa } } - coins, err := sdk.ParseCoinsNormalized(args[1]) - if err != nil { - return fmt.Errorf("failed to parse coins: %w", err) - } - + appendflag, _ := cmd.Flags().GetBool(flagAppendMode) vestingStart, _ := cmd.Flags().GetInt64(flagVestingStart) vestingEnd, _ := cmd.Flags().GetInt64(flagVestingEnd) vestingAmtStr, _ := cmd.Flags().GetString(flagVestingAmt) - vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) - if err != nil { - return fmt.Errorf("failed to parse vesting amount: %w", err) - } - - // create concrete account type based on input parameters - var genAccount authtypes.GenesisAccount - - balances := banktypes.Balance{Address: addr.String(), Coins: coins.Sort()} - baseAccount := authtypes.NewBaseAccount(addr, nil, 0, 0) - - if !vestingAmt.IsZero() { - baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) - - if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || - baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { - return errors.New("vesting amount cannot be greater than total amount") - } - - switch { - case vestingStart != 0 && vestingEnd != 0: - genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) - - case vestingEnd != 0: - genAccount = authvesting.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 := genutiltypes.GenesisStateFromGenFile(genFile) - if err != nil { - return fmt.Errorf("failed to unmarshal genesis state: %w", err) - } - - authGenState := authtypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - - accs, err := authtypes.UnpackAccounts(authGenState.Accounts) - if err != nil { - return fmt.Errorf("failed to get accounts from any: %w", err) - } - - bankGenState := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - if accs.Contains(addr) { - appendflag, _ := cmd.Flags().GetBool(flagAppendMode) - if !appendflag { - return fmt.Errorf("cannot add account at existing address %s", addr) - } - - genesisB := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState) - for idx, acc := range genesisB.Balances { - if acc.Address != addr.String() { - continue - } - - updatedCoins := acc.Coins.Add(coins...) - bankGenState.Balances[idx] = banktypes.Balance{Address: addr.String(), Coins: updatedCoins.Sort()} - break - } - } else { - // Add the new account to the set of genesis accounts and sanitize the accounts afterwards. - accs = append(accs, genAccount) - accs = authtypes.SanitizeGenesisAccounts(accs) - - genAccs, err := authtypes.PackAccounts(accs) - if err != nil { - return fmt.Errorf("failed to convert accounts into any's: %w", err) - } - authGenState.Accounts = genAccs - - authGenStateBz, err := clientCtx.Codec.MarshalJSON(&authGenState) - if err != nil { - return fmt.Errorf("failed to marshal auth genesis state: %w", err) - } - appState[authtypes.ModuleName] = authGenStateBz - - bankGenState.Balances = append(bankGenState.Balances, balances) - } - - bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) - - bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) - - bankGenStateBz, err := clientCtx.Codec.MarshalJSON(bankGenState) - if err != nil { - return fmt.Errorf("failed to marshal bank genesis state: %w", err) - } - appState[banktypes.ModuleName] = bankGenStateBz - - appStateJSON, err := json.Marshal(appState) - if err != nil { - return fmt.Errorf("failed to marshal application genesis state: %w", err) - } - - genDoc.AppState = appStateJSON - return genutil.ExportGenesisFile(genDoc, genFile) + return auth.AddGenesisAccount(clientCtx.Codec, addr, appendflag, config.GenesisFile(), args[1], vestingAmtStr, vestingStart, vestingEnd) }, } diff --git a/x/auth/helpers/genaccounts.go b/x/auth/helpers/genaccounts.go new file mode 100644 index 000000000000..00ee73c18e52 --- /dev/null +++ b/x/auth/helpers/genaccounts.go @@ -0,0 +1,137 @@ +package helpers + +import ( + "encoding/json" + "errors" + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + authvesting "github.com/cosmos/cosmos-sdk/x/auth/vesting/types" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +// AddGenesisAccount adds a genesis account to the genesis state. +// Where `cdc` is client codec, `genesisFileUrl` is the path/url of current genesis file, +// `accAddr` is the address to be added to the genesis state, `amountStr` is the list of initial coins +// to be added for the account, `appendAcct` updates the account if already exists. +// `vestingStart, vestingEnd and vestingAmtStr` respectively are the schedule start time, end time (unix epoch) +// and coins to be appended to the account already in the genesis.json file. +func AddGenesisAccount( + cdc codec.Codec, + accAddr sdk.AccAddress, + appendAcct bool, + genesisFileUrl, amountStr, vestingAmtStr string, + vestingStart, vestingEnd int64, +) error { + coins, err := sdk.ParseCoinsNormalized(amountStr) + if err != nil { + return fmt.Errorf("failed to parse coins: %w", err) + } + + vestingAmt, err := sdk.ParseCoinsNormalized(vestingAmtStr) + if err != nil { + return fmt.Errorf("failed to parse vesting amount: %w", err) + } + + // create concrete account type based on input parameters + var genAccount authtypes.GenesisAccount + + balances := banktypes.Balance{Address: accAddr.String(), Coins: coins.Sort()} + baseAccount := authtypes.NewBaseAccount(accAddr, nil, 0, 0) + + if !vestingAmt.IsZero() { + baseVestingAccount := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) + + if (balances.Coins.IsZero() && !baseVestingAccount.OriginalVesting.IsZero()) || + baseVestingAccount.OriginalVesting.IsAnyGT(balances.Coins) { + return errors.New("vesting amount cannot be greater than total amount") + } + + switch { + case vestingStart != 0 && vestingEnd != 0: + genAccount = authvesting.NewContinuousVestingAccountRaw(baseVestingAccount, vestingStart) + + case vestingEnd != 0: + genAccount = authvesting.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) + } + + appState, genDoc, err := genutiltypes.GenesisStateFromGenFile(genesisFileUrl) + if err != nil { + return fmt.Errorf("failed to unmarshal genesis state: %w", err) + } + + authGenState := authtypes.GetGenesisStateFromAppState(cdc, appState) + + accs, err := authtypes.UnpackAccounts(authGenState.Accounts) + if err != nil { + return fmt.Errorf("failed to get accounts from any: %w", err) + } + + bankGenState := banktypes.GetGenesisStateFromAppState(cdc, appState) + if accs.Contains(accAddr) { + if !appendAcct { + return fmt.Errorf(" Account %s already exists\nUse `append` flag to append account at existing address", accAddr) + } + + genesisB := banktypes.GetGenesisStateFromAppState(cdc, appState) + for idx, acc := range genesisB.Balances { + if acc.Address != accAddr.String() { + continue + } + + updatedCoins := acc.Coins.Add(coins...) + bankGenState.Balances[idx] = banktypes.Balance{Address: accAddr.String(), Coins: updatedCoins.Sort()} + break + } + } else { + // Add the new account to the set of genesis accounts and sanitize the accounts afterwards. + accs = append(accs, genAccount) + accs = authtypes.SanitizeGenesisAccounts(accs) + + genAccs, err := authtypes.PackAccounts(accs) + if err != nil { + return fmt.Errorf("failed to convert accounts into any's: %w", err) + } + authGenState.Accounts = genAccs + + authGenStateBz, err := cdc.MarshalJSON(&authGenState) + if err != nil { + return fmt.Errorf("failed to marshal auth genesis state: %w", err) + } + appState[authtypes.ModuleName] = authGenStateBz + + bankGenState.Balances = append(bankGenState.Balances, balances) + } + + bankGenState.Balances = banktypes.SanitizeGenesisBalances(bankGenState.Balances) + + bankGenState.Supply = bankGenState.Supply.Add(balances.Coins...) + + bankGenStateBz, err := cdc.MarshalJSON(bankGenState) + if err != nil { + return fmt.Errorf("failed to marshal bank genesis state: %w", err) + } + appState[banktypes.ModuleName] = bankGenStateBz + + appStateJSON, err := json.Marshal(appState) + if err != nil { + return fmt.Errorf("failed to marshal application genesis state: %w", err) + } + + genDoc.AppState = appStateJSON + return genutil.ExportGenesisFile(genDoc, genesisFileUrl) +}