From b9477ecbbec2a537a57db5c6d95839e07ccc0b4b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Apr 2018 16:12:14 -0400 Subject: [PATCH] init refactor uses genesis transaction now --- cmd/gaia/app/app.go | 183 +++++++++++------------- cmd/gaia/cli_test/cli_test.go | 61 ++++---- examples/democoin/cmd/democoind/main.go | 9 +- mock/app.go | 24 ++-- mock/app_test.go | 5 +- server/init.go | 149 ++++++++++++------- server/init_test.go | 3 +- server/start_test.go | 6 +- 8 files changed, 237 insertions(+), 203 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 37c062595..eb63c6f1a 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -3,7 +3,6 @@ package app import ( "encoding/json" "errors" - "strings" "github.com/spf13/pflag" "github.com/spf13/viper" @@ -185,141 +184,123 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } var ( - flagAccounts = "accounts" - flagChainID = "chain-id" - flagOWK = "overwrite-keys" + flagName = "name" + //flagOWK = "overwrite-keys" ) // get app init parameters for server init command func GaiaAppInit() server.AppInit { - fs := pflag.NewFlagSet("", pflag.ContinueOnError) - fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval:name2-coins-isval:...") - fs.String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created") - fs.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") + fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError) + //fsAppGenState.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") + + fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError) + fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator") + return server.AppInit{ - Flags: fs, - GenAppParams: GaiaGenAppParams, - AppendAppState: GaiaAppendAppState, + FlagsAppGenState: fsAppGenState, + FlagsAppGenTx: fsAppGenTx, + AppGenState: GaiaAppGenState, + AppGenTx: GaiaAppGenTx, } } +// simple genesis tx +type GaiaGenTx struct { + Name string `json:"name"` + Address sdk.Address `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` +} + +// power given to validators in gaia init functions +var FreePower = int64(100) + // Create the core parameters for genesis initialization for gaia // note that the pubkey input is this machines pubkey -func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { +func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - printMap := make(map[string]string) - var candidates []stake.Candidate - poolAssets := int64(0) - - chainID = viper.GetString(flagChainID) - if len(chainID) == 0 { - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + if len(appGenTxs) == 0 { + err = errors.New("must provide at least genesis transaction") + return } + // start with the default staking genesis state + stakeData := stake.GetDefaultGenesisState() + // get genesis flag account information - accountsStr := viper.GetString(flagAccounts) - accounts := strings.Split(accountsStr, ":") - genaccs := make([]GenesisAccount, len(accounts)) - for i, account := range accounts { - p := strings.Split(account, "-") - if len(p) != 3 { - err = errors.New("input account has bad form, each account must be in form name-coins-isval, for example: foobar-10fermion,10baz-true") - return - } - name := p[0] - var coins sdk.Coins - coins, err = sdk.ParseCoins(p[1]) - if err != nil { - return - } - isValidator := false - if p[2] == "true" { - isValidator = true - } + genaccs := make([]GenesisAccount, len(appGenTxs)) + for i, appGenTx := range appGenTxs { - var addr sdk.Address - var secret string - addr, secret, err = server.GenerateCoinKey() + var genTx GaiaGenTx + err = cdc.UnmarshalJSON(appGenTx, &genTx) if err != nil { return } - printMap["secret-"+name] = secret - - // create the genesis account - accAuth := auth.NewBaseAccountWithAddress(addr) - accAuth.Coins = coins + // create the genesis account, give'm few fermions and a buncha token with there name + accAuth := auth.NewBaseAccountWithAddress(genTx.Address) + accAuth.Coins = sdk.Coins{ + {genTx.Name + "Token", 1000}, + {"fermion", 50}, + } acc := NewGenesisAccount(&accAuth) genaccs[i] = acc // add the validator - if isValidator { + if len(genTx.Name) > 0 { + desc := stake.NewDescription(genTx.Name, "", "", "") + candidate := stake.NewCandidate(genTx.Address, genTx.PubKey, desc) + candidate.Assets = sdk.NewRat(FreePower) + stakeData.Candidates = append(stakeData.Candidates, candidate) - // only use this machines pubkey the first time, all others are dummies - var pk crypto.PubKey - if i == 0 { - pk = pubKey - } else { - pk = crypto.GenPrivKeyEd25519().PubKey() - } - - freePower := int64(100) - validator := tmtypes.GenesisValidator{ - PubKey: pk, - Power: freePower, - } - desc := stake.NewDescription(name, "", "", "") - candidate := stake.NewCandidate(addr, pk, desc) - candidate.Assets = sdk.NewRat(freePower) - poolAssets += freePower - validators = append(validators, validator) - candidates = append(candidates, candidate) + // pool logic + stakeData.Pool.TotalSupply += FreePower + stakeData.Pool.BondedPool += FreePower + stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool) } } - // create the print message - bz, err := cdc.MarshalJSON(printMap) - cliPrint = json.RawMessage(bz) - - stakeData := stake.GetDefaultGenesisState() - stakeData.Candidates = candidates - - // assume everything is bonded from the get-go - stakeData.Pool.TotalSupply = poolAssets - stakeData.Pool.BondedPool = poolAssets - stakeData.Pool.BondedShares = sdk.NewRat(poolAssets) - + // create the final app state genesisState := GenesisState{ Accounts: genaccs, StakeData: stakeData, } - appState, err = wire.MarshalJSONIndent(cdc, genesisState) return } -// append gaia app_state together, stitch the accounts together take the -// staking parameters from the first appState -func GaiaAppendAppState(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) { - var genState1, genState2 GenesisState - err = cdc.UnmarshalJSON(appState1, &genState1) - if err != nil { - panic(err) - } - err = cdc.UnmarshalJSON(appState2, &genState2) - if err != nil { - panic(err) - } - genState1.Accounts = append(genState1.Accounts, genState2.Accounts...) - genState1.StakeData.Candidates = append(genState1.StakeData.Candidates, genState2.StakeData.Candidates...) +// Generate a gaia genesis transaction +func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { - // pool logic - CombinedSupply := genState1.StakeData.Pool.TotalSupply + genState2.StakeData.Pool.TotalSupply - CombinedBondedPool := genState1.StakeData.Pool.BondedPool + genState2.StakeData.Pool.BondedPool - CombinedBondedShares := genState1.StakeData.Pool.BondedShares.Add(genState2.StakeData.Pool.BondedShares) - genState1.StakeData.Pool.TotalSupply = CombinedSupply - genState1.StakeData.Pool.BondedPool = CombinedBondedPool - genState1.StakeData.Pool.BondedShares = CombinedBondedShares + var addr sdk.Address + var secret string + addr, secret, err = server.GenerateCoinKey() + if err != nil { + return + } - return cdc.MarshalJSON(genState1) + var bz []byte + gaiaGenTx := GaiaGenTx{ + Name: viper.GetString(flagName), + Address: addr, + PubKey: pk, + } + bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx) + if err != nil { + return + } + appGenTx = json.RawMessage(bz) + + mm := map[string]string{"secret": secret} + bz, err = cdc.MarshalJSON(mm) + if err != nil { + return + } + cliPrint = json.RawMessage(bz) + + validator = tmtypes.GenesisValidator{ + PubKey: pk, + Power: FreePower, + } + return } diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index b3b2c4e7e..b70d25551 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -23,8 +23,7 @@ func TestGaiaCLISend(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - keys, chainID := executeInit(t, "gaiad init -o --accounts=foo-100000fermion-true", "foo") - require.Equal(t, 1, len(keys)) + key, chainID := executeInit(t, "gaiad init -o --name=foo") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -34,14 +33,14 @@ func TestGaiaCLISend(t *testing.T) { cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer cmd.Process.Kill() - executeWrite(t, "gaiacli keys add foo --recover", pass, keys[0]) + executeWrite(t, "gaiacli keys add foo --recover", pass, key) executeWrite(t, "gaiacli keys add bar", pass) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("fermion")) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass @@ -49,7 +48,7 @@ func TestGaiaCLISend(t *testing.T) { barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(99990), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion")) } func TestGaiaCLIDeclareCandidacy(t *testing.T) { @@ -57,8 +56,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) - keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true:foo-100000fermion-false", "bar", "foo") - require.Equal(t, 2, len(keys)) + key, chainID := executeInit(t, "gaiad init -o --name=foo") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -68,41 +66,46 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer cmd.Process.Kill() - executeWrite(t, "gaiacli keys add foo --recover", pass, keys[1]) - fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + executeWrite(t, "gaiacli keys add foo --recover", pass, key) + executeWrite(t, "gaiacli keys add bar", pass) + fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") + time.Sleep(time.Second * 3) // waiting for some blocks to pass + barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion")) // declare candidacy declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags) - declStr += fmt.Sprintf(" --name=%v", "foo") - declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) - declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey) + declStr += fmt.Sprintf(" --name=%v", "bar") + declStr += fmt.Sprintf(" --address-candidate=%v", barAddr) + declStr += fmt.Sprintf(" --pubkey=%v", barPubKey) declStr += fmt.Sprintf(" --amount=%v", "3fermion") - declStr += fmt.Sprintf(" --moniker=%v", "foo-vally") + declStr += fmt.Sprintf(" --moniker=%v", "bar-vally") fmt.Printf("debug declStr: %v\n", declStr) executeWrite(t, declStr, pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass - fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion")) - candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) - assert.Equal(t, candidate.Address.String(), fooAddr) + barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("fermion")) + candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) + assert.Equal(t, candidate.Address.String(), barAddr) assert.Equal(t, int64(3), candidate.Assets.Evaluate()) // TODO timeout issues if not connected to the internet // unbond a single share //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) - //unbondStr += fmt.Sprintf(" --name=%v", "foo") - //unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) - //unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr) + //unbondStr += fmt.Sprintf(" --name=%v", "bar") + //unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr) + //unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr) //unbondStr += fmt.Sprintf(" --shares=%v", "1") //unbondStr += fmt.Sprintf(" --sequence=%v", "1") //fmt.Printf("debug unbondStr: %v\n", unbondStr) //executeWrite(t, unbondStr, pass) //time.Sleep(time.Second * 3) // waiting for some blocks to pass - //fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - //assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion")) - //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) + //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + //assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("fermion")) + //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) //assert.Equal(t, int64(2), candidate.Assets.Evaluate()) } @@ -130,7 +133,7 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { fmt.Printf("debug read: %v\n", string(bz)) } -func executeInit(t *testing.T, cmdStr string, names ...string) (keys []string, chainID string) { +func executeInit(t *testing.T, cmdStr string) (key, chainID string) { out := tests.ExecuteT(t, cmdStr, 1) var initRes map[string]json.RawMessage @@ -144,12 +147,8 @@ func executeInit(t *testing.T, cmdStr string, names ...string) (keys []string, c err = json.Unmarshal(initRes["app_message"], &appMessageRes) require.NoError(t, err) - for _, name := range names { - var key string - err = json.Unmarshal(appMessageRes["secret-"+name], &key) - require.NoError(t, err) - keys = append(keys, key) - } + err = json.Unmarshal(appMessageRes["secret"], &key) + require.NoError(t, err) return } diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 0eb378005..afca80bce 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -8,8 +8,6 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -21,12 +19,13 @@ import ( // init parameters var CoolAppInit = server.AppInit{ - GenAppParams: CoolGenAppParams, + AppGenState: CoolAppGenState, + AppGenTx: server.SimpleAppGenTx, } // coolGenAppParams sets up the app_state and appends the cool app state -func CoolGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { - chainID, validators, appState, cliPrint, err = server.SimpleGenAppParams(cdc, pubKey) +func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { + appState, err = server.SimpleAppGenState(cdc, appGenTxs) if err != nil { return } diff --git a/mock/app.go b/mock/app.go index 09f09b830..84f762db0 100644 --- a/mock/app.go +++ b/mock/app.go @@ -8,7 +8,6 @@ import ( abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" tmtypes "github.com/tendermint/tendermint/types" - cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -106,17 +105,9 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci } } -// GenAppParams can be passed into InitCmd, returns a static string of a few +// AppGenState can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { - - chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) - - validators = []tmtypes.GenesisValidator{{ - PubKey: pubKey, - Power: 10, - }} - +func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) { appState = json.RawMessage(`{ "values": [ { @@ -131,3 +122,14 @@ func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validato }`) return } + +// Return a validator, not much else +func AppGenTx(_ *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + + validator = tmtypes.GenesisValidator{ + PubKey: pk, + Power: 10, + } + return +} diff --git a/mock/app_test.go b/mock/app_test.go index fe0948a84..7c84f9a1d 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" ) // TestInitApp makes sure we can initialize this thing without an error @@ -22,9 +21,9 @@ func TestInitApp(t *testing.T) { require.NoError(t, err) // initialize it future-way - pubKey := crypto.GenPrivKeyEd25519().PubKey() - _, _, appState, _, err := GenAppParams(nil, pubKey) + appState, err := AppGenState(nil, nil) require.NoError(t, err) + //TODO test validators in the init chain? req := abci.RequestInitChain{ AppStateBytes: appState, diff --git a/server/init.go b/server/init.go index edb256f8e..5916e3834 100644 --- a/server/init.go +++ b/server/init.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" "path" "path/filepath" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" @@ -30,13 +32,14 @@ type GenesisTx struct { IP string `json:"ip"` Validator tmtypes.GenesisValidator `json:"validator"` AppGenTx json.RawMessage `json:"app_gen_tx"` + CLIPrint json.RawMessage `json:"cli_print"` } var ( flagOverwrite = "overwrite" flagGenTxs = "gen-txs" flagIP = "ip" - flagChainID = "ip" + flagChainID = "chain-id" ) // get cmd to initialize all files for tendermint and application @@ -55,7 +58,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { nodeID := string(nodeKey.ID()) pubKey := ReadOrCreatePrivValidator(config) - appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey) if err != nil { return err } @@ -73,6 +76,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { IP: ip, Validator: validator, AppGenTx: appGenTx, + CLIPrint: cliPrint, } bz, err := wire.MarshalJSONIndent(cdc, tx) if err != nil { @@ -85,7 +89,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { err = cmn.WriteFile(file, bz, 0644) } - out, err := wire.MarshalJSONIndent(cdc, toPrint) + out, err := wire.MarshalJSONIndent(cdc, cliPrint) if err != nil { return err } @@ -94,7 +98,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { }, } cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") - cmd.Flags().AddFlagSet(appInit.FlagsAppTx) + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) return cmd } @@ -125,26 +129,31 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } // process genesis transactions, or otherwise create one for defaults - var appGenTxs, cliPrints []json.RawMessage + var appMessage json.RawMessage + var appGenTxs []json.RawMessage var validators []tmtypes.GenesisValidator var persistentPeers string + genTxsDir := viper.GetString(flagGenTxs) if genTxsDir != "" { - validators, persistentPeers, appGenTxs, cliPrints = processGenTxs(genTxsDir, cdc, appInit) + validators, appGenTxs, persistentPeers, err = processGenTxs(genTxsDir, cdc, appInit) + if err != nil { + return err + } config.P2P.PersistentPeers = persistentPeers configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get cfg.WriteConfigFile(configFilePath, config) } else { - appTx, cliPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey) + appMessage = am if err != nil { return err } validators = []tmtypes.GenesisValidator{validator} - appGenTxs = []json.RawMessage{appTx} - cliPrints = []json.RawMessage{cliPrint} + appGenTxs = []json.RawMessage{appGenTx} } - appState, err := appInit.GenAppParams(cdc, appGenTxs) + appState, err := appInit.AppGenState(cdc, appGenTxs) if err != nil { return err } @@ -156,13 +165,13 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { // print out some key information toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - AppMessage []json.RawMessage `json:"app_messages"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage json.RawMessage `json:"app_message"` }{ chainID, nodeID, - cliPrints, + appMessage, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -174,47 +183,55 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { }, } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file") - cmd.Flags().String(flagChainID, "", "designated chain-id for the genesis") - cmd.Flags().AddFlagSet(appInit.FlagsAppParams) + cmd.Flags().String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().String(flagGenTxs, "", "directory containing the genesis transactions") + cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided + cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) return cmd } // append a genesis-piece func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( - validators []tmtypes.GenesisValidator, appGenTxs, cliPrints []json.RawMessage, persistentPeers string, err error) { + validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { - fos, err := ioutil.ReadDir(genTxsDir) + // XXX sort the files by contents just incase people renamed their files + var fos []os.FileInfo + fos, err = ioutil.ReadDir(genTxsDir) + if err != nil { + return + } for _, fo := range fos { filename := fo.Name() if !fo.IsDir() && (path.Ext(filename) != ".json") { - return nil + return } // get the genTx - bz, err := ioutil.ReadFile(filename) + var bz []byte + bz, err = ioutil.ReadFile(filename) if err != nil { - return err + return } var genTx GenesisTx err = cdc.UnmarshalJSON(bz, &genTx) if err != nil { - return err + return } // combine some stuff validators = append(validators, genTx.Validator) - appGenTxs = append(appGenTxs, genTx.AppGenTxs) - cliPrints = append(cliPrints, genTx.CliPrints) + appGenTxs = append(appGenTxs, genTx.AppGenTx) // Add a persistent peer comma := "," if len(persistentPeers) == 0 { comma = "" } - persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) + persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, genTx.NodeID, genTx.IP) } - return nil + return } //________________________________________________________________________________________ @@ -267,43 +284,44 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js type AppInit struct { // flags required for application init functions - FlagsAppParams *pflag.FlagSet - FlagsAppTx *pflag.FlagSet + FlagsAppGenState *pflag.FlagSet + FlagsAppGenTx *pflag.FlagSet - // GenAppParams creates the core parameters initialization. It takes in a + // AppGenState creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. - GenAppParams func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) + AppGenState func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) // create the application genesis tx - GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) ( - appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) + AppGenTx func(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) } +//_____________________________________________________________________ + // simple default application init var DefaultAppInit = AppInit{ - GenAppParams: SimpleGenAppParams, + AppGenState: SimpleAppGenState, + AppGenTx: SimpleAppGenTx, } -// Create one account with a whole bunch of mycoin in it -func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage) ( - validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { +// simple genesis tx +type SimpleGenTx struct { + Addr sdk.Address `json:"addr"` +} - var addr sdk.Address +// create the genesis app state +func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - var secret string - addr, secret, err = GenerateCoinKey() - if err != nil { + if len(appGenTxs) != 1 { + err = errors.New("must provide a single genesis transaction") return } - mm := map[string]string{"secret": secret} - bz, err := cdc.MarshalJSON(mm) - cliPrint = json.RawMessage(bz) - - validators = []tmtypes.GenesisValidator{{ - PubKey: pubKey, - Power: 10, - }} + var genTx SimpleGenTx + err = cdc.UnmarshalJSON(appGenTxs[0], &genTx) + if err != nil { + return + } appState = json.RawMessage(fmt.Sprintf(`{ "accounts": [{ @@ -315,7 +333,40 @@ func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage } ] }] -}`, addr.String())) +}`, genTx.Addr.String())) + return +} + +// Generate a genesis transaction +func SimpleAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + + var addr sdk.Address + var secret string + addr, secret, err = GenerateCoinKey() + if err != nil { + return + } + + var bz []byte + simpleGenTx := SimpleGenTx{addr} + bz, err = cdc.MarshalJSON(simpleGenTx) + if err != nil { + return + } + appGenTx = json.RawMessage(bz) + + mm := map[string]string{"secret": secret} + bz, err = cdc.MarshalJSON(mm) + if err != nil { + return + } + cliPrint = json.RawMessage(bz) + + validator = tmtypes.GenesisValidator{ + PubKey: pk, + Power: 10, + } return } diff --git a/server/init_test.go b/server/init_test.go index 5db483516..1bdf0a085 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -21,7 +21,8 @@ func TestInit(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } cmd := InitCmd(ctx, cdc, appInit) err = cmd.RunE(nil, nil) diff --git a/server/start_test.go b/server/start_test.go index 85f1a7135..3bf2eac7e 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -28,7 +28,8 @@ func TestStartStandAlone(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil) @@ -58,7 +59,8 @@ func TestStartWithTendermint(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil)