New genesis workflow (#2602)
New genesis workflow: * `gaiad init` is now used to generate an empty `genesis.json`. * Genesis accounts need to be populated manually before running `gaiad collect-gentxs`. * This should support starfish too, see #2615 for more info. * Closes: #2596 #2615 * Validate validator address and address against respective account ex ante * Fix local testnet failures * New genesis tests * Run make format * Add --pubkey flag * gaiad collect-gentxs takes no args
This commit is contained in:
parent
f4338d6f75
commit
c20fcbfd8f
|
@ -7,6 +7,7 @@ BREAKING CHANGES
|
|||
* Gaia CLI (`gaiacli`)
|
||||
|
||||
* Gaia
|
||||
* [gaiad init] \#2602 New genesis workflow
|
||||
|
||||
* SDK
|
||||
* [simulation] \#2665 only argument to simulation.Invariant is now app
|
||||
|
|
|
@ -214,6 +214,7 @@ func InitializeTestLCD(
|
|||
genTxs := []json.RawMessage{}
|
||||
|
||||
// append any additional (non-proposing) validators
|
||||
var accs []gapp.GenesisAccount
|
||||
for i := 0; i < nValidators; i++ {
|
||||
operPrivKey := secp256k1.GenPrivKey()
|
||||
operAddr := operPrivKey.PubKey().Address()
|
||||
|
@ -242,9 +243,17 @@ func InitializeTestLCD(
|
|||
genTxs = append(genTxs, txBytes)
|
||||
valConsPubKeys = append(valConsPubKeys, pubKey)
|
||||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
||||
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
|
||||
accAuth.Coins = sdk.Coins{sdk.NewInt64Coin("steak", 150)}
|
||||
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
|
||||
}
|
||||
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, genTxs)
|
||||
appGenState := gapp.NewDefaultGenesisState()
|
||||
appGenState.Accounts = accs
|
||||
genDoc.AppState, err = cdc.MarshalJSON(appGenState)
|
||||
require.NoError(t, err)
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, *genDoc, genTxs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// add some tokens to init accounts
|
||||
|
|
|
@ -273,7 +273,8 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
// sanity check
|
||||
if len(req.Validators) > 0 {
|
||||
if len(req.Validators) != len(validators) {
|
||||
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d) ", len(req.Validators), len(validators)))
|
||||
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d)",
|
||||
len(req.Validators), len(validators)))
|
||||
}
|
||||
sort.Sort(abci.ValidatorUpdates(req.Validators))
|
||||
sort.Sort(abci.ValidatorUpdates(validators))
|
||||
|
|
|
@ -26,6 +26,7 @@ var (
|
|||
// bonded tokens given to genesis validators/accounts
|
||||
freeFermionVal = int64(100)
|
||||
freeFermionsAcc = sdk.NewInt(150)
|
||||
bondDenom = "steak"
|
||||
)
|
||||
|
||||
// State to Unmarshal
|
||||
|
@ -90,58 +91,60 @@ func GaiaAppInit() server.AppInit {
|
|||
|
||||
// Create the core parameters for genesis initialization for gaia
|
||||
// note that the pubkey input is this machines pubkey
|
||||
func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) {
|
||||
if len(appGenTxs) == 0 {
|
||||
err = errors.New("must provide at least genesis transaction")
|
||||
return
|
||||
func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
genesisState GenesisState, err error) {
|
||||
|
||||
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
|
||||
return genesisState, err
|
||||
}
|
||||
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
slashingData := slashing.DefaultGenesisState()
|
||||
|
||||
// get genesis flag account information
|
||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||
// if there are no gen txs to be processed, return the default empty state
|
||||
if len(appGenTxs) == 0 {
|
||||
return genesisState, errors.New("there must be at least one genesis tx")
|
||||
}
|
||||
|
||||
stakeData := genesisState.StakeData
|
||||
for i, genTx := range appGenTxs {
|
||||
var tx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(genTx, &tx)
|
||||
if err != nil {
|
||||
return
|
||||
if err := cdc.UnmarshalJSON(genTx, &tx); err != nil {
|
||||
return genesisState, err
|
||||
}
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
return
|
||||
return genesisState, errors.New(
|
||||
"must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
}
|
||||
if _, ok := msgs[0].(stake.MsgCreateValidator); !ok {
|
||||
return genesisState, fmt.Errorf(
|
||||
"Genesis transaction %v does not contain a MsgCreateValidator", i)
|
||||
}
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
genaccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
genesisState = GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stakeData,
|
||||
for _, acc := range genesisState.Accounts {
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
for _, coin := range acc.Coins {
|
||||
if coin.Denom == bondDenom {
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.
|
||||
Add(sdk.NewDecFromInt(coin.Amount)) // increase the supply
|
||||
}
|
||||
}
|
||||
}
|
||||
genesisState.StakeData = stakeData
|
||||
genesisState.GenTxs = appGenTxs
|
||||
return genesisState, nil
|
||||
}
|
||||
|
||||
// NewDefaultGenesisState generates the default state for gaia.
|
||||
func NewDefaultGenesisState() GenesisState {
|
||||
return GenesisState{
|
||||
Accounts: nil,
|
||||
StakeData: stake.DefaultGenesisState(),
|
||||
MintData: mint.DefaultGenesisState(),
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
SlashingData: slashingData,
|
||||
GenTxs: appGenTxs,
|
||||
SlashingData: slashing.DefaultGenesisState(),
|
||||
GenTxs: nil,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func genesisAccountFromMsgCreateValidator(msg stake.MsgCreateValidator, amount sdk.Int) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
||||
accAuth.Coins = []sdk.Coin{
|
||||
{msg.Description.Moniker + "Token", sdk.NewInt(1000)},
|
||||
{"steak", amount},
|
||||
}
|
||||
return NewGenesisAccount(&accAuth)
|
||||
}
|
||||
|
||||
// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
|
||||
|
@ -175,27 +178,43 @@ func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
|
|||
}
|
||||
|
||||
// GaiaAppGenState but with JSON
|
||||
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func GaiaAppGenStateJSON(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
// create the final app state
|
||||
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
||||
genesisState, err := GaiaAppGenState(cdc, genDoc, appGenTxs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
||||
return
|
||||
return codec.MarshalJSONIndent(cdc, genesisState)
|
||||
}
|
||||
|
||||
// CollectStdTxs processes and validates application's genesis StdTxs and returns the list of validators,
|
||||
// appGenTxs, and persistent peers required to generate genesis.json.
|
||||
func CollectStdTxs(moniker string, genTxsDir string, cdc *codec.Codec) (
|
||||
validators []tmtypes.GenesisValidator, appGenTxs []auth.StdTx, persistentPeers string, err error) {
|
||||
// CollectStdTxs processes and validates application's genesis StdTxs and returns
|
||||
// the list of appGenTxs, and persistent peers required to generate genesis.json.
|
||||
func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tmtypes.GenesisDoc) (
|
||||
appGenTxs []auth.StdTx, persistentPeers string, err error) {
|
||||
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
|
||||
var addresses []string
|
||||
// prepare a map of all accounts in genesis state to then validate
|
||||
// against the validators addresses
|
||||
var appState GenesisState
|
||||
if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
addrMap := make(map[string]GenesisAccount, len(appState.Accounts))
|
||||
for i := 0; i < len(appState.Accounts); i++ {
|
||||
acc := appState.Accounts[i]
|
||||
strAddr := string(acc.Address)
|
||||
addrMap[strAddr] = acc
|
||||
}
|
||||
|
||||
// addresses and IPs (and port) validator server info
|
||||
var addressesIPs []string
|
||||
|
||||
for _, fo := range fos {
|
||||
filename := filepath.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
|
||||
|
@ -204,48 +223,55 @@ func CollectStdTxs(moniker string, genTxsDir string, cdc *codec.Codec) (
|
|||
|
||||
// get the genStdTx
|
||||
var jsonRawTx []byte
|
||||
jsonRawTx, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
if jsonRawTx, err = ioutil.ReadFile(filename); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
var genStdTx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx)
|
||||
if err != nil {
|
||||
return
|
||||
if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil {
|
||||
return appGenTxs, persistentPeers, err
|
||||
}
|
||||
appGenTxs = append(appGenTxs, genStdTx)
|
||||
|
||||
nodeAddr := genStdTx.GetMemo()
|
||||
if len(nodeAddr) == 0 {
|
||||
err = fmt.Errorf("couldn't find node's address in %s", fo.Name())
|
||||
return
|
||||
// the memo flag is used to store
|
||||
// the ip and node-id, for example this may be:
|
||||
// "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656"
|
||||
nodeAddrIP := genStdTx.GetMemo()
|
||||
if len(nodeAddrIP) == 0 {
|
||||
return appGenTxs, persistentPeers, fmt.Errorf(
|
||||
"couldn't find node's address and IP in %s", fo.Name())
|
||||
}
|
||||
|
||||
// genesis transactions must be single-message
|
||||
msgs := genStdTx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("each genesis transaction must provide a single genesis message")
|
||||
return
|
||||
|
||||
return appGenTxs, persistentPeers, errors.New(
|
||||
"each genesis transaction must provide a single genesis message")
|
||||
}
|
||||
|
||||
// TODO: this could be decoupled from stake.MsgCreateValidator
|
||||
// TODO: and we likely want to do it for real world Gaia
|
||||
// validate the validator address and funds against the accounts in the state
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
validators = append(validators, tmtypes.GenesisValidator{
|
||||
PubKey: msg.PubKey,
|
||||
Power: freeFermionVal,
|
||||
Name: msg.Description.Moniker,
|
||||
})
|
||||
addr := string(sdk.AccAddress(msg.ValidatorAddr))
|
||||
acc, ok := addrMap[addr]
|
||||
if !ok {
|
||||
return appGenTxs, persistentPeers, fmt.Errorf(
|
||||
"account %v not in genesis.json: %+v", addr, addrMap)
|
||||
}
|
||||
if acc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) {
|
||||
err = fmt.Errorf("insufficient fund for the delegation: %s < %s",
|
||||
acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount)
|
||||
}
|
||||
|
||||
// exclude itself from persistent peers
|
||||
if msg.Description.Moniker != moniker {
|
||||
addresses = append(addresses, nodeAddr)
|
||||
addressesIPs = append(addressesIPs, nodeAddrIP)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(addresses)
|
||||
persistentPeers = strings.Join(addresses, ",")
|
||||
sort.Strings(addressesIPs)
|
||||
persistentPeers = strings.Join(addressesIPs, ",")
|
||||
|
||||
return
|
||||
return appGenTxs, persistentPeers, nil
|
||||
}
|
||||
|
||||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -27,7 +29,8 @@ var (
|
|||
|
||||
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
appState := NewDefaultGenesisState()
|
||||
stakeData := appState.StakeData
|
||||
genAccs := make([]GenesisAccount, len(genTxs))
|
||||
|
||||
for i, genTx := range genTxs {
|
||||
|
@ -35,17 +38,15 @@ func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
|||
require.Equal(t, 1, len(msgs))
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// get genesis flag account information
|
||||
genAccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
||||
acc.Coins = sdk.Coins{sdk.NewInt64Coin(bondDenom, 150)}
|
||||
genAccs[i] = NewGenesisAccount(&acc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(150)) // increase the supply
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
return GenesisState{
|
||||
Accounts: genAccs,
|
||||
StakeData: stakeData,
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}
|
||||
appState.Accounts = genAccs
|
||||
return appState
|
||||
}
|
||||
|
||||
func TestToAccount(t *testing.T) {
|
||||
|
@ -68,6 +69,19 @@ func TestGaiaAppGenTx(t *testing.T) {
|
|||
func TestGaiaAppGenState(t *testing.T) {
|
||||
cdc := MakeCodec()
|
||||
_ = cdc
|
||||
var genDoc tmtypes.GenesisDoc
|
||||
|
||||
// test unmarshalling error
|
||||
_, err := GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
|
||||
require.Error(t, err)
|
||||
|
||||
appState := makeGenesisState(t, []auth.StdTx{})
|
||||
genDoc.AppState, err = json.Marshal(appState)
|
||||
require.NoError(t, err)
|
||||
|
||||
// test validation error
|
||||
_, err = GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
|
||||
require.Error(t, err)
|
||||
|
||||
// TODO test must provide at least genesis transaction
|
||||
// TODO test with both one and two genesis transactions:
|
||||
|
@ -77,7 +91,8 @@ func TestGaiaAppGenState(t *testing.T) {
|
|||
func makeMsg(name string, pk crypto.PubKey) auth.StdTx {
|
||||
desc := stake.NewDescription(name, "", "", "")
|
||||
comm := stakeTypes.CommissionMsg{}
|
||||
msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin("steak", 50), desc, comm)
|
||||
msg := stake.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(bondDenom,
|
||||
50), desc, comm)
|
||||
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
|
||||
}
|
||||
|
||||
|
@ -106,3 +121,10 @@ func TestGaiaGenesisValidation(t *testing.T) {
|
|||
err = GaiaValidateGenesisState(genesisState)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
func TestNewDefaultGenesisAccount(t *testing.T) {
|
||||
addr := secp256k1.GenPrivKeySecp256k1([]byte("")).PubKey().Address()
|
||||
acc := NewDefaultGenesisAccount(sdk.AccAddress(addr))
|
||||
require.Equal(t, sdk.NewInt(1000), acc.Coins.AmountOf("fooToken"))
|
||||
require.Equal(t, sdk.NewInt(150), acc.Coins.AmountOf(bondDenom))
|
||||
}
|
||||
|
|
|
@ -5,9 +5,11 @@ package clitest
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -207,7 +209,7 @@ func TestGaiaCLIGasAuto(t *testing.T) {
|
|||
|
||||
func TestGaiaCLICreateValidator(t *testing.T) {
|
||||
chainID, servAddr, port := initializeFixtures(t)
|
||||
flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID)
|
||||
flags := fmt.Sprintf("--home=%s --chain-id=%v --node=%s", gaiacliHome, chainID, servAddr)
|
||||
|
||||
// start gaiad server
|
||||
proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr))
|
||||
|
@ -544,7 +546,7 @@ func TestGaiaCLIConfig(t *testing.T) {
|
|||
servAddr, port, err := server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
node := fmt.Sprintf("%s:%s", servAddr, port)
|
||||
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
|
||||
chainID := executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||
executeWrite(t, fmt.Sprintf("gaiacli --home=%s config", gaiadHome), gaiacliHome, node, "y")
|
||||
config, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml"))
|
||||
require.NoError(t, err)
|
||||
|
@ -594,12 +596,27 @@ func initializeFixtures(t *testing.T) (chainID, servAddr, port string) {
|
|||
tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe-reset-all", gaiadHome), "")
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
|
||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome))
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf(
|
||||
"gaiacli keys show foo --output=json --home=%s", gaiacliHome))
|
||||
chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome))
|
||||
genFile := filepath.Join(gaiadHome, "config", "genesis.json")
|
||||
genDoc := readGenesisFile(t, genFile)
|
||||
var appState app.GenesisState
|
||||
err := codec.Cdc.UnmarshalJSON(genDoc.AppState, &appState)
|
||||
require.NoError(t, err)
|
||||
appState.Accounts = []app.GenesisAccount{app.NewDefaultGenesisAccount(fooAddr)}
|
||||
appStateJSON, err := codec.Cdc.MarshalJSON(appState)
|
||||
require.NoError(t, err)
|
||||
genDoc.AppState = appStateJSON
|
||||
genDoc.SaveAs(genFile)
|
||||
executeWrite(t, fmt.Sprintf(
|
||||
"gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome),
|
||||
app.DefaultKeyPass)
|
||||
executeWrite(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass)
|
||||
// get a free port, also setup some common flags
|
||||
servAddr, port, err := server.FreeTCPAddr()
|
||||
servAddr, port, err = server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
return
|
||||
}
|
||||
|
@ -618,6 +635,18 @@ func writeToNewTempFile(t *testing.T, s string) *os.File {
|
|||
return fp
|
||||
}
|
||||
|
||||
func readGenesisFile(t *testing.T, genFile string) types.GenesisDoc {
|
||||
var genDoc types.GenesisDoc
|
||||
fp, err := os.Open(genFile)
|
||||
require.NoError(t, err)
|
||||
fileContents, err := ioutil.ReadAll(fp)
|
||||
require.NoError(t, err)
|
||||
defer fp.Close()
|
||||
err = codec.Cdc.UnmarshalJSON(fileContents, &genDoc)
|
||||
require.NoError(t, err)
|
||||
return genDoc
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
// executors
|
||||
|
||||
|
|
|
@ -39,7 +39,8 @@ func main() {
|
|||
}
|
||||
appInit := app.GaiaAppInit()
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, server.AppInit{}))
|
||||
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/go-amino"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
type initConfig struct {
|
||||
ChainID string
|
||||
GenTxsDir string
|
||||
Name string
|
||||
NodeID string
|
||||
ValPubKey crypto.PubKey
|
||||
}
|
||||
|
||||
// nolint
|
||||
func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "collect-gentxs",
|
||||
Short: "Collect genesis txs and output a genesis.json file",
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint := printInfo{
|
||||
Moniker: config.Moniker,
|
||||
ChainID: genDoc.ChainID,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
|
||||
initCfg := initConfig{
|
||||
ChainID: genDoc.ChainID,
|
||||
GenTxsDir: filepath.Join(config.RootDir, "config", "gentx"),
|
||||
Name: name,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint.AppMessage = appMessage
|
||||
// print out some key information
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func genAppStateFromConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig,
|
||||
genDoc types.GenesisDoc) (appState json.RawMessage, err error) {
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
// process genesis transactions, else create default genesis.json
|
||||
var appGenTxs []auth.StdTx
|
||||
var persistentPeers string
|
||||
var genTxs []json.RawMessage
|
||||
var jsonRawTx json.RawMessage
|
||||
|
||||
appGenTxs, persistentPeers, err = app.CollectStdTxs(
|
||||
cdc, config.Moniker, initCfg.GenTxsDir, genDoc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs = make([]json.RawMessage, len(appGenTxs))
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
for i, stdTx := range appGenTxs {
|
||||
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs[i] = jsonRawTx
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
appState, err = app.GaiaAppGenStateJSON(cdc, genDoc, genTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = WriteGenesisFile(genFile, initCfg.ChainID, nil, appState)
|
||||
return
|
||||
}
|
||||
|
||||
func loadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
|
||||
genContents, err := ioutil.ReadFile(genFile)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = cdc.UnmarshalJSON(genContents, &genDoc)
|
||||
return
|
||||
}
|
|
@ -55,9 +55,20 @@ following delegation and commission default parameters:
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Read --pubkey, if empty take it from priv_validator.json
|
||||
if valPubKeyString := viper.GetString(cli.FlagPubKey); valPubKeyString != "" {
|
||||
valPubKey, err = sdk.GetConsPubKeyBech32(valPubKeyString)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Run gaiad tx create-validator
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, valPubKey)
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
|
||||
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
|
||||
|
||||
w, err := ioutil.TempFile("", "gentx")
|
||||
|
@ -82,28 +93,41 @@ following delegation and commission default parameters:
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(tmcli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id")
|
||||
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
|
||||
cmd.Flags().AddFlagSet(cli.FsCommissionCreate)
|
||||
cmd.Flags().AddFlagSet(cli.FsAmount)
|
||||
cmd.Flags().AddFlagSet(cli.FsPk)
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip string, valPubKey crypto.PubKey) {
|
||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
||||
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID string,
|
||||
valPubKey crypto.PubKey) {
|
||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
||||
viper.Set(client.FlagChainID, chainID)
|
||||
viper.Set(client.FlagFrom, viper.GetString(client.FlagName)) // --from
|
||||
viper.Set(cli.FlagNodeID, nodeID) // --node-id
|
||||
viper.Set(cli.FlagIP, ip) // --ip
|
||||
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey)) // --pubkey
|
||||
viper.Set(cli.FlagAmount, defaultAmount) // --amount
|
||||
viper.Set(cli.FlagCommissionRate, defaultCommissionRate)
|
||||
viper.Set(cli.FlagCommissionMaxRate, defaultCommissionMaxRate)
|
||||
viper.Set(cli.FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate)
|
||||
viper.Set(cli.FlagGenesisFormat, true) // --genesis-format
|
||||
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
|
||||
viper.Set(cli.FlagGenesisFormat, true) // --genesis-format
|
||||
viper.Set(cli.FlagMoniker, config.Moniker) // --moniker
|
||||
if config.Moniker == "" {
|
||||
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
|
||||
}
|
||||
if viper.GetString(cli.FlagAmount) == "" {
|
||||
viper.Set(cli.FlagAmount, defaultAmount)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionRate) == "" {
|
||||
viper.Set(cli.FlagCommissionRate, defaultCommissionRate)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionMaxRate) == "" {
|
||||
viper.Set(cli.FlagCommissionMaxRate, defaultCommissionMaxRate)
|
||||
}
|
||||
if viper.GetString(cli.FlagCommissionMaxChangeRate) == "" {
|
||||
viper.Set(cli.FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate)
|
||||
}
|
||||
}
|
||||
|
||||
func prepareFlagsForTxSign() {
|
||||
|
|
|
@ -2,24 +2,19 @@ package init
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
|
@ -27,26 +22,11 @@ import (
|
|||
)
|
||||
|
||||
const (
|
||||
flagWithTxs = "with-txs"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagOverwriteKey = "overwrite-key"
|
||||
flagSkipGenesis = "skip-genesis"
|
||||
flagMoniker = "moniker"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagMoniker = "moniker"
|
||||
)
|
||||
|
||||
type initConfig struct {
|
||||
ChainID string
|
||||
GenTxsDir string
|
||||
Name string
|
||||
NodeID string
|
||||
ClientHome string
|
||||
WithTxs bool
|
||||
Overwrite bool
|
||||
OverwriteKey bool
|
||||
ValPubKey crypto.PubKey
|
||||
}
|
||||
|
||||
type printInfo struct {
|
||||
Moniker string `json:"moniker"`
|
||||
ChainID string `json:"chain_id"`
|
||||
|
@ -70,22 +50,16 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize private validator, p2p, genesis, and application configuration files",
|
||||
Long: `Initialize validators's and node's configuration files.
|
||||
|
||||
Note that only node's configuration files will be written if the flag --skip-genesis is
|
||||
enabled, and the genesis file will not be generated.
|
||||
`,
|
||||
Args: cobra.NoArgs,
|
||||
Long: `Initialize validators's and node's configuration files.`,
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
|
||||
name := viper.GetString(client.FlagName)
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
if chainID == "" {
|
||||
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
|
||||
nodeID, _, err := InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -93,37 +67,26 @@ enabled, and the genesis file will not be generated.
|
|||
if viper.GetString(flagMoniker) != "" {
|
||||
config.Moniker = viper.GetString(flagMoniker)
|
||||
}
|
||||
if config.Moniker == "" && name != "" {
|
||||
config.Moniker = name
|
||||
}
|
||||
toPrint := printInfo{
|
||||
ChainID: chainID,
|
||||
Moniker: config.Moniker,
|
||||
NodeID: nodeID,
|
||||
}
|
||||
if viper.GetBool(flagSkipGenesis) {
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
return displayInfo(cdc, toPrint)
|
||||
}
|
||||
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: filepath.Join(config.RootDir, "config", "gentx"),
|
||||
Name: name,
|
||||
NodeID: nodeID,
|
||||
ClientHome: viper.GetString(flagClientHome),
|
||||
WithTxs: viper.GetBool(flagWithTxs),
|
||||
Overwrite: viper.GetBool(flagOverwrite),
|
||||
OverwriteKey: viper.GetBool(flagOverwriteKey),
|
||||
ValPubKey: valPubKey,
|
||||
var appState json.RawMessage
|
||||
genFile := config.GenesisFile()
|
||||
if appState, err = initializeEmptyGenesis(cdc, genFile, chainID,
|
||||
viper.GetBool(flagOverwrite)); err != nil {
|
||||
return err
|
||||
}
|
||||
appMessage, err := initWithConfig(cdc, config, initCfg)
|
||||
// print out some key information
|
||||
if err != nil {
|
||||
if err = WriteGenesisFile(genFile, chainID, nil, appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint.AppMessage = appMessage
|
||||
toPrint := printInfo{
|
||||
ChainID: chainID,
|
||||
Moniker: config.Moniker,
|
||||
NodeID: nodeID,
|
||||
AppMessage: appState,
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
|
@ -131,12 +94,7 @@ enabled, and the genesis file will not be generated.
|
|||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().Bool(flagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
|
||||
cmd.Flags().String(flagMoniker, "", "overrides --name flag and set the validator's moniker to a different value; ignored if it runs without the --with-txs flag")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().Bool(flagOverwriteKey, false, "overwrite client's key")
|
||||
cmd.Flags().Bool(flagSkipGenesis, false, "do not create genesis.json")
|
||||
cmd.Flags().String(flagMoniker, "", "set the validator's moniker")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -151,105 +109,6 @@ func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey
|
|||
return
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig) (
|
||||
appMessage json.RawMessage, err error) {
|
||||
genFile := config.GenesisFile()
|
||||
if !initCfg.Overwrite && common.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
// process genesis transactions, else create default genesis.json
|
||||
var appGenTxs []auth.StdTx
|
||||
var persistentPeers string
|
||||
var genTxs []json.RawMessage
|
||||
var appState json.RawMessage
|
||||
var jsonRawTx json.RawMessage
|
||||
chainID := initCfg.ChainID
|
||||
|
||||
if initCfg.WithTxs {
|
||||
_, appGenTxs, persistentPeers, err = app.CollectStdTxs(config.Moniker, initCfg.GenTxsDir, cdc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs = make([]json.RawMessage, len(appGenTxs))
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
for i, stdTx := range appGenTxs {
|
||||
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs[i] = jsonRawTx
|
||||
}
|
||||
} else {
|
||||
var ip, keyPass, secret string
|
||||
var addr sdk.AccAddress
|
||||
var signedTx auth.StdTx
|
||||
|
||||
if initCfg.Name == "" {
|
||||
err = errors.New("must specify validator's moniker (--name)")
|
||||
return
|
||||
}
|
||||
|
||||
config.Moniker = initCfg.Name
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
memo := fmt.Sprintf("%s@%s:26656", initCfg.NodeID, ip)
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password for account %q (default: %q):", initCfg.Name, app.DefaultKeyPass)
|
||||
keyPass, err = client.GetPassword(prompt, buf)
|
||||
if err != nil && keyPass != "" {
|
||||
// An error was returned that either failed to read the password from
|
||||
// STDIN or the given password is not empty but failed to meet minimum
|
||||
// length requirements.
|
||||
return
|
||||
}
|
||||
if keyPass == "" {
|
||||
keyPass = app.DefaultKeyPass
|
||||
}
|
||||
|
||||
addr, secret, err = server.GenerateSaveCoinKey(initCfg.ClientHome, initCfg.Name, keyPass, initCfg.OverwriteKey)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appMessage, err = json.Marshal(map[string]string{"secret": secret})
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
initCfg.ValPubKey,
|
||||
sdk.NewInt64Coin("steak", 100),
|
||||
stake.NewDescription(config.Moniker, "", "", ""),
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
txBldr := authtx.NewTxBuilderFromCLI().WithCodec(cdc).WithMemo(memo).WithChainID(chainID)
|
||||
signedTx, err = txBldr.SignStdTx(
|
||||
initCfg.Name, keyPass, auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo), false,
|
||||
)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
jsonRawTx, err = cdc.MarshalJSON(signedTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs = []json.RawMessage{jsonRawTx}
|
||||
}
|
||||
|
||||
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
|
||||
appState, err = app.GaiaAppGenStateJSON(cdc, genTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = WriteGenesisFile(genFile, chainID, nil, appState)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
|
@ -279,3 +138,13 @@ func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
|
|||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
func initializeEmptyGenesis(cdc *codec.Codec, genFile string, chainID string,
|
||||
overwrite bool) (appState json.RawMessage, err error) {
|
||||
if !overwrite && common.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
return codec.MarshalJSONIndent(cdc, app.NewDefaultGenesisState())
|
||||
}
|
||||
|
|
|
@ -42,7 +42,6 @@ func setupClientHome(t *testing.T) func() {
|
|||
clientDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
viper.Set(flagClientHome, clientDir)
|
||||
viper.Set(flagOverwriteKey, true)
|
||||
return func() {
|
||||
if err := os.RemoveAll(clientDir); err != nil {
|
||||
// TODO: Handle with #870
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
@ -35,7 +36,9 @@ var (
|
|||
const nodeDirPerm = 0755
|
||||
|
||||
// get cmd to initialize all files for tendermint testnet and application
|
||||
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec,
|
||||
appInit server.AppInit) *cobra.Command {
|
||||
|
||||
cmd := &cobra.Command{
|
||||
Use: "testnet",
|
||||
Short: "Initialize files for a Gaiad testnet",
|
||||
|
@ -50,7 +53,7 @@ Example:
|
|||
`,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
return testnetWithConfig(config, cdc, appInit)
|
||||
return testnetWithConfig(config, cdc)
|
||||
},
|
||||
}
|
||||
cmd.Flags().Int(nValidators, 4,
|
||||
|
@ -69,7 +72,7 @@ Example:
|
|||
return cmd
|
||||
}
|
||||
|
||||
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) error {
|
||||
func testnetWithConfig(config *cfg.Config, cdc *codec.Codec) error {
|
||||
outDir := viper.GetString(outputDir)
|
||||
numValidators := viper.GetInt(nValidators)
|
||||
|
||||
|
@ -80,6 +83,8 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
valPubKeys := make([]crypto.PubKey, numValidators)
|
||||
|
||||
// Generate private key, node ID, initial transaction
|
||||
var accs []app.GenesisAccount
|
||||
var genFiles []string
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||
|
@ -115,8 +120,12 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
}
|
||||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
|
||||
// write genesis
|
||||
genFiles = append(genFiles, config.GenesisFile())
|
||||
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass)
|
||||
prompt := fmt.Sprintf(
|
||||
"Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass)
|
||||
keyPass, err := client.GetPassword(prompt, buf)
|
||||
if err != nil && keyPass != "" {
|
||||
// An error was returned that either failed to read the password from
|
||||
|
@ -138,12 +147,20 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Save private key seed words
|
||||
// save private key seed words
|
||||
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
accs = append(accs, app.GenesisAccount{
|
||||
Address: addr,
|
||||
Coins: sdk.Coins{
|
||||
sdk.NewInt64Coin(fmt.Sprintf("%sToken", nodeDirName), 1000),
|
||||
sdk.NewInt64Coin("steak", 150),
|
||||
},
|
||||
})
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
|
@ -173,8 +190,27 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
}
|
||||
}
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
// Generate empty genesis.json
|
||||
appGenState := app.NewDefaultGenesisState()
|
||||
appGenState.Accounts = accs
|
||||
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
AppState: appGenStateJSON,
|
||||
Validators: nil,
|
||||
}
|
||||
|
||||
// Save all genesis.json files
|
||||
for i := 0; i < numValidators; i++ {
|
||||
if err := genDoc.SaveAs(genFiles[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||
|
@ -186,16 +222,17 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||
// Run `init` and generate genesis.json and config.toml
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: gentxsDir,
|
||||
Name: moniker,
|
||||
WithTxs: true,
|
||||
Overwrite: true,
|
||||
OverwriteKey: false,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
ChainID: chainID,
|
||||
GenTxsDir: gentxsDir,
|
||||
Name: moniker,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
if _, err := initWithConfig(cdc, config, initCfg); err != nil {
|
||||
genDoc, err := loadGenesisDoc(cdc, config.GenesisFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err := genAppStateFromConfig(cdc, config, initCfg, genDoc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,6 @@ func main() {
|
|||
|
||||
appInit := server.DefaultAppInit
|
||||
rootCmd.AddCommand(InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
@ -85,7 +84,8 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
appState, err := appInit.AppGenState(
|
||||
cdc, tmtypes.GenesisDoc{}, []json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -108,13 +108,15 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagChainID, "",
|
||||
"genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
|
@ -124,7 +126,8 @@ func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Applicatio
|
|||
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
||||
}
|
||||
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, storeTracer io.Writer) (
|
||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
bapp := app.NewBasecoinApp(logger, db)
|
||||
return bapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
|
|
@ -36,8 +36,9 @@ var CoolAppInit = server.AppInit{
|
|||
}
|
||||
|
||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||
func CoolAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
appState, err = server.SimpleAppGenState(cdc, appGenTxs)
|
||||
func CoolAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
appState, err = server.SimpleAppGenState(cdc, tmtypes.GenesisDoc{}, appGenTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -90,7 +91,8 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
appState, err := appInit.AppGenState(cdc, tmtypes.GenesisDoc{},
|
||||
[]json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -113,13 +115,15 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cob
|
|||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID, []tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
return gaiaInit.WriteGenesisFile(config.GenesisFile(), chainID,
|
||||
[]tmtypes.GenesisValidator{validator}, appStateJSON)
|
||||
},
|
||||
}
|
||||
|
||||
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
|
||||
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagChainID, "",
|
||||
"genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(client.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
|
@ -129,7 +133,8 @@ func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
|
|||
return app.NewDemocoinApp(logger, db)
|
||||
}
|
||||
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer) (json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
func exportAppStateAndTMValidators(logger log.Logger, db dbm.DB, _ io.Writer) (
|
||||
json.RawMessage, []tmtypes.GenesisValidator, error) {
|
||||
dapp := app.NewDemocoinApp(logger, db)
|
||||
return dapp.ExportAppStateAndValidators()
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ import (
|
|||
type AppInit struct {
|
||||
// AppGenState creates the core parameters initialization. It takes in a
|
||||
// pubkey meant to represent the pubkey of the validator of this machine.
|
||||
AppGenState func(cdc *codec.Codec, appGenTx []json.RawMessage) (appState json.RawMessage, err error)
|
||||
AppGenState func(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error)
|
||||
}
|
||||
|
||||
// SimpleGenTx is a simple genesis tx
|
||||
|
@ -35,7 +36,8 @@ var DefaultAppInit = AppInit{
|
|||
}
|
||||
|
||||
// Generate a genesis transaction
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||
var addr sdk.AccAddress
|
||||
var secret string
|
||||
addr, secret, err = GenerateCoinKey()
|
||||
|
@ -63,7 +65,8 @@ func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (appGenTx, cliPrint json
|
|||
}
|
||||
|
||||
// create the genesis app state
|
||||
func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func SimpleAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
|
||||
if len(appGenTxs) != 1 {
|
||||
err = errors.New("must provide a single genesis transaction")
|
||||
|
|
|
@ -3,6 +3,7 @@ package mock
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
|
@ -102,7 +103,8 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci
|
|||
|
||||
// AppGenState can be passed into InitCmd, returns a static string of a few
|
||||
// key-values that can be parsed by InitChainer
|
||||
func AppGenState(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func AppGenState(_ *codec.Codec, _ types.GenesisDoc, _ []json.RawMessage) (appState json.
|
||||
RawMessage, err error) {
|
||||
appState = json.RawMessage(`{
|
||||
"values": [
|
||||
{
|
||||
|
@ -119,7 +121,8 @@ func AppGenState(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage,
|
|||
}
|
||||
|
||||
// AppGenStateEmpty returns an empty transaction state for mocking.
|
||||
func AppGenStateEmpty(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
func AppGenStateEmpty(_ *codec.Codec, _ types.GenesisDoc, _ []json.RawMessage) (
|
||||
appState json.RawMessage, err error) {
|
||||
appState = json.RawMessage(``)
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package mock
|
||||
|
||||
import (
|
||||
"github.com/tendermint/tendermint/types"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -20,7 +21,7 @@ func TestInitApp(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// initialize it future-way
|
||||
appState, err := AppGenState(nil, nil)
|
||||
appState, err := AppGenState(nil, types.GenesisDoc{}, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
//TODO test validators in the init chain?
|
||||
|
|
|
@ -35,11 +35,11 @@ const (
|
|||
|
||||
// common flagsets to add to various functions
|
||||
var (
|
||||
fsPk = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsAmount = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
FsPk = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
FsAmount = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsShares = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsDescriptionCreate = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsCommissionCreate = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
FsCommissionCreate = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsCommissionUpdate = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsDescriptionEdit = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
fsValidator = flag.NewFlagSet("", flag.ContinueOnError)
|
||||
|
@ -48,8 +48,8 @@ var (
|
|||
)
|
||||
|
||||
func init() {
|
||||
fsPk.String(FlagPubKey, "", "Go-Amino encoded hex PubKey of the validator. For Ed25519 the go-amino prepend hex is 1624de6220")
|
||||
fsAmount.String(FlagAmount, "", "Amount of coins to bond")
|
||||
FsPk.String(FlagPubKey, "", "Bech32-encoded PubKey of the validator. ")
|
||||
FsAmount.String(FlagAmount, "", "Amount of coins to bond")
|
||||
fsShares.String(FlagSharesAmount, "", "Amount of source-shares to either unbond or redelegate as a positive integer or decimal")
|
||||
fsShares.String(FlagSharesFraction, "", "Fraction of source-shares to either unbond or redelegate as a positive integer or decimal >0 and <=1")
|
||||
fsDescriptionCreate.String(FlagMoniker, "", "validator name")
|
||||
|
@ -57,9 +57,9 @@ func init() {
|
|||
fsDescriptionCreate.String(FlagWebsite, "", "optional website")
|
||||
fsDescriptionCreate.String(FlagDetails, "", "optional details")
|
||||
fsCommissionUpdate.String(FlagCommissionRate, "", "The new commission rate percentage")
|
||||
fsCommissionCreate.String(FlagCommissionRate, "", "The initial commission rate percentage")
|
||||
fsCommissionCreate.String(FlagCommissionMaxRate, "", "The maximum commission rate percentage")
|
||||
fsCommissionCreate.String(FlagCommissionMaxChangeRate, "", "The maximum commission change rate percentage (per day)")
|
||||
FsCommissionCreate.String(FlagCommissionRate, "", "The initial commission rate percentage")
|
||||
FsCommissionCreate.String(FlagCommissionMaxRate, "", "The maximum commission rate percentage")
|
||||
FsCommissionCreate.String(FlagCommissionMaxChangeRate, "", "The maximum commission change rate percentage (per day)")
|
||||
fsDescriptionEdit.String(FlagMoniker, types.DoNotModifyDesc, "validator name")
|
||||
fsDescriptionEdit.String(FlagIdentity, types.DoNotModifyDesc, "optional identity signature (ex. UPort or Keybase)")
|
||||
fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "optional website")
|
||||
|
|
|
@ -103,10 +103,10 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().AddFlagSet(fsPk)
|
||||
cmd.Flags().AddFlagSet(fsAmount)
|
||||
cmd.Flags().AddFlagSet(FsPk)
|
||||
cmd.Flags().AddFlagSet(FsAmount)
|
||||
cmd.Flags().AddFlagSet(fsDescriptionCreate)
|
||||
cmd.Flags().AddFlagSet(fsCommissionCreate)
|
||||
cmd.Flags().AddFlagSet(FsCommissionCreate)
|
||||
cmd.Flags().AddFlagSet(fsDelegator)
|
||||
cmd.Flags().Bool(FlagGenesisFormat, false, "Export the transaction in gen-tx format; it implies --generate-only")
|
||||
cmd.Flags().String(FlagIP, "", fmt.Sprintf("Node's public IP. It takes effect only when used in combination with --%s", FlagGenesisFormat))
|
||||
|
@ -204,7 +204,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command {
|
|||
},
|
||||
}
|
||||
|
||||
cmd.Flags().AddFlagSet(fsAmount)
|
||||
cmd.Flags().AddFlagSet(FsAmount)
|
||||
cmd.Flags().AddFlagSet(fsValidator)
|
||||
|
||||
return cmd
|
||||
|
|
Loading…
Reference in New Issue