init refactor uses genesis transaction now

This commit is contained in:
rigelrozanski 2018-04-25 16:12:14 -04:00
parent 12f20d160a
commit b9477ecbbe
8 changed files with 237 additions and 203 deletions

View File

@ -3,7 +3,6 @@ package app
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"strings"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -185,57 +184,93 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
} }
var ( var (
flagAccounts = "accounts" flagName = "name"
flagChainID = "chain-id" //flagOWK = "overwrite-keys"
flagOWK = "overwrite-keys"
) )
// get app init parameters for server init command // get app init parameters for server init command
func GaiaAppInit() server.AppInit { func GaiaAppInit() server.AppInit {
fs := pflag.NewFlagSet("", pflag.ContinueOnError) fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval:name2-coins-isval:...") //fsAppGenState.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail")
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") fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
return server.AppInit{ return server.AppInit{
Flags: fs, FlagsAppGenState: fsAppGenState,
GenAppParams: GaiaGenAppParams, FlagsAppGenTx: fsAppGenTx,
AppendAppState: GaiaAppendAppState, 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 // Create the core parameters for genesis initialization for gaia
// note that the pubkey input is this machines pubkey // 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) if len(appGenTxs) == 0 {
var candidates []stake.Candidate err = errors.New("must provide at least genesis transaction")
poolAssets := int64(0)
chainID = viper.GetString(flagChainID)
if len(chainID) == 0 {
chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6))
}
// 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 return
} }
name := p[0]
var coins sdk.Coins // start with the default staking genesis state
coins, err = sdk.ParseCoins(p[1]) stakeData := stake.GetDefaultGenesisState()
// get genesis flag account information
genaccs := make([]GenesisAccount, len(appGenTxs))
for i, appGenTx := range appGenTxs {
var genTx GaiaGenTx
err = cdc.UnmarshalJSON(appGenTx, &genTx)
if err != nil { if err != nil {
return return
} }
isValidator := false
if p[2] == "true" { // create the genesis account, give'm few fermions and a buncha token with there name
isValidator = true 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 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)
// pool logic
stakeData.Pool.TotalSupply += FreePower
stakeData.Pool.BondedPool += FreePower
stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool)
}
}
// create the final app state
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stakeData,
}
appState, err = wire.MarshalJSONIndent(cdc, genesisState)
return
}
// Generate a gaia genesis transaction
func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
var addr sdk.Address var addr sdk.Address
var secret string var secret string
@ -244,82 +279,28 @@ func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, va
return return
} }
printMap["secret-"+name] = secret var bz []byte
gaiaGenTx := GaiaGenTx{
// create the genesis account Name: viper.GetString(flagName),
accAuth := auth.NewBaseAccountWithAddress(addr) Address: addr,
accAuth.Coins = coins
acc := NewGenesisAccount(&accAuth)
genaccs[i] = acc
// add the validator
if isValidator {
// 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, PubKey: pk,
Power: freePower,
} }
desc := stake.NewDescription(name, "", "", "") bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx)
candidate := stake.NewCandidate(addr, pk, desc) if err != nil {
candidate.Assets = sdk.NewRat(freePower)
poolAssets += freePower
validators = append(validators, validator)
candidates = append(candidates, candidate)
}
}
// 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)
genesisState := GenesisState{
Accounts: genaccs,
StakeData: stakeData,
}
appState, err = wire.MarshalJSONIndent(cdc, genesisState)
return return
} }
appGenTx = json.RawMessage(bz)
// append gaia app_state together, stitch the accounts together take the mm := map[string]string{"secret": secret}
// staking parameters from the first appState bz, err = cdc.MarshalJSON(mm)
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 { if err != nil {
panic(err) return
} }
err = cdc.UnmarshalJSON(appState2, &genState2) cliPrint = json.RawMessage(bz)
if err != nil {
panic(err)
}
genState1.Accounts = append(genState1.Accounts, genState2.Accounts...)
genState1.StakeData.Candidates = append(genState1.StakeData.Candidates, genState2.StakeData.Candidates...)
// pool logic validator = tmtypes.GenesisValidator{
CombinedSupply := genState1.StakeData.Pool.TotalSupply + genState2.StakeData.Pool.TotalSupply PubKey: pk,
CombinedBondedPool := genState1.StakeData.Pool.BondedPool + genState2.StakeData.Pool.BondedPool Power: FreePower,
CombinedBondedShares := genState1.StakeData.Pool.BondedShares.Add(genState2.StakeData.Pool.BondedShares) }
genState1.StakeData.Pool.TotalSupply = CombinedSupply return
genState1.StakeData.Pool.BondedPool = CombinedBondedPool
genState1.StakeData.Pool.BondedShares = CombinedBondedShares
return cdc.MarshalJSON(genState1)
} }

