Skip to content

Commit

Permalink
feat: update logic add genesis account (#408) (#410)
Browse files Browse the repository at this point in the history
* update logic add genesis account

* fix wrong name file

* feat: update changelog

* delete extra white space

Co-authored-by: Roman <roman@osmosis.team>

---------

Co-authored-by: Roman <roman@osmosis.team>
(cherry picked from commit 7778778)

Co-authored-by: Nguyen Thanh Nhan <thanhnhan98qh@gmail.com>
  • Loading branch information
mergify[bot] and ThanhNhann authored Feb 8, 2023
1 parent 7a958cb commit 4937288
Show file tree
Hide file tree
Showing 3 changed files with 145 additions and 106 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* [\#10922](https://github.com/cosmos/cosmos-sdk/pull/10922), [/#10956](https://github.com/cosmos/cosmos-sdk/pull/10956) Deprecate key `server.Generate*` functions and move them to `testutil` and support custom mnemonics in in-process testing network. Moved `TestMnemonic` from `testutil` package to `testdata`.

### Features

* [\#408](https://github.com/osmosis-labs/cosmos-sdk/pull/408) Add `AddGenesisAccount` helper func in x/auth module which helps adding accounts to genesis state.
* [\#10614](https://github.com/cosmos/cosmos-sdk/pull/10614) Support in-place migration ordering

### Improvements
Expand Down
112 changes: 7 additions & 105 deletions simapp/simd/cmd/genaccounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,23 @@ package cmd

import (
"bufio"
"encoding/json"
"errors"
"fmt"

"github.com/spf13/cobra"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"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"

"github.com/spf13/cobra"
)

const (
flagVestingStart = "vesting-start-time"
flagVestingEnd = "vesting-end-time"
flagVestingAmt = "vesting-amount"
flagAppendMode = "append"
)

// AddGenesisAccountCmd returns add-genesis-account cobra Command.
Expand Down Expand Up @@ -66,106 +61,12 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
addr = info.GetAddress()
}

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)
}

if accs.Contains(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.
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 := banktypes.GetGenesisStateFromAppState(clientCtx.Codec, appState)
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)
},
}

Expand All @@ -174,6 +75,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
cmd.Flags().Int64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
cmd.Flags().Int64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
cmd.Flags().Bool(flagAppendMode, false, "append the coins to an account already in the genesis.json file")
flags.AddQueryFlagsToCmd(cmd)

return cmd
Expand Down
137 changes: 137 additions & 0 deletions x/auth/helpers/genaccounts.go
Original file line number Diff line number Diff line change
@@ -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)
}

0 comments on commit 4937288

Please sign in to comment.