gaia init automatic key processing

This commit is contained in:
rigelrozanski 2018-04-26 00:27:40 -04:00
parent d1c6216c0f
commit 05c5809bae
8 changed files with 233 additions and 188 deletions

View File

@ -24,8 +24,13 @@ var keybase keys.Keybase
// initialize a keybase based on the configuration
func GetKeyBase() (keys.Keybase, error) {
rootDir := viper.GetString(cli.HomeFlag)
return GetKeyBaseFromDir(rootDir)
}
// initialize a keybase based on the configuration
func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
if keybase == nil {
rootDir := viper.GetString(cli.HomeFlag)
db, err := dbm.NewGoLevelDB(KeyDBName, filepath.Join(rootDir, "keys"))
if err != nil {
return nil, err

View File

@ -1,20 +1,14 @@
package app
import (
"encoding/json"
"errors"
"os"
"github.com/spf13/pflag"
"github.com/spf13/viper"
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"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
@ -27,6 +21,12 @@ const (
appName = "GaiaApp"
)
// default home directories for expected binaries
var (
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
)
// Extended ABCI application
type GaiaApp struct {
*bam.BaseApp
@ -153,154 +153,3 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
return abci.ResponseInitChain{}
}
//________________________________________________________________________________________
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
}
// GenesisAccount doesn't need pubkey or sequence
type GenesisAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
}
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
}
}
var (
flagName = "name"
//flagOWK = "overwrite-keys"
)
// get app init parameters for server init command
func GaiaAppInit() server.AppInit {
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{
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 GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
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
genaccs := make([]GenesisAccount, len(appGenTxs))
for i, appGenTx := range appGenTxs {
var genTx GaiaGenTx
err = cdc.UnmarshalJSON(appGenTx, &genTx)
if err != nil {
return
}
// 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 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 secret string
addr, secret, err = server.GenerateCoinKey()
if err != nil {
return
}
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
}

175
cmd/gaia/app/genesis.go Normal file
View File

@ -0,0 +1,175 @@
package app
import (
"encoding/json"
"errors"
"github.com/spf13/pflag"
"github.com/spf13/viper"
crypto "github.com/tendermint/go-crypto"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/stake"
)
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
StakeData stake.GenesisState `json:"stake"`
}
// GenesisAccount doesn't need pubkey or sequence
type GenesisAccount struct {
Address sdk.Address `json:"address"`
Coins sdk.Coins `json:"coins"`
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
}
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
return &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
}
}
var (
flagName = "name"
flagClientHome = "home-client"
flagOWK = "owk"
// bonded tokens given to genesis validators/accounts
freeFermionVal = int64(100)
freeFermionsAcc = int64(50)
)
// get app init parameters for server init command
func GaiaAppInit() server.AppInit {
fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
fsAppGenTx.String(flagClientHome, DefaultCLIHome, "home directory for the client, used for key generation")
fsAppGenTx.Bool(flagOWK, false, "overwrite the for the accounts created")
return server.AppInit{
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
// Create the core parameters for genesis initialization for gaia
// note that the pubkey input is this machines pubkey
func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
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
genaccs := make([]GenesisAccount, len(appGenTxs))
for i, appGenTx := range appGenTxs {
var genTx GaiaGenTx
err = cdc.UnmarshalJSON(appGenTx, &genTx)
if err != nil {
return
}
// 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", freeFermionsAcc},
}
acc := NewGenesisAccount(&accAuth)
genaccs[i] = acc
stakeData.Pool.TotalSupply += freeFermionsAcc // increase the supply
// 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(freeFermionVal)
stakeData.Candidates = append(stakeData.Candidates, candidate)
// pool logic
stakeData.Pool.TotalSupply += freeFermionVal
stakeData.Pool.BondedPool += freeFermionVal
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 secret string
clientRoot := viper.GetString(flagClientHome)
overwrite := viper.GetBool(flagOWK)
name := viper.GetString(flagName)
addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite)
if err != nil {
return
}
var bz []byte
gaiaGenTx := GaiaGenTx{
Name: name,
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: freeFermionVal,
}
return
}

View File