View File

@ -23,8 +23,7 @@ func TestGaiaCLISend(t *testing.T) {
pass := "1234567890" pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete foo", pass)
executeWrite(t, "gaiacli keys delete bar", pass) executeWrite(t, "gaiacli keys delete bar", pass)
keys, chainID := executeInit(t, "gaiad init -o --accounts=foo-100000fermion-true", "foo") key, chainID := executeInit(t, "gaiad init -o --name=foo")
require.Equal(t, 1, len(keys))
// get a free port, also setup some common flags // get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t) 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)) cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill() 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) executeWrite(t, "gaiacli keys add bar", pass)
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) 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) 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 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)) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion"))
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) 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) { func TestGaiaCLIDeclareCandidacy(t *testing.T) {
@ -57,8 +56,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) {
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
pass := "1234567890" pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete foo", pass)
keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true:foo-100000fermion-false", "bar", "foo") key, chainID := executeInit(t, "gaiad init -o --name=foo")
require.Equal(t, 2, len(keys))
// get a free port, also setup some common flags // get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t) 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)) cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
defer cmd.Process.Kill() defer cmd.Process.Kill()
executeWrite(t, "gaiacli keys add foo --recover", pass, keys[1]) executeWrite(t, "gaiacli keys add foo --recover", pass, key)
fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json") 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)) 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 // declare candidacy
declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags) declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags)
declStr += fmt.Sprintf(" --name=%v", "foo") declStr += fmt.Sprintf(" --name=%v", "bar")
declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) declStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey) declStr += fmt.Sprintf(" --pubkey=%v", barPubKey)
declStr += fmt.Sprintf(" --amount=%v", "3fermion") 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) fmt.Printf("debug declStr: %v\n", declStr)
executeWrite(t, declStr, pass) executeWrite(t, declStr, pass)
time.Sleep(time.Second * 3) // waiting for some blocks to pass time.Sleep(time.Second * 3) // waiting for some blocks to pass
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion")) assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("fermion"))
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
assert.Equal(t, candidate.Address.String(), fooAddr) assert.Equal(t, candidate.Address.String(), barAddr)
assert.Equal(t, int64(3), candidate.Assets.Evaluate()) assert.Equal(t, int64(3), candidate.Assets.Evaluate())
// TODO timeout issues if not connected to the internet // TODO timeout issues if not connected to the internet
// unbond a single share // unbond a single share
//unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
//unbondStr += fmt.Sprintf(" --name=%v", "foo") //unbondStr += fmt.Sprintf(" --name=%v", "bar")
//unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) //unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
//unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr) //unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr)
//unbondStr += fmt.Sprintf(" --shares=%v", "1") //unbondStr += fmt.Sprintf(" --shares=%v", "1")
//unbondStr += fmt.Sprintf(" --sequence=%v", "1") //unbondStr += fmt.Sprintf(" --sequence=%v", "1")
//fmt.Printf("debug unbondStr: %v\n", unbondStr) //fmt.Printf("debug unbondStr: %v\n", unbondStr)
//executeWrite(t, unbondStr, pass) //executeWrite(t, unbondStr, pass)
//time.Sleep(time.Second * 3) // waiting for some blocks to pass //time.Sleep(time.Second * 3) // waiting for some blocks to pass
//fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
//assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion")) //assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("fermion"))
//candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
//assert.Equal(t, int64(2), candidate.Assets.Evaluate()) //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)) 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) out := tests.ExecuteT(t, cmdStr, 1)
var initRes map[string]json.RawMessage 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) err = json.Unmarshal(initRes["app_message"], &appMessageRes)
require.NoError(t, err) require.NoError(t, err)
for _, name := range names { err = json.Unmarshal(appMessageRes["secret"], &key)
var key string
err = json.Unmarshal(appMessageRes["secret-"+name], &key)
require.NoError(t, err) require.NoError(t, err)
keys = append(keys, key)
}
return return
} }

