Merge PR #3549: Support Vesting Accounts in add-genesis-account
This commit is contained in:
parent
b5fdb83830
commit
d759bef4d1
@ -46,6 +46,8 @@ FEATURES
|
||||
* [\#3429](https://github.com/cosmos/cosmos-sdk/issues/3429) Support querying
|
||||
for all delegator distribution rewards.
|
||||
* \#3449 Proof verification now works with absence proofs
|
||||
* [\#3484](https://github.com/cosmos/cosmos-sdk/issues/3484) Add support
|
||||
vesting accounts to the add-genesis-account command.
|
||||
|
||||
* Gaia
|
||||
- [\#3397](https://github.com/cosmos/cosmos-sdk/pull/3397) Implement genesis file sanitization to avoid failures at chain init.
|
||||
|
||||
@ -8,6 +8,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
@ -34,15 +35,22 @@ const (
|
||||
feeDenom = "feetoken"
|
||||
fee2Denom = "fee2token"
|
||||
keyBaz = "baz"
|
||||
keyVesting = "vesting"
|
||||
keyFooBarBaz = "foobarbaz"
|
||||
)
|
||||
|
||||
var startCoins = sdk.Coins{
|
||||
sdk.NewCoin(feeDenom, staking.TokensFromTendermintPower(1000000)),
|
||||
sdk.NewCoin(fee2Denom, staking.TokensFromTendermintPower(1000000)),
|
||||
sdk.NewCoin(fooDenom, staking.TokensFromTendermintPower(1000)),
|
||||
sdk.NewCoin(denom, staking.TokensFromTendermintPower(150)),
|
||||
}
|
||||
var (
|
||||
startCoins = sdk.Coins{
|
||||
sdk.NewCoin(feeDenom, staking.TokensFromTendermintPower(1000000)),
|
||||
sdk.NewCoin(fee2Denom, staking.TokensFromTendermintPower(1000000)),
|
||||
sdk.NewCoin(fooDenom, staking.TokensFromTendermintPower(1000)),
|
||||
sdk.NewCoin(denom, staking.TokensFromTendermintPower(150)),
|
||||
}
|
||||
|
||||
vestingCoins = sdk.Coins{
|
||||
sdk.NewCoin(feeDenom, staking.TokensFromTendermintPower(500000)),
|
||||
}
|
||||
)
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// Fixtures
|
||||
@ -108,6 +116,7 @@ func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||
f.KeysAdd(keyFoo)
|
||||
f.KeysAdd(keyBar)
|
||||
f.KeysAdd(keyBaz)
|
||||
f.KeysAdd(keyVesting)
|
||||
f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
|
||||
"--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz))
|
||||
|
||||
@ -120,6 +129,12 @@ func InitFixtures(t *testing.T) (f *Fixtures) {
|
||||
|
||||
// Start an account with tokens
|
||||
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
|
||||
f.AddGenesisAccount(
|
||||
f.KeyAddress(keyVesting), startCoins,
|
||||
fmt.Sprintf("--vesting-amount=%s", vestingCoins),
|
||||
fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()),
|
||||
fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
|
||||
)
|
||||
f.GenTx(keyFoo)
|
||||
f.CollectGenTxs()
|
||||
return
|
||||
|
||||
@ -16,7 +16,7 @@ import (
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
)
|
||||
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||
func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
|
||||
@ -32,22 +32,32 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
|
||||
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
|
||||
}
|
||||
coins.Sort()
|
||||
|
||||
vestingStart := viper.GetInt64(flagVestingStart)
|
||||
vestingEnd := viper.GetInt64(flagVestingEnd)
|
||||
vestingAmt, err := sdk.ParseCoins(viper.GetString(flagVestingAmt))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
if !common.FileExists(genFile) {
|
||||
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
|
||||
}
|
||||
|
||||
genDoc, err := LoadGenesisDoc(cdc, genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -58,7 +68,7 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
|
||||
return err
|
||||
}
|
||||
|
||||
appState, err = addGenesisAccount(cdc, appState, addr, coins)
|
||||
appState, err = addGenesisAccount(cdc, appState, addr, coins, vestingAmt, vestingStart, vestingEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -74,10 +84,18 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "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
|
||||
}
|
||||
|
||||
func addGenesisAccount(cdc *codec.Codec, appState app.GenesisState, addr sdk.AccAddress, coins sdk.Coins) (app.GenesisState, error) {
|
||||
func addGenesisAccount(
|
||||
cdc *codec.Codec, appState app.GenesisState, addr sdk.AccAddress,
|
||||
coins, vestingAmt sdk.Coins, vestingStart, vestingEnd int64,
|
||||
) (app.GenesisState, error) {
|
||||
|
||||
for _, stateAcc := range appState.Accounts {
|
||||
if stateAcc.Address.Equals(addr) {
|
||||
return appState, fmt.Errorf("the application state already contains account %v", addr)
|
||||
@ -86,6 +104,38 @@ func addGenesisAccount(cdc *codec.Codec, appState app.GenesisState, addr sdk.Acc
|
||||
|
||||
acc := auth.NewBaseAccountWithAddress(addr)
|
||||
acc.Coins = coins
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc))
|
||||
|
||||
if !vestingAmt.IsZero() {
|
||||
var vacc auth.VestingAccount
|
||||
|
||||
bvacc := &auth.BaseVestingAccount{
|
||||
BaseAccount: &acc,
|
||||
OriginalVesting: vestingAmt,
|
||||
EndTime: vestingEnd,
|
||||
}
|
||||
|
||||
if bvacc.OriginalVesting.IsAllGT(acc.Coins) {
|
||||
return appState, fmt.Errorf("vesting amount cannot be greater than total amount")
|
||||
}
|
||||
if vestingStart >= vestingEnd {
|
||||
return appState, fmt.Errorf("vesting start time must before end time")
|
||||
}
|
||||
|
||||
if vestingStart != 0 {
|
||||
vacc = &auth.ContinuousVestingAccount{
|
||||
BaseVestingAccount: bvacc,
|
||||
StartTime: vestingStart,
|
||||
}
|
||||
} else {
|
||||
vacc = &auth.DelayedVestingAccount{
|
||||
BaseVestingAccount: bvacc,
|
||||
}
|
||||
}
|
||||
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccountI(vacc))
|
||||
} else {
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc))
|
||||
}
|
||||
|
||||
return appState, nil
|
||||
}
|
||||
|
||||
@ -15,9 +15,12 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||
cdc := codec.New()
|
||||
addr1 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
|
||||
type args struct {
|
||||
appState app.GenesisState
|
||||
addr sdk.AccAddress
|
||||
coins sdk.Coins
|
||||
appState app.GenesisState
|
||||
addr sdk.AccAddress
|
||||
coins sdk.Coins
|
||||
vestingAmt sdk.Coins
|
||||
vestingStart int64
|
||||
vestingEnd int64
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -30,16 +33,55 @@ func TestAddGenesisAccount(t *testing.T) {
|
||||
app.GenesisState{},
|
||||
addr1,
|
||||
sdk.Coins{},
|
||||
sdk.Coins{},
|
||||
0,
|
||||
0,
|
||||
},
|
||||
false},
|
||||
{"dup account", args{
|
||||
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
||||
addr1,
|
||||
sdk.Coins{}}, true},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"dup account",
|
||||
args{
|
||||
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
|
||||
addr1,
|
||||
sdk.Coins{},
|
||||
sdk.Coins{},
|
||||
0,
|
||||
0,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid vesting amount",
|
||||
args{
|
||||
app.GenesisState{},
|
||||
addr1,
|
||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
||||
sdk.Coins{sdk.NewInt64Coin("stake", 100)},
|
||||
0,
|
||||
0,
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"invalid vesting times",
|
||||
args{
|
||||
app.GenesisState{},
|
||||
addr1,
|
||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
||||
sdk.Coins{sdk.NewInt64Coin("stake", 50)},
|
||||
1654668078,
|
||||
1554668078,
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
_, err := addGenesisAccount(cdc, tt.args.appState, tt.args.addr, tt.args.coins)
|
||||
_, err := addGenesisAccount(
|
||||
cdc, tt.args.appState, tt.args.addr, tt.args.coins,
|
||||
tt.args.vestingAmt, tt.args.vestingStart, tt.args.vestingEnd,
|
||||
)
|
||||
require.Equal(t, tt.wantErr, (err != nil))
|
||||
})
|
||||
}
|
||||
|
||||
@ -19,8 +19,11 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagVestingStart = "vesting-start-time"
|
||||
flagVestingEnd = "vesting-end-time"
|
||||
flagVestingAmt = "vesting-amount"
|
||||
)
|
||||
|
||||
type printInfo struct {
|
||||
@ -31,19 +34,19 @@ type printInfo struct {
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}
|
||||
|
||||
// nolint: errcheck
|
||||
func displayInfo(cdc *codec.Codec, info printInfo) error {
|
||||
out, err := codec.MarshalJSONIndent(cdc, info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out)) // nolint: errcheck
|
||||
return nil
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
// nolint
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
// InitCmd returns a command that initializes all files needed for Tendermint
|
||||
// and the respective application.
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { // nolint: golint
|
||||
cmd := &cobra.Command{
|
||||
Use: "init [moniker]",
|
||||
Short: "Initialize private validator, p2p, genesis, and application configuration files",
|
||||
@ -80,7 +83,6 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user