@ -24,7 +24,8 @@ func TestGaiaCLISend(t *testing.T) {
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
executeWrite(t, "gaiacli keys delete bar", pass)
key, chainID := executeInit(t, "gaiad init -o --name=foo")
chainID := executeInit(t, "gaiad init -o --name=foo")
executeWrite(t, "gaiacli keys add bar", pass)
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
@ -34,9 +35,6 @@ 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, 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")
@ -58,7 +56,8 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) {
pass := "1234567890"
executeWrite(t, "gaiacli keys delete foo", pass)
executeWrite(t, "gaiacli keys delete bar", pass)
key, chainID := executeInit(t, "gaiad init -o --name=foo")
chainID := executeInit(t, "gaiad init -o --name=foo")
executeWrite(t, "gaiacli keys add bar", pass)
// get a free port, also setup some common flags
servAddr := server.FreeTCPAddr(t)
@ -68,8 +67,6 @@ 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, 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")
@ -140,7 +137,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) (key, chainID string) {
func executeInit(t *testing.T, cmdStr string) (chainID string) {
out := tests.ExecuteT(t, cmdStr)
var initRes map[string]json.RawMessage
@ -150,13 +147,6 @@ func executeInit(t *testing.T, cmdStr string) (key, chainID string) {
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(t, err)
var appMessageRes map[string]json.RawMessage
err = json.Unmarshal(initRes["app_message"], &appMessageRes)
require.NoError(t, err)
err = json.Unmarshal(appMessageRes["secret"], &key)
require.NoError(t, err)
return
}

View File

@ -1,8 +1,6 @@
package main
import (
"os"
"github.com/spf13/cobra"
"github.com/tendermint/tmlibs/cli"
@ -73,6 +71,6 @@ func main() {
)
// prepare and add flags
executor := cli.PrepareMainCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome)
executor.Execute()
}

View File

@ -1,7 +1,6 @@
package main
import (
"os"
"path/filepath"
"github.com/spf13/cobra"
@ -27,8 +26,7 @@ func main() {
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp)
// prepare and add flags
rootDir := os.ExpandEnv("$HOME/.gaiad")
executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir)
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
executor.Execute()
}

View File

@ -8,8 +8,6 @@ import (
"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"
@ -22,8 +20,13 @@ import (
"github.com/tendermint/tendermint/p2p"
tmtypes "github.com/tendermint/tendermint/types"
pvm "github.com/tendermint/tendermint/types/priv_validator"
tmcli "github.com/tendermint/tmlibs/cli"
cmn "github.com/tendermint/tmlibs/common"
dbm "github.com/tendermint/tmlibs/db"
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/wire"
)
// genesis piece structure for creating combined genesis
@ -82,7 +85,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
}
genTxFile := json.RawMessage(bz)
name := fmt.Sprintf("gentx-%v.json", nodeID)
file := filepath.Join(viper.GetString("home"), name)
file := filepath.Join(viper.GetString(tmcli.HomeFlag), name)
err = cmn.WriteFile(file, bz, 0644)
if err != nil {
return err
@ -148,7 +151,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return err
}
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(tmcli.HomeFlag), "config", "config.toml") //TODO this is annoying should be easier to get
cfg.WriteConfigFile(configFilePath, config)
} else {
appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey)
@ -165,7 +168,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
return err
}
err = WriteGenesisFile(cdc, genFile, chainID, validators, appState)
err = writeGenesisFile(cdc, genFile, chainID, validators, appState)
if err != nil {
return err
}
@ -258,7 +261,7 @@ func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
}
// create the genesis file
func WriteGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
genDoc := tmtypes.GenesisDoc{
ChainID: chainID,
Validators: validators,
@ -399,3 +402,30 @@ func GenerateCoinKey() (sdk.Address, string, error) {
addr := info.PubKey.Address()
return addr, secret, nil
}
// GenerateSaveCoinKey returns the address of a public key, along with the secret
// phrase to recover the private key.
func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (sdk.Address, string, error) {
// get the keystore from the client
keybase, err := clkeys.GetKeyBaseFromDir(clientRoot)
if err != nil {
return nil, "", err
}
// ensure no overwrite
if !overwrite {
_, err := keybase.Get(keyName)
if err == nil {
return nil, "", errors.New("key already exists, overwrite is disabled")
}
}
// generate a private key, with recovery phrase
info, secret, err := keybase.Create(keyName, keyPass, keys.AlgoEd25519)
if err != nil {
return nil, "", err
}
addr := info.PubKey.Address()
return addr, secret, nil
}

View File

@ -36,7 +36,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
flagJSON := "json"
cmd := cobra.Command{
Use: "show_validator",
Short: "Show this node's validator info",
Short: "Show this node's tendermint validator info",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.Config
@ -67,7 +67,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
return &cobra.Command{
Use: "unsafe_reset_all",
Short: "Reset all blockchain data",
Short: "Reset blockchain database, priv_validator.json file, and the logger",
RunE: func(cmd *cobra.Command, args []string) error {
cfg := ctx.Config
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)