View File

@ -8,8 +8,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/tendermint/tmlibs/cli" "github.com/tendermint/tmlibs/cli"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "github.com/tendermint/tmlibs/log"
@ -21,12 +19,13 @@ import (
// init parameters // init parameters
var CoolAppInit = server.AppInit{ var CoolAppInit = server.AppInit{
GenAppParams: CoolGenAppParams, AppGenState: CoolAppGenState,
AppGenTx: server.SimpleAppGenTx,
} }
// coolGenAppParams sets up the app_state and appends the cool app state // 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) { func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
chainID, validators, appState, cliPrint, err = server.SimpleGenAppParams(cdc, pubKey) appState, err = server.SimpleAppGenState(cdc, appGenTxs)
if err != nil { if err != nil {
return return
} }

View File

@ -8,7 +8,6 @@ import (
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto" crypto "github.com/tendermint/go-crypto"
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db" dbm "github.com/tendermint/tmlibs/db"
"github.com/tendermint/tmlibs/log" "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 // 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) { func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6))
validators = []tmtypes.GenesisValidator{{
PubKey: pubKey,
Power: 10,
}}
appState = json.RawMessage(`{ appState = json.RawMessage(`{
"values": [ "values": [
{ {
@ -131,3 +122,14 @@ func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validato
}`) }`)
return 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
}

View File

@ -7,7 +7,6 @@ import (
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
abci "github.com/tendermint/abci/types" abci "github.com/tendermint/abci/types"
crypto "github.com/tendermint/go-crypto"
) )
// TestInitApp makes sure we can initialize this thing without an error // TestInitApp makes sure we can initialize this thing without an error
@ -22,9 +21,9 @@ func TestInitApp(t *testing.T) {
require.NoError(t, err) require.NoError(t, err)
// initialize it future-way // initialize it future-way
pubKey := crypto.GenPrivKeyEd25519().PubKey() appState, err := AppGenState(nil, nil)
_, _, appState, _, err := GenAppParams(nil, pubKey)
require.NoError(t, err) require.NoError(t, err)
//TODO test validators in the init chain? //TODO test validators in the init chain?
req := abci.RequestInitChain{ req := abci.RequestInitChain{
AppStateBytes: appState, AppStateBytes: appState,

View File

@ -4,11 +4,13 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"os"
"path" "path"
"path/filepath" "path/filepath"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/wire"
"github.com/pkg/errors"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/pflag" "github.com/spf13/pflag"
"github.com/spf13/viper" "github.com/spf13/viper"
@ -30,13 +32,14 @@ type GenesisTx struct {
IP string `json:"ip"` IP string `json:"ip"`
Validator tmtypes.GenesisValidator `json:"validator"` Validator tmtypes.GenesisValidator `json:"validator"`
AppGenTx json.RawMessage `json:"app_gen_tx"` AppGenTx json.RawMessage `json:"app_gen_tx"`
CLIPrint json.RawMessage `json:"cli_print"`
} }
var ( var (
flagOverwrite = "overwrite" flagOverwrite = "overwrite"
flagGenTxs = "gen-txs" flagGenTxs = "gen-txs"
flagIP = "ip" flagIP = "ip"
flagChainID = "ip" flagChainID = "chain-id"
) )
// get cmd to initialize all files for tendermint and application // 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()) nodeID := string(nodeKey.ID())
pubKey := ReadOrCreatePrivValidator(config) pubKey := ReadOrCreatePrivValidator(config)
appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey) appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey)
if err != nil { if err != nil {
return err return err
} }
@ -73,6 +76,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
IP: ip, IP: ip,
Validator: validator, Validator: validator,
AppGenTx: appGenTx, AppGenTx: appGenTx,
CLIPrint: cliPrint,
} }
bz, err := wire.MarshalJSONIndent(cdc, tx) bz, err := wire.MarshalJSONIndent(cdc, tx)
if err != nil { if err != nil {
@ -85,7 +89,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
err = cmn.WriteFile(file, bz, 0644) err = cmn.WriteFile(file, bz, 0644)
} }
out, err := wire.MarshalJSONIndent(cdc, toPrint) out, err := wire.MarshalJSONIndent(cdc, cliPrint)
if err != nil { if err != nil {
return err 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().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 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 // 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 validators []tmtypes.GenesisValidator
var persistentPeers string var persistentPeers string
genTxsDir := viper.GetString(flagGenTxs) genTxsDir := viper.GetString(flagGenTxs)
if genTxsDir != "" { 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 config.P2P.PersistentPeers = persistentPeers
configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get
cfg.WriteConfigFile(configFilePath, config) cfg.WriteConfigFile(configFilePath, config)
} else { } else {
appTx, cliPrint, validator, err := appInit.GenAppTx(cdc, pubKey) appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey)
appMessage = am
if err != nil { if err != nil {
return err return err
} }
validators = []tmtypes.GenesisValidator{validator} validators = []tmtypes.GenesisValidator{validator}
appGenTxs = []json.RawMessage{appTx} appGenTxs = []json.RawMessage{appGenTx}
cliPrints = []json.RawMessage{cliPrint}
} }
appState, err := appInit.GenAppParams(cdc, appGenTxs) appState, err := appInit.AppGenState(cdc, appGenTxs)
if err != nil { if err != nil {
return err return err
} }
@ -158,11 +167,11 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
toPrint := struct { toPrint := struct {
ChainID string `json:"chain_id"` ChainID string `json:"chain_id"`
NodeID string `json:"node_id"` NodeID string `json:"node_id"`
AppMessage []json.RawMessage `json:"app_messages"` AppMessage json.RawMessage `json:"app_message"`
}{ }{
chainID, chainID,
nodeID, nodeID,
cliPrints, appMessage,
} }
out, err := wire.MarshalJSONIndent(cdc, toPrint) out, err := wire.MarshalJSONIndent(cdc, toPrint)
if err != nil { 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().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
cmd.Flags().String(flagChainID, "", "designated chain-id for the genesis") cmd.Flags().String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created")
cmd.Flags().AddFlagSet(appInit.FlagsAppParams) 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 return cmd
} }
// append a genesis-piece // append a genesis-piece
func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( 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 { for _, fo := range fos {
filename := fo.Name() filename := fo.Name()
if !fo.IsDir() && (path.Ext(filename) != ".json") { if !fo.IsDir() && (path.Ext(filename) != ".json") {
return nil return
} }
// get the genTx // get the genTx
bz, err := ioutil.ReadFile(filename) var bz []byte
bz, err = ioutil.ReadFile(filename)
if err != nil { if err != nil {
return err return
} }
var genTx GenesisTx var genTx GenesisTx
err = cdc.UnmarshalJSON(bz, &genTx) err = cdc.UnmarshalJSON(bz, &genTx)
if err != nil { if err != nil {
return err return
} }
// combine some stuff // combine some stuff
validators = append(validators, genTx.Validator) validators = append(validators, genTx.Validator)
appGenTxs = append(appGenTxs, genTx.AppGenTxs) appGenTxs = append(appGenTxs, genTx.AppGenTx)
cliPrints = append(cliPrints, genTx.CliPrints)
// Add a persistent peer // Add a persistent peer
comma := "," comma := ","
if len(persistentPeers) == 0 { if len(persistentPeers) == 0 {
comma = "" 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 { type AppInit struct {
// flags required for application init functions // flags required for application init functions
FlagsAppParams *pflag.FlagSet FlagsAppGenState *pflag.FlagSet
FlagsAppTx *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. // 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 // create the application genesis tx
GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) ( AppGenTx func(cdc *wire.Codec, pk crypto.PubKey) (
appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error)
} }
//_____________________________________________________________________
// simple default application init // simple default application init
var DefaultAppInit = AppInit{ var DefaultAppInit = AppInit{
GenAppParams: SimpleGenAppParams, AppGenState: SimpleAppGenState,
AppGenTx: SimpleAppGenTx,
} }
// Create one account with a whole bunch of mycoin in it // simple genesis tx
func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage) ( type SimpleGenTx struct {
validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { 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 if len(appGenTxs) != 1 {
addr, secret, err = GenerateCoinKey() err = errors.New("must provide a single genesis transaction")
if err != nil {
return return
} }
mm := map[string]string{"secret": secret} var genTx SimpleGenTx
bz, err := cdc.MarshalJSON(mm) err = cdc.UnmarshalJSON(appGenTxs[0], &genTx)
cliPrint = json.RawMessage(bz) if err != nil {
return
validators = []tmtypes.GenesisValidator{{ }
PubKey: pubKey,
Power: 10,
}}
appState = json.RawMessage(fmt.Sprintf(`{ appState = json.RawMessage(fmt.Sprintf(`{
"accounts": [{ "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 return
} }

View File

@ -21,7 +21,8 @@ func TestInit(t *testing.T) {
ctx := NewContext(cfg, logger) ctx := NewContext(cfg, logger)
cdc := wire.NewCodec() cdc := wire.NewCodec()
appInit := AppInit{ appInit := AppInit{
GenAppParams: mock.GenAppParams, AppGenState: mock.AppGenState,
AppGenTx: mock.AppGenTx,
} }
cmd := InitCmd(ctx, cdc, appInit) cmd := InitCmd(ctx, cdc, appInit)
err = cmd.RunE(nil, nil) err = cmd.RunE(nil, nil)

View File

@ -28,7 +28,8 @@ func TestStartStandAlone(t *testing.T) {
ctx := NewContext(cfg, logger) ctx := NewContext(cfg, logger)
cdc := wire.NewCodec() cdc := wire.NewCodec()
appInit := AppInit{ appInit := AppInit{
GenAppParams: mock.GenAppParams, AppGenState: mock.AppGenState,
AppGenTx: mock.AppGenTx,
} }
initCmd := InitCmd(ctx, cdc, appInit) initCmd := InitCmd(ctx, cdc, appInit)
err = initCmd.RunE(nil, nil) err = initCmd.RunE(nil, nil)
@ -58,7 +59,8 @@ func TestStartWithTendermint(t *testing.T) {
ctx := NewContext(cfg, logger) ctx := NewContext(cfg, logger)
cdc := wire.NewCodec() cdc := wire.NewCodec()
appInit := AppInit{ appInit := AppInit{
GenAppParams: mock.GenAppParams, AppGenState: mock.AppGenState,
AppGenTx: mock.AppGenTx,
} }
initCmd := InitCmd(ctx, cdc, appInit) initCmd := InitCmd(ctx, cdc, appInit)
err = initCmd.RunE(nil, nil) err = initCmd.RunE(nil, nil)