Merge PR #2524: Replace GenTx with StdTx
Rework the process of loading a genesis.json file to load a starting app state and set of initial transactions to process. * New function to create genesis account from MsgCreateValidator * Add arg to PrintUnsignedStdTx() to actually operate in offline mode * New func processStdTxs() * Remove gen-tx command * Cleanup, return validators as they need to be written into genesis.json * Modify gaiad init to allow auto-create of stdTx * Remove server/testnet.go * Don't load node_key.json, which might not be available * Get the txs through DeliverTx * Add app.slashingKeeper.AddValidators at the end of genesis * On InitChain(), Signature's account number must be 0 * Add (tentative?) command to generate {node_key,priv_validator}.json files * Reintroduce gaiad testnet * Prompt user for passwords * Update gaia to work with auth.StdTx * Remove test_utils, NewTestGaiaAppGenState is now deprecated * Combine --genesis-format and --generate-only * Improve sign command's --offline flag documentation * Moniker must be set * Call app.slashingKeeper.AddValidators() even if len(txs) == 0 * Refactoring, introduce gaiad init --skip-genesis, code cleanup * Drop unnecessary workaround to make lcd_tests pass * Reintroduce gentx * Simple name changes, GenesisState.Txs -> .GenTxs; OWK -> OverwriteKey; OverwriteKeys -> OverwriteKey
This commit is contained in:
parent
ad355d6c69
commit
593921d04d
|
@ -452,7 +452,7 @@
|
|||
version = "v0.11.0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:a69eebd15b05045ffdb10a984e001fadc5666f74383de3d2a9ee5862ee99cfdc"
|
||||
digest = "1:f9c7a1f3ee087476f4883c33cc7c1bdbe56b9670b2fb27855ea2f386393272f5"
|
||||
name = "github.com/tendermint/tendermint"
|
||||
packages = [
|
||||
"abci/client",
|
||||
|
@ -518,8 +518,8 @@
|
|||
"version",
|
||||
]
|
||||
pruneopts = "UT"
|
||||
revision = "0c9c3292c918617624f6f3fbcd95eceade18bcd5"
|
||||
version = "v0.25.0"
|
||||
revision = "90eda9bfb6e6daeed1c8015df41cb36772d91778"
|
||||
version = "v0.25.1-rc0"
|
||||
|
||||
[[projects]]
|
||||
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||
|
|
|
@ -57,11 +57,11 @@
|
|||
|
||||
[[override]]
|
||||
name = "github.com/tendermint/tendermint"
|
||||
version = "=0.25.0"
|
||||
version = "=0.25.1-rc0"
|
||||
|
||||
## deps without releases:
|
||||
|
||||
[[constraint]]
|
||||
[[override]]
|
||||
name = "golang.org/x/crypto"
|
||||
source = "https://github.com/tendermint/crypto"
|
||||
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba"
|
||||
|
|
|
@ -20,6 +20,7 @@ BREAKING CHANGES
|
|||
* [cli] [\#2190](https://github.com/cosmos/cosmos-sdk/issues/2190) `gaiacli init --gen-txs` is now `gaiacli init --with-txs` to reduce confusion
|
||||
* [cli] \#2073 --from can now be either an address or a key name
|
||||
* [cli] [\#1184](https://github.com/cosmos/cosmos-sdk/issues/1184) Subcommands reorganisation, see [\#2390](https://github.com/cosmos/cosmos-sdk/pull/2390) for a comprehensive list of changes.
|
||||
* [cli] [\#2524](https://github.com/cosmos/cosmos-sdk/issues/2524) Add support offline mode to `gaiacli tx sign`. Lookups are not performed if the flag `--offline` is on.
|
||||
|
||||
* Gaia
|
||||
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
|
||||
|
@ -45,6 +46,12 @@ BREAKING CHANGES
|
|||
* [x/slashing] \#2430 Simulate more slashes, check if validator is jailed before jailing
|
||||
* [x/stake] \#2393 Removed `CompleteUnbonding` and `CompleteRedelegation` Msg types, and instead added unbonding/redelegation queues to endblocker
|
||||
* [x/stake] \#1673 Validators are no longer deleted until they can no longer possibly be slashed
|
||||
* [\#1890](https://github.com/cosmos/cosmos-sdk/issues/1890) Start chain with initial state + sequence of transactions
|
||||
* [cli] Rename `gaiad init gentx` to `gaiad gentx`.
|
||||
* [cli] Add `--skip-genesis` flag to `gaiad init` to prevent `genesis.json` generation.
|
||||
* Drop `GenesisTx` in favor of a signed `StdTx` with only one `MsgCreateValidator` message.
|
||||
* [cli] Port `gaiad init` and `gaiad testnet` to work with `StdTx` genesis transactions.
|
||||
* [cli] Add `--moniker` flag to `gaiad init` to override moniker when generating `genesis.json` - i.e. it takes effect when running with the `--with-txs` flag, it is ignored otherwise.
|
||||
|
||||
* SDK
|
||||
* [core] \#2219 Update to Tendermint 0.24.0
|
||||
|
@ -115,6 +122,7 @@ FEATURES
|
|||
* [cli] \#2220 Add `gaiacli config` feature to interactively create CLI config files to reduce the number of required flags
|
||||
* [stake][cli] [\#1672](https://github.com/cosmos/cosmos-sdk/issues/1672) Introduced
|
||||
new commission flags for validator commands `create-validator` and `edit-validator`.
|
||||
* [stake][cli] [\#1890](https://github.com/cosmos/cosmos-sdk/issues/1890) Add `--genesis-format` flag to `gaiacli tx create-validator` to produce transactions in genesis-friendly format.
|
||||
|
||||
* Gaia
|
||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
||||
|
|
|
@ -496,7 +496,7 @@ func TestValidatorsQuery(t *testing.T) {
|
|||
require.Equal(t, 1, len(operAddrs))
|
||||
|
||||
validators := getValidators(t, port)
|
||||
require.Equal(t, len(validators), 1)
|
||||
require.Equal(t, 1, len(validators), fmt.Sprintf("%+v", validators))
|
||||
|
||||
// make sure all the validators were found (order unknown because sorted by operator addr)
|
||||
foundVal := false
|
||||
|
|
|
@ -4,6 +4,8 @@ import (
|
|||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/http"
|
||||
|
@ -14,7 +16,7 @@ import (
|
|||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
@ -26,6 +28,7 @@ import (
|
|||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
tmcfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
@ -205,42 +208,43 @@ func InitializeTestLCD(
|
|||
|
||||
genesisFile := config.GenesisFile()
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||
require.NoError(t, err)
|
||||
|
||||
// append initial (proposing) validator
|
||||
genDoc.Validators[0] = tmtypes.GenesisValidator{
|
||||
PubKey: privVal.GetPubKey(),
|
||||
Power: 100, // create enough power to enable 2/3 voting power
|
||||
Name: "validator-1",
|
||||
}
|
||||
require.Nil(t, err)
|
||||
genDoc.Validators = nil
|
||||
genDoc.SaveAs(genesisFile)
|
||||
genTxs := []json.RawMessage{}
|
||||
|
||||
// append any additional (non-proposing) validators
|
||||
for i := 1; i < nValidators; i++ {
|
||||
genDoc.Validators = append(genDoc.Validators,
|
||||
tmtypes.GenesisValidator{
|
||||
PubKey: ed25519.GenPrivKey().PubKey(),
|
||||
Power: 1,
|
||||
Name: fmt.Sprintf("validator-%d", i+1),
|
||||
},
|
||||
for i := 0; i < nValidators; i++ {
|
||||
operPrivKey := secp256k1.GenPrivKey()
|
||||
operAddr := operPrivKey.PubKey().Address()
|
||||
pubKey := privVal.PubKey
|
||||
delegation := 100
|
||||
if i > 0 {
|
||||
pubKey = ed25519.GenPrivKey().PubKey()
|
||||
delegation = 1
|
||||
}
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(operAddr),
|
||||
pubKey,
|
||||
sdk.NewCoin("steak", sdk.NewInt(int64(delegation))),
|
||||
stake.Description{Moniker: fmt.Sprintf("validator-%d", i+1)},
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
}
|
||||
|
||||
var appGenTxs []json.RawMessage
|
||||
|
||||
for _, gdValidator := range genDoc.Validators {
|
||||
operAddr := ed25519.GenPrivKey().PubKey().Address()
|
||||
pk := gdValidator.PubKey
|
||||
|
||||
valConsPubKeys = append(valConsPubKeys, pk)
|
||||
stdSignMsg := txbuilder.StdSignMsg{
|
||||
ChainID: genDoc.ChainID,
|
||||
Msgs: []sdk.Msg{msg},
|
||||
}
|
||||
sig, err := operPrivKey.Sign(stdSignMsg.Bytes())
|
||||
require.Nil(t, err)
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
|
||||
txBytes, err := cdc.MarshalJSON(tx)
|
||||
require.Nil(t, err)
|
||||
genTxs = append(genTxs, txBytes)
|
||||
valConsPubKeys = append(valConsPubKeys, pubKey)
|
||||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
||||
|
||||
appGenTx, _, _, err := gapp.GaiaAppGenTxNF(cdc, pk, sdk.AccAddress(operAddr), gdValidator.Name)
|
||||
require.NoError(t, err)
|
||||
|
||||
appGenTxs = append(appGenTxs, appGenTx)
|
||||
}
|
||||
|
||||
genesisState, err := gapp.NewTestGaiaAppGenState(cdc, appGenTxs[:], genDoc.Validators, valOperAddrs)
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, genTxs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// add some tokens to init accounts
|
||||
|
|
|
@ -107,7 +107,8 @@ func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
|
|||
|
||||
// SignStdTx appends a signature to a StdTx and returns a copy of a it. If appendSig
|
||||
// is false, it replaces the signatures already attached with the new signature.
|
||||
func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool) (auth.StdTx, error) {
|
||||
// Don't perform online validation or lookups if offline is true.
|
||||
func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string, stdTx auth.StdTx, appendSig bool, offline bool) (auth.StdTx, error) {
|
||||
var signedStdTx auth.StdTx
|
||||
|
||||
keybase, err := keys.GetKeyBase()
|
||||
|
@ -122,10 +123,10 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
|||
|
||||
// Check whether the address is a signer
|
||||
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
|
||||
fmt.Fprintf(os.Stderr, "WARNING: The generated transaction's intended signer does not match the given signer: '%v'", name)
|
||||
fmt.Fprintf(os.Stderr, "WARNING: The generated transaction's intended signer does not match the given signer: '%v'\n", name)
|
||||
}
|
||||
|
||||
if txBldr.AccountNumber == 0 {
|
||||
if !offline && txBldr.AccountNumber == 0 {
|
||||
accNum, err := cliCtx.GetAccountNumber(addr)
|
||||
if err != nil {
|
||||
return signedStdTx, err
|
||||
|
@ -133,7 +134,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
|||
txBldr = txBldr.WithAccountNumber(accNum)
|
||||
}
|
||||
|
||||
if txBldr.Sequence == 0 {
|
||||
if !offline && txBldr.Sequence == 0 {
|
||||
accSeq, err := cliCtx.GetAccountSequence(addr)
|
||||
if err != nil {
|
||||
return signedStdTx, err
|
||||
|
|
|
@ -2,15 +2,7 @@ package app
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"fmt"
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
|
@ -21,10 +13,20 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
)
|
||||
|
||||
const (
|
||||
appName = "GaiaApp"
|
||||
// DefaultKeyPass contains the default key password for genesis transactions
|
||||
DefaultKeyPass = "12345678"
|
||||
)
|
||||
|
||||
// default home directories for expected binaries
|
||||
|
@ -238,6 +240,38 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
if len(genesisState.GenTxs) > 0 {
|
||||
for _, genTx := range genesisState.GenTxs {
|
||||
var tx auth.StdTx
|
||||
err = app.cdc.UnmarshalJSON(genTx, &tx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bz := app.cdc.MustMarshalBinary(tx)
|
||||
res := app.BaseApp.DeliverTx(bz)
|
||||
if !res.IsOK() {
|
||||
panic(res.Log)
|
||||
}
|
||||
}
|
||||
|
||||
validators = app.stakeKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
}
|
||||
app.slashingKeeper.AddValidators(ctx, validators)
|
||||
|
||||
// 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)))
|
||||
}
|
||||
sort.Sort(abci.ValidatorUpdates(req.Validators))
|
||||
sort.Sort(abci.ValidatorUpdates(validators))
|
||||
for i, val := range validators {
|
||||
if !val.Equal(req.Validators[i]) {
|
||||
panic(fmt.Errorf("validators[%d] != req.Validators[%d] ", i, i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
}
|
||||
|
|
|
@ -4,31 +4,27 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/config"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// DefaultKeyPass contains the default key password for genesis transactions
|
||||
const DefaultKeyPass = "12345678"
|
||||
|
||||
var (
|
||||
// bonded tokens given to genesis validators/accounts
|
||||
freeFermionVal = int64(100)
|
||||
freeFermionsAcc = sdk.NewInt(50)
|
||||
freeFermionsAcc = sdk.NewInt(150)
|
||||
)
|
||||
|
||||
// State to Unmarshal
|
||||
|
@ -38,6 +34,7 @@ type GenesisState struct {
|
|||
DistrData distr.GenesisState `json:"distr"`
|
||||
GovData gov.GenesisState `json:"gov"`
|
||||
SlashingData slashing.GenesisState `json:"slashing"`
|
||||
GenTxs []json.RawMessage `json:"gentxs"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
|
@ -70,97 +67,12 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
|||
|
||||
// get app init parameters for server init command
|
||||
func GaiaAppInit() server.AppInit {
|
||||
fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
|
||||
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
fsAppGenTx.String(server.FlagName, "", "validator moniker, required")
|
||||
fsAppGenTx.String(server.FlagClientHome, DefaultCLIHome,
|
||||
"home directory for the client, used for key generation")
|
||||
fsAppGenTx.Bool(server.FlagOWK, false, "overwrite the accounts created")
|
||||
|
||||
return server.AppInit{
|
||||
FlagsAppGenState: fsAppGenState,
|
||||
FlagsAppGenTx: fsAppGenTx,
|
||||
AppGenTx: GaiaAppGenTx,
|
||||
AppGenState: GaiaAppGenStateJSON,
|
||||
AppGenState: GaiaAppGenStateJSON,
|
||||
}
|
||||
}
|
||||
|
||||
// simple genesis tx
|
||||
type GaiaGenTx struct {
|
||||
Name string `json:"name"`
|
||||
Address sdk.AccAddress `json:"address"`
|
||||
PubKey string `json:"pub_key"`
|
||||
}
|
||||
|
||||
// GaiaAppGenTx generates a Gaia genesis transaction.
|
||||
func GaiaAppGenTx(
|
||||
cdc *codec.Codec, pk crypto.PubKey, genTxConfig config.GenTx,
|
||||
) (appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
if genTxConfig.Name == "" {
|
||||
return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)")
|
||||
}
|
||||
|
||||
buf := client.BufferStdin()
|
||||
prompt := fmt.Sprintf("Password for account '%s' (default %s):", genTxConfig.Name, 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 appGenTx, cliPrint, validator, err
|
||||
}
|
||||
|
||||
if keyPass == "" {
|
||||
keyPass = DefaultKeyPass
|
||||
}
|
||||
|
||||
addr, secret, err := server.GenerateSaveCoinKey(
|
||||
genTxConfig.CliRoot,
|
||||
genTxConfig.Name,
|
||||
keyPass,
|
||||
genTxConfig.Overwrite,
|
||||
)
|
||||
if err != nil {
|
||||
return appGenTx, cliPrint, validator, err
|
||||
}
|
||||
|
||||
mm := map[string]string{"secret": secret}
|
||||
bz, err := cdc.MarshalJSON(mm)
|
||||
if err != nil {
|
||||
return appGenTx, cliPrint, validator, err
|
||||
}
|
||||
|
||||
cliPrint = json.RawMessage(bz)
|
||||
appGenTx, _, validator, err = GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name)
|
||||
|
||||
return appGenTx, cliPrint, validator, err
|
||||
}
|
||||
|
||||
// Generate a gaia genesis transaction without flags
|
||||
func GaiaAppGenTxNF(cdc *codec.Codec, pk crypto.PubKey, addr sdk.AccAddress, name string) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
var bz []byte
|
||||
gaiaGenTx := GaiaGenTx{
|
||||
Name: name,
|
||||
Address: addr,
|
||||
PubKey: sdk.MustBech32ifyConsPub(pk),
|
||||
}
|
||||
bz, err = codec.MarshalJSONIndent(cdc, gaiaGenTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appGenTx = json.RawMessage(bz)
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
Power: freeFermionVal,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// 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) {
|
||||
|
@ -171,27 +83,27 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
|||
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
|
||||
slashingData := slashing.DefaultGenesisState()
|
||||
|
||||
// get genesis flag account information
|
||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||
for i, appGenTx := range appGenTxs {
|
||||
|
||||
var genTx GaiaGenTx
|
||||
err = cdc.UnmarshalJSON(appGenTx, &genTx)
|
||||
for i, genTx := range appGenTxs {
|
||||
var tx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(genTx, &tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
msgs := tx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("must provide genesis StdTx with exactly 1 CreateValidator message")
|
||||
return
|
||||
}
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// create the genesis account, give'm few steaks and a buncha token with there name
|
||||
genaccs[i] = genesisAccountFromGenTx(genTx)
|
||||
genaccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
|
||||
// add the validator
|
||||
if len(genTx.Name) > 0 {
|
||||
stakeData = addValidatorToStakeData(genTx, stakeData)
|
||||
}
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
|
@ -201,41 +113,17 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
|||
DistrData: distr.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
SlashingData: slashingData,
|
||||
GenTxs: appGenTxs,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func addValidatorToStakeData(genTx GaiaGenTx, stakeData stake.GenesisState) stake.GenesisState {
|
||||
desc := stake.NewDescription(genTx.Name, "", "", "")
|
||||
validator := stake.NewValidator(
|
||||
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
|
||||
)
|
||||
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDec(freeFermionVal)) // increase the supply
|
||||
|
||||
// add some new shares to the validator
|
||||
var issuedDelShares sdk.Dec
|
||||
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, sdk.NewInt(freeFermionVal))
|
||||
stakeData.Validators = append(stakeData.Validators, validator)
|
||||
|
||||
// create the self-delegation from the issuedDelShares
|
||||
delegation := stake.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(validator.OperatorAddr),
|
||||
ValidatorAddr: validator.OperatorAddr,
|
||||
Shares: issuedDelShares,
|
||||
Height: 0,
|
||||
}
|
||||
|
||||
stakeData.Bonds = append(stakeData.Bonds, delegation)
|
||||
return stakeData
|
||||
}
|
||||
|
||||
func genesisAccountFromGenTx(genTx GaiaGenTx) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
|
||||
accAuth.Coins = sdk.Coins{
|
||||
{genTx.Name + "Token", sdk.NewInt(1000)},
|
||||
{"steak", freeFermionsAcc},
|
||||
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)
|
||||
}
|
||||
|
@ -249,11 +137,11 @@ func GaiaValidateGenesisState(genesisState GenesisState) (err error) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = stake.ValidateGenesis(genesisState.StakeData)
|
||||
if err != nil {
|
||||
return
|
||||
// skip stakeData validation as genesis is created from txs
|
||||
if len(genesisState.GenTxs) > 0 {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
return stake.ValidateGenesis(genesisState.StakeData)
|
||||
}
|
||||
|
||||
// Ensures that there are no duplicate accounts in the genesis state,
|
||||
|
@ -272,7 +160,6 @@ func validateGenesisStateAccounts(accs []GenesisAccount) (err error) {
|
|||
|
||||
// GaiaAppGenState but with JSON
|
||||
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
|
||||
// create the final app state
|
||||
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
|
@ -281,3 +168,75 @@ func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appStat
|
|||
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
||||
return
|
||||
}
|
||||
|
||||
// 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) {
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var addresses []string
|
||||
for _, fo := range fos {
|
||||
filename := filepath.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
|
||||
continue
|
||||
}
|
||||
|
||||
// get the genStdTx
|
||||
var jsonRawTx []byte
|
||||
jsonRawTx, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var genStdTx auth.StdTx
|
||||
err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
msgs := genStdTx.GetMsgs()
|
||||
if len(msgs) != 1 {
|
||||
err = errors.New("each genesis transaction must provide a single genesis message")
|
||||
return
|
||||
}
|
||||
|
||||
// TODO: this could be decoupled from stake.MsgCreateValidator
|
||||
// TODO: and we likely want to do it for real world Gaia
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
validators = append(validators, tmtypes.GenesisValidator{
|
||||
PubKey: msg.PubKey,
|
||||
Power: freeFermionVal,
|
||||
Name: msg.Description.Moniker,
|
||||
})
|
||||
|
||||
// exclude itself from persistent peers
|
||||
if msg.Description.Moniker != moniker {
|
||||
addresses = append(addresses, nodeAddr)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Strings(addresses)
|
||||
persistentPeers = strings.Join(addresses, ",")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
accAuth.Coins = []sdk.Coin{
|
||||
{"fooToken", sdk.NewInt(1000)},
|
||||
{"steak", freeFermionsAcc},
|
||||
}
|
||||
return NewGenesisAccount(&accAuth)
|
||||
}
|
||||
|
|
|
@ -25,25 +25,24 @@ var (
|
|||
emptyPubkey crypto.PubKey
|
||||
)
|
||||
|
||||
func makeGenesisState(genTxs []GaiaGenTx) GenesisState {
|
||||
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
genAccs := make([]GenesisAccount, len(genTxs))
|
||||
|
||||
// get genesis flag account information
|
||||
genaccs := make([]GenesisAccount, len(genTxs))
|
||||
for i, genTx := range genTxs {
|
||||
genaccs[i] = genesisAccountFromGenTx(genTx)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
msgs := genTx.GetMsgs()
|
||||
require.Equal(t, 1, len(msgs))
|
||||
msg := msgs[0].(stake.MsgCreateValidator)
|
||||
|
||||
// add the validator
|
||||
if len(genTx.Name) > 0 {
|
||||
stakeData = addValidatorToStakeData(genTx, stakeData)
|
||||
}
|
||||
// get genesis flag account information
|
||||
genAccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
return GenesisState{
|
||||
Accounts: genaccs,
|
||||
Accounts: genAccs,
|
||||
StakeData: stakeData,
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}
|
||||
|
@ -75,17 +74,23 @@ func TestGaiaAppGenState(t *testing.T) {
|
|||
// TODO correct: genesis account created, canididates created, pool token variance
|
||||
}
|
||||
|
||||
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)
|
||||
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
|
||||
}
|
||||
|
||||
func TestGaiaGenesisValidation(t *testing.T) {
|
||||
genTxs := make([]GaiaGenTx, 2)
|
||||
addr := pk1.Address()
|
||||
genTxs := make([]auth.StdTx, 2)
|
||||
// Test duplicate accounts fails
|
||||
genTxs[0] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
|
||||
genTxs[1] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
|
||||
genesisState := makeGenesisState(genTxs)
|
||||
genTxs[0] = makeMsg("test-0", pk1)
|
||||
genTxs[1] = makeMsg("test-1", pk1)
|
||||
genesisState := makeGenesisState(t, genTxs)
|
||||
err := GaiaValidateGenesisState(genesisState)
|
||||
require.NotNil(t, err)
|
||||
// Test bonded + jailed validator fails
|
||||
genesisState = makeGenesisState(genTxs[:1])
|
||||
genesisState = makeGenesisState(t, genTxs)
|
||||
val1 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #2"})
|
||||
val1.Jailed = true
|
||||
val1.Status = sdk.Bonded
|
||||
|
@ -94,7 +99,7 @@ func TestGaiaGenesisValidation(t *testing.T) {
|
|||
require.NotNil(t, err)
|
||||
// Test duplicate validator fails
|
||||
val1.Jailed = false
|
||||
genesisState = makeGenesisState(genTxs[:1])
|
||||
genesisState = makeGenesisState(t, genTxs)
|
||||
val2 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #3"})
|
||||
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val1)
|
||||
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val2)
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// NewTestGaiaAppGenState creates the core parameters for a test genesis
|
||||
// initialization given a set of genesis txs, TM validators and their respective
|
||||
// operating addresses.
|
||||
func NewTestGaiaAppGenState(
|
||||
cdc *codec.Codec, appGenTxs []json.RawMessage, tmVals []tmtypes.GenesisValidator, valOperAddrs []sdk.ValAddress,
|
||||
) (GenesisState, error) {
|
||||
|
||||
switch {
|
||||
case len(appGenTxs) == 0:
|
||||
return GenesisState{}, errors.New("must provide at least genesis transaction")
|
||||
case len(tmVals) != len(valOperAddrs):
|
||||
return GenesisState{}, errors.New("number of TM validators does not match number of operator addresses")
|
||||
}
|
||||
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.DefaultGenesisState()
|
||||
|
||||
// get genesis account information
|
||||
genAccs := make([]GenesisAccount, len(appGenTxs))
|
||||
for i, appGenTx := range appGenTxs {
|
||||
|
||||
var genTx GaiaGenTx
|
||||
if err := cdc.UnmarshalJSON(appGenTx, &genTx); err != nil {
|
||||
return GenesisState{}, err
|
||||
}
|
||||
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc))
|
||||
|
||||
// create the genesis account for the given genesis tx
|
||||
genAccs[i] = genesisAccountFromGenTx(genTx)
|
||||
}
|
||||
|
||||
for i, tmVal := range tmVals {
|
||||
var issuedDelShares sdk.Dec
|
||||
|
||||
// increase total supply by validator's power
|
||||
power := sdk.NewInt(tmVal.Power)
|
||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(power))
|
||||
|
||||
// add the validator
|
||||
desc := stake.NewDescription(tmVal.Name, "", "", "")
|
||||
validator := stake.NewValidator(valOperAddrs[i], tmVal.PubKey, desc)
|
||||
|
||||
validator, stakeData.Pool, issuedDelShares = validator.AddTokensFromDel(stakeData.Pool, power)
|
||||
stakeData.Validators = append(stakeData.Validators, validator)
|
||||
|
||||
// create the self-delegation from the issuedDelShares
|
||||
selfDel := stake.Delegation{
|
||||
DelegatorAddr: sdk.AccAddress(validator.OperatorAddr),
|
||||
ValidatorAddr: validator.OperatorAddr,
|
||||
Shares: issuedDelShares,
|
||||
Height: 0,
|
||||
}
|
||||
|
||||
stakeData.Bonds = append(stakeData.Bonds, selfDel)
|
||||
}
|
||||
|
||||
return GenesisState{
|
||||
Accounts: genAccs,
|
||||
StakeData: stakeData,
|
||||
DistrData: distr.DefaultGenesisState(),
|
||||
SlashingData: slashing.DefaultGenesisState(),
|
||||
GovData: gov.DefaultGenesisState(),
|
||||
}, nil
|
||||
}
|
|
@ -311,7 +311,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
||||
|
||||
proposalsQuery := tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
proposalsQuery, _ := tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
require.Equal(t, "No matching proposals found", proposalsQuery)
|
||||
|
||||
// submit a test proposal
|
||||
|
@ -346,7 +346,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
||||
|
||||
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals %v", flags), "")
|
||||
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||
|
||||
depositStr := fmt.Sprintf("gaiacli tx deposit %v", flags)
|
||||
|
@ -400,10 +400,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
require.Equal(t, int64(1), votes[0].ProposalID)
|
||||
require.Equal(t, gov.OptionYes, votes[0].Option)
|
||||
|
||||
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=DepositPeriod %v", flags), "")
|
||||
require.Equal(t, "No matching proposals found", proposalsQuery)
|
||||
|
||||
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=VotingPeriod %v", flags), "")
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --status=VotingPeriod %v", flags), "")
|
||||
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||
|
||||
// submit a second test proposal
|
||||
|
@ -417,7 +417,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
|||
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||
tests.WaitForNextNBlocksTM(2, port)
|
||||
|
||||
proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "")
|
||||
proposalsQuery, _ = tests.ExecuteT(t, fmt.Sprintf("gaiacli query proposals --latest=1 %v", flags), "")
|
||||
require.Equal(t, " 2 - Apples", proposalsQuery)
|
||||
}
|
||||
|
||||
|
@ -628,10 +628,10 @@ func executeWriteRetStdStreams(t *testing.T, cmdStr string, writes ...string) (b
|
|||
}
|
||||
|
||||
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
||||
out := tests.ExecuteT(t, cmdStr, app.DefaultKeyPass)
|
||||
_, stderr := tests.ExecuteT(t, cmdStr, app.DefaultKeyPass)
|
||||
|
||||
var initRes map[string]json.RawMessage
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||
|
@ -641,7 +641,7 @@ func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
|||
}
|
||||
|
||||
func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKey) {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var ko keys.KeyOutput
|
||||
keys.UnmarshalJSON([]byte(out), &ko)
|
||||
|
||||
|
@ -655,7 +655,7 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKe
|
|||
}
|
||||
|
||||
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var initRes map[string]json.RawMessage
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
require.NoError(t, err, "out %v, err %v", out, err)
|
||||
|
@ -672,7 +672,7 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
|||
// stake
|
||||
|
||||
func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var validator stake.Validator
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &validator)
|
||||
|
@ -681,7 +681,7 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
|||
}
|
||||
|
||||
func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var pool stake.Pool
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &pool)
|
||||
|
@ -690,7 +690,7 @@ func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
|
|||
}
|
||||
|
||||
func executeGetParams(t *testing.T, cmdStr string) stake.Params {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var params stake.Params
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), ¶ms)
|
||||
|
@ -702,7 +702,7 @@ func executeGetParams(t *testing.T, cmdStr string) stake.Params {
|
|||
// gov
|
||||
|
||||
func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var proposal gov.Proposal
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &proposal)
|
||||
|
@ -711,7 +711,7 @@ func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
|||
}
|
||||
|
||||
func executeGetVote(t *testing.T, cmdStr string) gov.Vote {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var vote gov.Vote
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &vote)
|
||||
|
@ -720,7 +720,7 @@ func executeGetVote(t *testing.T, cmdStr string) gov.Vote {
|
|||
}
|
||||
|
||||
func executeGetVotes(t *testing.T, cmdStr string) []gov.Vote {
|
||||
out := tests.ExecuteT(t, cmdStr, "")
|
||||
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||
var votes []gov.Vote
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &votes)
|
||||
|
|
|
@ -32,6 +32,7 @@ func main() {
|
|||
appInit := app.GaiaAppInit()
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
newApp, exportAppStateAndTMValidators)
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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"
|
||||
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
tmcli "github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultAmount = "100steak"
|
||||
defaultCommissionRate = "0.1"
|
||||
defaultCommissionMaxRate = "0.2"
|
||||
defaultCommissionMaxChangeRate = "0.01"
|
||||
)
|
||||
|
||||
// GenTxCmd builds the gaiad gentx command.
|
||||
// nolint: errcheck
|
||||
func GenTxCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gentx",
|
||||
Short: "Generate a genesis tx carrying a self delegation",
|
||||
Long: fmt.Sprintf(`This command is an alias of the 'gaiad tx create-validator' command'.
|
||||
|
||||
It creates a genesis piece carrying a self delegation with the
|
||||
following delegation and commission default parameters:
|
||||
|
||||
delegation amount: %s
|
||||
commission rate: %s
|
||||
commission max rate: %s
|
||||
commission max change rate: %s
|
||||
`, defaultAmount, defaultCommissionRate, defaultCommissionMaxRate, defaultCommissionMaxChangeRate),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(tmcli.HomeFlag))
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(ctx.Config)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip, err := server.ExternalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Run gaiad tx create-validator
|
||||
prepareFlagsForTxCreateValidator(config, nodeID, ip, valPubKey)
|
||||
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
|
||||
|
||||
w, err := ioutil.TempFile("", "gentx")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
unsignedGenTxFilename := w.Name()
|
||||
defer os.Remove(unsignedGenTxFilename)
|
||||
os.Stdout = w
|
||||
if err = createValidatorCmd.RunE(nil, args); err != nil {
|
||||
return err
|
||||
}
|
||||
w.Close()
|
||||
|
||||
prepareFlagsForTxSign()
|
||||
signCmd := authcmd.GetSignCommand(cdc, authcmd.GetAccountDecoder(cdc))
|
||||
if w, err = prepareOutputFile(config.RootDir, nodeID); err != nil {
|
||||
return err
|
||||
}
|
||||
os.Stdout = w
|
||||
return signCmd.RunE(nil, []string{unsignedGenTxFilename})
|
||||
},
|
||||
}
|
||||
|
||||
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.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip string, valPubKey crypto.PubKey) {
|
||||
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home
|
||||
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
|
||||
if config.Moniker == "" {
|
||||
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
|
||||
}
|
||||
}
|
||||
|
||||
func prepareFlagsForTxSign() {
|
||||
viper.Set("offline", true)
|
||||
}
|
||||
|
||||
func prepareOutputFile(rootDir, nodeID string) (w *os.File, err error) {
|
||||
writePath := filepath.Join(rootDir, "config", "gentx")
|
||||
if err = common.EnsureDir(writePath, 0700); err != nil {
|
||||
return
|
||||
}
|
||||
filename := filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID))
|
||||
return os.Create(filename)
|
||||
}
|
|
@ -2,311 +2,258 @@ package init
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"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"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
servercfg "github.com/cosmos/cosmos-sdk/server/config"
|
||||
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"
|
||||
"github.com/tendermint/tendermint/privval"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gen-tx",
|
||||
Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
const (
|
||||
flagWithTxs = "with-txs"
|
||||
flagOverwrite = "overwrite"
|
||||
flagClientHome = "home-client"
|
||||
flagOverwriteKey = "overwrite-key"
|
||||
flagSkipGenesis = "skip-genesis"
|
||||
flagMoniker = "moniker"
|
||||
)
|
||||
|
||||
ip := viper.GetString(server.FlagIP)
|
||||
if len(ip) == 0 {
|
||||
eip, err := server.ExternalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ip = eip
|
||||
}
|
||||
|
||||
genTxConfig := servercfg.GenTx{
|
||||
viper.GetString(server.FlagName),
|
||||
viper.GetString(server.FlagClientHome),
|
||||
viper.GetBool(server.FlagOWK),
|
||||
ip,
|
||||
}
|
||||
cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
toPrint := struct {
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
GenTxFile json.RawMessage `json:"gen_tx_file"`
|
||||
}{
|
||||
cliPrint,
|
||||
genTxFile,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cmd.Flags().String(server.FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx)
|
||||
return cmd
|
||||
type initConfig struct {
|
||||
ChainID string
|
||||
GenTxsDir string
|
||||
Name string
|
||||
NodeID string
|
||||
ClientHome string
|
||||
WithTxs bool
|
||||
Overwrite bool
|
||||
OverwriteKey bool
|
||||
ValPubKey crypto.PubKey
|
||||
}
|
||||
|
||||
// NOTE: This will update (write) the config file with
|
||||
// updated name (moniker) for node.
|
||||
func gentxWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, genTxConfig servercfg.GenTx) (
|
||||
cliPrint json.RawMessage, genTxFile json.RawMessage, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
type printInfo struct {
|
||||
Moniker string `json:"moniker"`
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}
|
||||
|
||||
appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
// nolint: errcheck
|
||||
func displayInfo(cdc *codec.Codec, info printInfo) error {
|
||||
out, err := codec.MarshalJSONIndent(cdc, info)
|
||||
if err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
tx := server.GenesisTx{
|
||||
NodeID: nodeID,
|
||||
IP: genTxConfig.IP,
|
||||
Validator: validator,
|
||||
AppGenTx: appGenTx,
|
||||
}
|
||||
bz, err := codec.MarshalJSONIndent(cdc, tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxFile = json.RawMessage(bz)
|
||||
name := fmt.Sprintf("gentx-%v.json", nodeID)
|
||||
writePath := filepath.Join(config.RootDir, "config", "gentx")
|
||||
file := filepath.Join(writePath, name)
|
||||
err = common.EnsureDir(writePath, 0700)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
err = common.WriteFile(file, bz, 0644)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
|
||||
return
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
return nil
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
// nolint: golint
|
||||
// nolint
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
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,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
initConfig := server.InitConfig{
|
||||
viper.GetString(server.FlagChainID),
|
||||
viper.GetBool(server.FlagWithTxs),
|
||||
filepath.Join(config.RootDir, "config", "gentx"),
|
||||
viper.GetBool(server.FlagOverwrite),
|
||||
|
||||
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)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig)
|
||||
if err != nil {
|
||||
return err
|
||||
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,
|
||||
}
|
||||
appMessage, err := initWithConfig(cdc, config, initCfg)
|
||||
// print out some key information
|
||||
toPrint := struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"node_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}{
|
||||
chainID,
|
||||
nodeID,
|
||||
appMessage,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
|
||||
toPrint.AppMessage = appMessage
|
||||
return displayInfo(cdc, toPrint)
|
||||
},
|
||||
}
|
||||
cmd.Flags().BoolP(server.FlagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(server.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().Bool(server.FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||
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))
|
||||
|
||||
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")
|
||||
return cmd
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, initConfig server.InitConfig) (
|
||||
chainID string, nodeID string, appMessage json.RawMessage, err error) {
|
||||
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
|
||||
func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error) {
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
nodeID = string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
if initConfig.ChainID == "" {
|
||||
initConfig.ChainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
chainID = initConfig.ChainID
|
||||
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||
return
|
||||
}
|
||||
|
||||
func initWithConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig) (
|
||||
appMessage json.RawMessage, err error) {
|
||||
genFile := config.GenesisFile()
|
||||
if !initConfig.Overwrite && common.FileExists(genFile) {
|
||||
if !initCfg.Overwrite && common.FileExists(genFile) {
|
||||
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
return
|
||||
}
|
||||
|
||||
// process genesis transactions, or otherwise create one for defaults
|
||||
var appGenTxs []json.RawMessage
|
||||
var validators []types.GenesisValidator
|
||||
// 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 initConfig.GenTxs {
|
||||
validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc)
|
||||
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
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
for i, stdTx := range appGenTxs {
|
||||
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
genTxs[i] = jsonRawTx
|
||||
}
|
||||
} else {
|
||||
genTxConfig := servercfg.GenTx{
|
||||
viper.GetString(server.FlagName),
|
||||
viper.GetString(server.FlagClientHome),
|
||||
viper.GetBool(server.FlagOWK),
|
||||
"127.0.0.1",
|
||||
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
|
||||
}
|
||||
|
||||
// Write updated config with moniker
|
||||
config.Moniker = genTxConfig.Name
|
||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig)
|
||||
appMessage = am
|
||||
if err != nil {
|
||||
return "", "", nil, err
|
||||
}
|
||||
validators = []types.GenesisValidator{validator}
|
||||
appGenTxs = []json.RawMessage{appGenTx}
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// append a genesis-piece
|
||||
func processGenTxs(genTxsDir string, cdc *codec.Codec) (
|
||||
validators []types.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
||||
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
genTxs := make(map[string]server.GenesisTx)
|
||||
var nodeIDs []string
|
||||
for _, fo := range fos {
|
||||
filename := path.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
||||
continue
|
||||
}
|
||||
|
||||
// get the genTx
|
||||
var bz []byte
|
||||
bz, err = ioutil.ReadFile(filename)
|
||||
config.Moniker = initCfg.Name
|
||||
ip, err = server.ExternalIP()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var genTx server.GenesisTx
|
||||
err = cdc.UnmarshalJSON(bz, &genTx)
|
||||
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
|
||||
}
|
||||
|
||||
genTxs[genTx.NodeID] = genTx
|
||||
nodeIDs = append(nodeIDs, genTx.NodeID)
|
||||
}
|
||||
|
||||
sort.Strings(nodeIDs)
|
||||
|
||||
for _, nodeID := range nodeIDs {
|
||||
genTx := genTxs[nodeID]
|
||||
|
||||
// combine some stuff
|
||||
validators = append(validators, genTx.Validator)
|
||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
||||
|
||||
// Add a persistent peer
|
||||
comma := ","
|
||||
if len(persistentPeers) == 0 {
|
||||
comma = ""
|
||||
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
|
||||
}
|
||||
persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP)
|
||||
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
|
||||
}
|
||||
|
||||
// read of create the private key file for this config
|
||||
func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
||||
// private validator
|
||||
privValFile := tmConfig.PrivValidatorFile()
|
||||
var privValidator *privval.FilePV
|
||||
if common.FileExists(privValFile) {
|
||||
privValidator = privval.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = privval.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
// writeGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||
// error is returned if building or writing the configuration to file fails.
|
||||
// nolint: unparam
|
||||
func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error {
|
||||
func WriteGenesisFile(genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := types.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
|
@ -319,3 +266,16 @@ func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators
|
|||
|
||||
return genDoc.SaveAs(genesisFile)
|
||||
}
|
||||
|
||||
// read of create the private key file for this config
|
||||
func ReadOrCreatePrivValidator(privValFile string) crypto.PubKey {
|
||||
// private validator
|
||||
var privValidator *privval.FilePV
|
||||
if common.FileExists(privValFile) {
|
||||
privValidator = privval.LoadFilePV(privValFile)
|
||||
} else {
|
||||
privValidator = privval.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
}
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
|
|
@ -2,47 +2,64 @@ package init
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||
"github.com/stretchr/testify/require"
|
||||
abciServer "github.com/tendermint/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
func TestInitCmd(t *testing.T) {
|
||||
defer server.SetupViper(t)()
|
||||
defer setupClientHome(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
cdc := app.MakeCodec()
|
||||
appInit := server.AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
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
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyState(t *testing.T) {
|
||||
defer server.SetupViper(t)()
|
||||
defer setupClientHome(t)()
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
cdc := app.MakeCodec()
|
||||
appInit := server.AppInit{
|
||||
AppGenTx: mock.AppGenTx,
|
||||
AppGenState: mock.AppGenStateEmpty,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
|
@ -80,15 +97,17 @@ func TestStartStandAlone(t *testing.T) {
|
|||
defer func() {
|
||||
os.RemoveAll(home)
|
||||
}()
|
||||
viper.Set(cli.HomeFlag, home)
|
||||
viper.Set(client.FlagName, "moniker")
|
||||
defer setupClientHome(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := server.NewContext(cfg, logger)
|
||||
cdc := codec.New()
|
||||
cdc := app.MakeCodec()
|
||||
appInit := server.AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
initCmd := InitCmd(ctx, cdc, appInit)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
|
@ -109,3 +128,19 @@ func TestStartStandAlone(t *testing.T) {
|
|||
svr.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
func TestInitNodeValidatorFiles(t *testing.T) {
|
||||
home, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
defer func() {
|
||||
os.RemoveAll(home)
|
||||
}()
|
||||
viper.Set(cli.HomeFlag, home)
|
||||
viper.Set(client.FlagName, "moniker")
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
nodeID, valPubKey, err := InitializeNodeValidatorFiles(cfg)
|
||||
require.Nil(t, err)
|
||||
require.NotEqual(t, "", nodeID)
|
||||
require.NotEqual(t, 0, len(valPubKey.Bytes()))
|
||||
}
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
package init
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
gc "github.com/cosmos/cosmos-sdk/server/config"
|
||||
|
||||
"os"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/spf13/viper"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
)
|
||||
|
||||
|
@ -46,8 +50,7 @@ Example:
|
|||
`,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
config := ctx.Config
|
||||
err := testnetWithConfig(config, cdc, appInit)
|
||||
return err
|
||||
return testnetWithConfig(config, cdc, appInit)
|
||||
},
|
||||
}
|
||||
cmd.Flags().Int(nValidators, 4,
|
||||
|
@ -70,6 +73,12 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
outDir := viper.GetString(outputDir)
|
||||
numValidators := viper.GetInt(nValidators)
|
||||
|
||||
// Generate genesis.json and config.toml
|
||||
chainID := "chain-" + cmn.RandStr(6)
|
||||
monikers := make([]string, numValidators)
|
||||
nodeIDs := make([]string, numValidators)
|
||||
valPubKeys := make([]crypto.PubKey, numValidators)
|
||||
|
||||
// Generate private key, node ID, initial transaction
|
||||
for i := 0; i < numValidators; i++ {
|
||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||
|
@ -92,60 +101,101 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
|||
return err
|
||||
}
|
||||
|
||||
monikers = append(monikers, nodeDirName)
|
||||
config.Moniker = nodeDirName
|
||||
ip, err := getIP(i)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
nodeIDs[i], valPubKeys[i], err = InitializeNodeValidatorFiles(config)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip)
|
||||
|
||||
genTxConfig := gc.GenTx{
|
||||
nodeDirName,
|
||||
clientDir,
|
||||
true,
|
||||
ip,
|
||||
buf := client.BufferStdin()
|
||||
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
|
||||
// STDIN or the given password is not empty but failed to meet minimum
|
||||
// length requirements.
|
||||
return err
|
||||
}
|
||||
if keyPass == "" {
|
||||
keyPass = app.DefaultKeyPass
|
||||
}
|
||||
|
||||
// Run `init gen-tx` and generate initial transactions
|
||||
cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig)
|
||||
addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
info := map[string]string{"secret": secret}
|
||||
cliPrint, err := json.Marshal(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save private key seed words
|
||||
name := fmt.Sprintf("%v.json", "key_seed")
|
||||
err = writeFile(name, clientDir, cliPrint)
|
||||
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
msg := stake.NewMsgCreateValidator(
|
||||
sdk.ValAddress(addr),
|
||||
valPubKeys[i],
|
||||
sdk.NewInt64Coin("steak", 100),
|
||||
stake.NewDescription(nodeDirName, "", "", ""),
|
||||
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||
)
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
|
||||
txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo)
|
||||
signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
|
||||
txBytes, err := cdc.MarshalJSON(signedTx)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
|
||||
// Gather gentxs folder
|
||||
name = fmt.Sprintf("%v.json", nodeDirName)
|
||||
err = writeFile(name, gentxsDir, genTxFile)
|
||||
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
|
||||
if err != nil {
|
||||
_ = os.RemoveAll(outDir)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Generate genesis.json and config.toml
|
||||
chainID := "chain-" + cmn.RandStr(6)
|
||||
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)
|
||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||
initConfig := server.InitConfig{
|
||||
chainID,
|
||||
true,
|
||||
gentxsDir,
|
||||
true,
|
||||
}
|
||||
moniker := monikers[i]
|
||||
config.Moniker = nodeDirName
|
||||
config.SetRoot(nodeDir)
|
||||
|
||||
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||
// Run `init` and generate genesis.json and config.toml
|
||||
_, _, _, err := initWithConfig(cdc, appInit, config, initConfig)
|
||||
if err != nil {
|
||||
initCfg := initConfig{
|
||||
ChainID: chainID,
|
||||
GenTxsDir: gentxsDir,
|
||||
Name: moniker,
|
||||
WithTxs: true,
|
||||
Overwrite: true,
|
||||
OverwriteKey: false,
|
||||
NodeID: nodeID,
|
||||
ValPubKey: valPubKey,
|
||||
}
|
||||
if _, err := initWithConfig(cdc, config, initCfg); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ These instructions are for setting up a brand new full node from scratch.
|
|||
First, initialize the node and create the necessary config files:
|
||||
|
||||
```bash
|
||||
gaiad init --name <your_custom_name>
|
||||
gaiad init --skip-genesis --name <your_custom_name>
|
||||
```
|
||||
|
||||
::: warning Note
|
||||
|
|
|
@ -2,6 +2,7 @@ package app
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
|
@ -21,6 +22,12 @@ const (
|
|||
appName = "BasecoinApp"
|
||||
)
|
||||
|
||||
// default home directories for expected binaries
|
||||
var (
|
||||
DefaultCLIHome = os.ExpandEnv("$HOME/.basecli")
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.basecoind")
|
||||
)
|
||||
|
||||
// BasecoinApp implements an extended ABCI application. It contains a BaseApp,
|
||||
// a codec for serialization, KVStore keys for multistore state management, and
|
||||
// various mappers and keepers to manage getting, setting, and serializing the
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
@ -13,10 +14,11 @@ import (
|
|||
|
||||
var (
|
||||
basecoindHome = ""
|
||||
basecliHome = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
basecoindHome = getTestingHomeDir()
|
||||
basecoindHome, basecliHome = getTestingHomeDirs()
|
||||
}
|
||||
|
||||
func TestInitStartSequence(t *testing.T) {
|
||||
|
@ -32,8 +34,8 @@ func executeInit(t *testing.T) {
|
|||
chainID string
|
||||
initRes map[string]json.RawMessage
|
||||
)
|
||||
out := tests.ExecuteT(t, fmt.Sprintf("basecoind --home=%s init", basecoindHome), "")
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
_, stderr := tests.ExecuteT(t, fmt.Sprintf("basecoind --home=%s --home-client=%s init --name=test", basecoindHome, basecliHome), app.DefaultKeyPass)
|
||||
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||
require.NoError(t, err)
|
||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||
require.NoError(t, err)
|
||||
|
@ -45,8 +47,9 @@ func executeStart(t *testing.T, servAddr, port string) {
|
|||
tests.WaitForTMStart(port)
|
||||
}
|
||||
|
||||
func getTestingHomeDir() string {
|
||||
func getTestingHomeDirs() (string, string) {
|
||||
tmpDir := os.TempDir()
|
||||
basecoindHome := fmt.Sprintf("%s%s.test_basecoind", tmpDir, string(os.PathSeparator))
|
||||
return basecoindHome
|
||||
basecliHome := fmt.Sprintf("%s%s.test_basecli", tmpDir, string(os.PathSeparator))
|
||||
return basecoindHome, basecliHome
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
|
@ -86,7 +84,7 @@ func main() {
|
|||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli"))
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
|
||||
err := executor.Execute()
|
||||
if err != nil {
|
||||
// Note: Handle with #870
|
||||
|
|
|
@ -2,23 +2,32 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
const (
|
||||
flagClientHome = "home-client"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
ctx := server.NewDefaultContext()
|
||||
|
@ -30,7 +39,7 @@ func main() {
|
|||
}
|
||||
|
||||
appInit := server.DefaultAppInit
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(InitCmd(ctx, cdc, appInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||
|
@ -47,6 +56,69 @@ func main() {
|
|||
}
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
// nolint: errcheck
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
if chainID == "" {
|
||||
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
|
||||
pk := gaiaInit.ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||
genTx, appMessage, validator, err := server.SimpleAppGenTx(cdc, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint := struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"noide_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}{
|
||||
chainID,
|
||||
nodeID,
|
||||
appMessage,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
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.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Application {
|
||||
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package app
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tendermint/libs/common"
|
||||
|
@ -27,6 +28,12 @@ const (
|
|||
appName = "DemocoinApp"
|
||||
)
|
||||
|
||||
// default home directories for expected binaries
|
||||
var (
|
||||
DefaultCLIHome = os.ExpandEnv("$HOME/.democli")
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.democoind")
|
||||
)
|
||||
|
||||
// Extended ABCI application
|
||||
type DemocoinApp struct {
|
||||
*bam.BaseApp
|
||||
|
|
|
@ -3,6 +3,7 @@ package clitest
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
|
@ -13,10 +14,11 @@ import (
|
|||
|
||||
var (
|
||||
democoindHome = ""
|
||||
democliHome = ""
|
||||
)
|
||||
|
||||
func init() {
|
||||
democoindHome = getTestingHomeDir()
|
||||
democoindHome, democliHome = getTestingHomeDirs()
|
||||
}
|
||||
|
||||
func TestInitStartSequence(t *testing.T) {
|
||||
|
@ -32,8 +34,8 @@ func executeInit(t *testing.T) {
|
|||
chainID string
|
||||
initRes map[string]json.RawMessage
|
||||
)
|
||||
out := tests.ExecuteT(t, fmt.Sprintf("democoind --home=%s init", democoindHome), "")
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
_, stderr := tests.ExecuteT(t, fmt.Sprintf("democoind --home=%s --home-client=%s init --name=test", democoindHome, democliHome), app.DefaultKeyPass)
|
||||
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||
require.NoError(t, err)
|
||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||
require.NoError(t, err)
|
||||
|
@ -45,8 +47,9 @@ func executeStart(t *testing.T, servAddr, port string) {
|
|||
tests.WaitForTMStart(port)
|
||||
}
|
||||
|
||||
func getTestingHomeDir() string {
|
||||
func getTestingHomeDirs() (string, string) {
|
||||
tmpDir := os.TempDir()
|
||||
democoindHome := fmt.Sprintf("%s%s.test_democoind", tmpDir, string(os.PathSeparator))
|
||||
return democoindHome
|
||||
democliHome := fmt.Sprintf("%s%s.test_democli", tmpDir, string(os.PathSeparator))
|
||||
return democoindHome, democliHome
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
|
@ -91,7 +89,7 @@ func main() {
|
|||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.democli"))
|
||||
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
|
||||
err := executor.Execute()
|
||||
if err != nil {
|
||||
// handle with #870
|
||||
|
|
|
@ -2,6 +2,11 @@ package main
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
"io"
|
||||
"os"
|
||||
|
||||
|
@ -19,10 +24,13 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/server"
|
||||
)
|
||||
|
||||
const (
|
||||
flagClientHome = "home-client"
|
||||
)
|
||||
|
||||
// init parameters
|
||||
var CoolAppInit = server.AppInit{
|
||||
AppGenState: CoolAppGenState,
|
||||
AppGenTx: server.SimpleAppGenTx,
|
||||
}
|
||||
|
||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||
|
@ -52,6 +60,69 @@ func CoolAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState js
|
|||
return
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
// nolint: errcheck
|
||||
func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||
chainID := viper.GetString(client.FlagChainID)
|
||||
if chainID == "" {
|
||||
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
||||
}
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
|
||||
pk := gaiaInit.ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||
genTx, appMessage, validator, err := server.SimpleAppGenTx(cdc, pk)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, []json.RawMessage{genTx})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
toPrint := struct {
|
||||
ChainID string `json:"chain_id"`
|
||||
NodeID string `json:"noide_id"`
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
}{
|
||||
chainID,
|
||||
nodeID,
|
||||
appMessage,
|
||||
}
|
||||
out, err := codec.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||
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.FlagName, "", "validator's moniker")
|
||||
cmd.MarkFlagRequired(client.FlagName)
|
||||
return cmd
|
||||
}
|
||||
|
||||
func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
|
||||
return app.NewDemocoinApp(logger, db)
|
||||
}
|
||||
|
@ -71,7 +142,7 @@ func main() {
|
|||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
|
||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, CoolAppInit))
|
||||
rootCmd.AddCommand(InitCmd(ctx, cdc, CoolAppInit))
|
||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit))
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||
|
|
|
@ -35,16 +35,3 @@ func (c *Config) MinimumFees() sdk.Coins {
|
|||
|
||||
// DefaultConfig returns server's default configuration.
|
||||
func DefaultConfig() *Config { return &Config{BaseConfig{MinFees: defaultMinimumFees}} }
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// Configuration structure for command functions that share configuration.
|
||||
// For example: init, init gen-tx and testnet commands need similar input and run the same code
|
||||
|
||||
// Storage for init gen-tx command input parameters
|
||||
type GenTx struct {
|
||||
Name string
|
||||
CliRoot string
|
||||
Overwrite bool
|
||||
IP string
|
||||
}
|
||||
|
|
|
@ -2,111 +2,59 @@ package server
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
"github.com/tendermint/tendermint/types"
|
||||
|
||||
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
//Parameter names, for init gen-tx command
|
||||
var (
|
||||
FlagName = "name"
|
||||
FlagClientHome = "home-client"
|
||||
FlagOWK = "owk"
|
||||
)
|
||||
|
||||
//parameter names, init command
|
||||
var (
|
||||
FlagOverwrite = "overwrite"
|
||||
FlagWithTxs = "with-txs"
|
||||
FlagIP = "ip"
|
||||
FlagChainID = "chain-id"
|
||||
)
|
||||
|
||||
// genesis piece structure for creating combined genesis
|
||||
type GenesisTx struct {
|
||||
NodeID string `json:"node_id"`
|
||||
IP string `json:"ip"`
|
||||
Validator tmtypes.GenesisValidator `json:"validator"`
|
||||
AppGenTx json.RawMessage `json:"app_gen_tx"`
|
||||
}
|
||||
|
||||
// Storage for init command input parameters
|
||||
type InitConfig struct {
|
||||
ChainID string
|
||||
GenTxs bool
|
||||
GenTxsDir string
|
||||
Overwrite bool
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// Core functionality passed from the application to the server init command
|
||||
type AppInit struct {
|
||||
|
||||
// flags required for application init functions
|
||||
FlagsAppGenState *pflag.FlagSet
|
||||
FlagsAppGenTx *pflag.FlagSet
|
||||
|
||||
// create the application genesis tx
|
||||
AppGenTx func(cdc *codec.Codec, pk crypto.PubKey, genTxConfig serverconfig.GenTx) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error)
|
||||
|
||||
// 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, appGenTxs []json.RawMessage) (appState json.RawMessage, err error)
|
||||
AppGenState func(cdc *codec.Codec, appGenTx []json.RawMessage) (appState json.RawMessage, err error)
|
||||
}
|
||||
|
||||
// SimpleGenTx is a simple genesis tx
|
||||
type SimpleGenTx struct {
|
||||
Addr sdk.AccAddress `json:"addr"`
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// simple default application init
|
||||
var DefaultAppInit = AppInit{
|
||||
AppGenTx: SimpleAppGenTx,
|
||||
AppGenState: SimpleAppGenState,
|
||||
}
|
||||
|
||||
// simple genesis tx
|
||||
type SimpleGenTx struct {
|
||||
Addr sdk.AccAddress `json:"addr"`
|
||||
}
|
||||
|
||||
// Generate a genesis transaction
|
||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey, genTxConfig serverconfig.GenTx) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.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()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var bz []byte
|
||||
simpleGenTx := SimpleGenTx{addr}
|
||||
simpleGenTx := SimpleGenTx{Addr: 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,
|
||||
|
@ -122,8 +70,8 @@ func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState
|
|||
return
|
||||
}
|
||||
|
||||
var genTx SimpleGenTx
|
||||
err = cdc.UnmarshalJSON(appGenTxs[0], &genTx)
|
||||
var tx SimpleGenTx
|
||||
err = cdc.UnmarshalJSON(appGenTxs[0], &tx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
@ -138,7 +86,7 @@ func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState
|
|||
}
|
||||
]
|
||||
}]
|
||||
}`, genTx.Addr))
|
||||
}`, tx.Addr))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -176,7 +124,8 @@ func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (s
|
|||
if !overwrite {
|
||||
_, err := keybase.Get(keyName)
|
||||
if err == nil {
|
||||
return sdk.AccAddress([]byte{}), "", errors.New("key already exists, overwrite is disabled")
|
||||
return sdk.AccAddress([]byte{}), "", fmt.Errorf(
|
||||
"key already exists, overwrite is disabled (clientRoot: %s)", clientRoot)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,14 +6,11 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
dbm "github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
gc "github.com/cosmos/cosmos-sdk/server/config"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -126,14 +123,3 @@ func AppGenStateEmpty(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMes
|
|||
appState = json.RawMessage(``)
|
||||
return
|
||||
}
|
||||
|
||||
// Return a validator, not much else
|
||||
func AppGenTx(_ *codec.Codec, pk crypto.PubKey, genTxConfig gc.GenTx) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
Power: 10,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package server
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"os"
|
||||
|
@ -42,6 +43,7 @@ func SetupViper(t *testing.T) func() {
|
|||
rootDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||
require.Nil(t, err)
|
||||
viper.Set(cli.HomeFlag, rootDir)
|
||||
viper.Set(client.FlagName, "moniker")
|
||||
return func() {
|
||||
err := os.RemoveAll(rootDir)
|
||||
if err != nil {
|
||||
|
|
|
@ -14,7 +14,7 @@ import (
|
|||
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
||||
// logging STDOUT/STDERR to t.
|
||||
// nolint: errcheck
|
||||
func ExecuteT(t *testing.T, cmd, input string) (out string) {
|
||||
func ExecuteT(t *testing.T, cmd, input string) (stdout, stderr string) {
|
||||
t.Log("Running", cmn.Cyan(cmd))
|
||||
|
||||
// split cmd to name and args
|
||||
|
@ -50,8 +50,10 @@ func ExecuteT(t *testing.T, cmd, input string) (out string) {
|
|||
t.Log("Stderr:", cmn.Red(string(errbz)))
|
||||
}
|
||||
|
||||
out = strings.Trim(string(outbz), "\n")
|
||||
return out
|
||||
stdout = strings.Trim(string(outbz), "\n")
|
||||
stderr = strings.Trim(string(errbz), "\n")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Execute the command, launch goroutines to log stdout/err to t.
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/tendermint/tendermint/crypto"
|
||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||
|
@ -81,7 +80,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
|||
if !res.IsOK() {
|
||||
return newCtx, res, true
|
||||
}
|
||||
res = validateAccNumAndSequence(signerAccs, stdSigs)
|
||||
res = validateAccNumAndSequence(ctx, signerAccs, stdSigs)
|
||||
if !res.IsOK() {
|
||||
return newCtx, res, true
|
||||
}
|
||||
|
@ -149,17 +148,23 @@ func getSignerAccs(ctx sdk.Context, am AccountMapper, addrs []sdk.AccAddress) (a
|
|||
return
|
||||
}
|
||||
|
||||
func validateAccNumAndSequence(accs []Account, sigs []StdSignature) sdk.Result {
|
||||
func validateAccNumAndSequence(ctx sdk.Context, accs []Account, sigs []StdSignature) sdk.Result {
|
||||
for i := 0; i < len(accs); i++ {
|
||||
accnum := accs[i].GetAccountNumber()
|
||||
seq := accs[i].GetSequence()
|
||||
// On InitChain, make sure account number == 0
|
||||
if ctx.BlockHeight() == 0 && sigs[i].AccountNumber != 0 {
|
||||
return sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("Invalid account number for BlockHeight == 0. Got %d, expected 0", sigs[i].AccountNumber)).Result()
|
||||
}
|
||||
|
||||
// Check account number.
|
||||
if accnum != sigs[i].AccountNumber {
|
||||
accnum := accs[i].GetAccountNumber()
|
||||
if ctx.BlockHeight() != 0 && accnum != sigs[i].AccountNumber {
|
||||
return sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("Invalid account number. Got %d, expected %d", sigs[i].AccountNumber, accnum)).Result()
|
||||
}
|
||||
|
||||
// Check sequence number.
|
||||
seq := accs[i].GetSequence()
|
||||
if seq != sigs[i].Sequence {
|
||||
return sdk.ErrInvalidSequence(
|
||||
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sigs[i].Sequence, seq)).Result()
|
||||
|
@ -287,7 +292,7 @@ func ensureSufficientMempoolFees(ctx sdk.Context, stdTx StdTx) sdk.Result {
|
|||
|
||||
func setGasMeter(simulate bool, ctx sdk.Context, stdTx StdTx) sdk.Context {
|
||||
// set the gas meter
|
||||
if simulate {
|
||||
if simulate || ctx.BlockHeight() == 0 {
|
||||
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||
}
|
||||
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
||||
|
|
|
@ -169,6 +169,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
@ -218,6 +219,66 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
|||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
||||
// Test logic around account number checking with many signers when BlockHeight is 0.
|
||||
func TestAnteHandlerAccountNumbersAtBlockHeightZero(t *testing.T) {
|
||||
// setup
|
||||
ms, capKey, capKey2 := setupMultiStore()
|
||||
cdc := codec.New()
|
||||
RegisterBaseAccount(cdc)
|
||||
mapper := NewAccountMapper(cdc, capKey, ProtoBaseAccount)
|
||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(0)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
priv2, addr2 := privAndAddr()
|
||||
|
||||
// set the accounts
|
||||
acc1 := mapper.NewAccountWithAddress(ctx, addr1)
|
||||
acc1.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc1)
|
||||
acc2 := mapper.NewAccountWithAddress(ctx, addr2)
|
||||
acc2.SetCoins(newCoins())
|
||||
mapper.SetAccount(ctx, acc2)
|
||||
|
||||
// msg and signatures
|
||||
var tx sdk.Tx
|
||||
msg := newTestMsg(addr1)
|
||||
fee := newStdFee()
|
||||
|
||||
msgs := []sdk.Msg{msg}
|
||||
|
||||
// test good tx from one signer
|
||||
privs, accnums, seqs := []crypto.PrivKey{priv1}, []int64{0}, []int64{0}
|
||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx from wrong account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{1}, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// from correct account number
|
||||
seqs = []int64{1}
|
||||
tx = newTestTx(ctx, msgs, privs, []int64{0}, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
|
||||
// new tx with another signer and incorrect account numbers
|
||||
msg1 := newTestMsg(addr1, addr2)
|
||||
msg2 := newTestMsg(addr2, addr1)
|
||||
msgs = []sdk.Msg{msg1, msg2}
|
||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{1, 0}, []int64{2, 0}
|
||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||
checkInvalidTx(t, anteHandler, ctx, tx, false, sdk.CodeInvalidSequence)
|
||||
|
||||
// correct account numbers
|
||||
privs, accnums, seqs = []crypto.PrivKey{priv1, priv2}, []int64{0, 0}, []int64{2, 0}
|
||||
tx = newTestTx(ctx, msgs, privs, accnums, seqs, fee)
|
||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
||||
}
|
||||
|
||||
// Test logic around sequence checking with one signer and many signers.
|
||||
func TestAnteHandlerSequences(t *testing.T) {
|
||||
// setup
|
||||
|
@ -228,6 +289,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
@ -348,6 +410,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
@ -391,6 +454,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
@ -442,6 +506,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
@ -523,6 +588,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
|||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||
ctx = ctx.WithBlockHeight(1)
|
||||
|
||||
// keys and addresses
|
||||
priv1, addr1 := privAndAddr()
|
||||
|
|
|
@ -19,6 +19,7 @@ import (
|
|||
const (
|
||||
flagAppend = "append"
|
||||
flagPrintSigs = "print-sigs"
|
||||
flagOffline = "offline"
|
||||
)
|
||||
|
||||
// GetSignCommand returns the sign command
|
||||
|
@ -27,13 +28,18 @@ func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Comm
|
|||
Use: "sign <file>",
|
||||
Short: "Sign transactions generated offline",
|
||||
Long: `Sign transactions created with the --generate-only flag.
|
||||
Read a transaction from <file>, sign it, and print its JSON encoding.`,
|
||||
Read a transaction from <file>, sign it, and print its JSON encoding.
|
||||
|
||||
The --offline flag makes sure that the client will not reach out to the local cache.
|
||||
Thus account number or sequence number lookups will not be performed and it is
|
||||
recommended to set such parameters manually.`,
|
||||
RunE: makeSignCmd(codec, decoder),
|
||||
Args: cobra.ExactArgs(1),
|
||||
}
|
||||
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
||||
cmd.Flags().Bool(flagAppend, true, "Append the signature to the existing ones. If disabled, old signatures would be overwritten")
|
||||
cmd.Flags().Bool(flagPrintSigs, false, "Print the addresses that must sign the transaction and those who have already signed it, then exit")
|
||||
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
@ -53,7 +59,7 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
|||
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
||||
txBldr := authtxb.NewTxBuilderFromCLI()
|
||||
|
||||
newTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, viper.GetBool(flagAppend))
|
||||
newTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, viper.GetBool(flagAppend), viper.GetBool(flagOffline))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -210,7 +210,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
|||
testCases := []appTestCase{
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg3},
|
||||
accNums: []int64{0, 2},
|
||||
accNums: []int64{0, 0},
|
||||
accSeqs: []int64{0, 0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
|
@ -258,7 +258,7 @@ func TestMsgSendDependent(t *testing.T) {
|
|||
},
|
||||
{
|
||||
msgs: []sdk.Msg{sendMsg4},
|
||||
accNums: []int64{1},
|
||||
accNums: []int64{0},
|
||||
accSeqs: []int64{0},
|
||||
expSimPass: true,
|
||||
expPass: true,
|
||||
|
|
|
@ -14,9 +14,9 @@ func (k Keeper) onValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
|||
vdi := types.ValidatorDistInfo{
|
||||
OperatorAddr: addr,
|
||||
FeePoolWithdrawalHeight: height,
|
||||
Pool: types.DecCoins{},
|
||||
PoolCommission: types.DecCoins{},
|
||||
DelAccum: types.NewTotalAccum(height),
|
||||
Pool: types.DecCoins{},
|
||||
PoolCommission: types.DecCoins{},
|
||||
DelAccum: types.NewTotalAccum(height),
|
||||
}
|
||||
k.SetValidatorDistInfo(ctx, vdi)
|
||||
}
|
||||
|
|
|
@ -82,7 +82,7 @@ func SimulateFromSeed(tb testing.TB, app *baseapp.BaseApp,
|
|||
// Initially this is the same as the initial validator set
|
||||
nextValidators := validators
|
||||
|
||||
header := abci.Header{Height: 0, Time: timestamp, ProposerAddress: randomProposer(r, validators)}
|
||||
header := abci.Header{Height: 1, Time: timestamp, ProposerAddress: randomProposer(r, validators)}
|
||||
opCount := 0
|
||||
|
||||
// Setup code to catch SIGTERM's
|
||||
|
@ -384,7 +384,7 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
|
|||
time := header.Time
|
||||
vals := voteInfos
|
||||
if r.Float64() < pastEvidenceFraction {
|
||||
height = int64(r.Intn(int(header.Height)))
|
||||
height = int64(r.Intn(int(header.Height) - 1))
|
||||
time = pastTimes[height]
|
||||
vals = pastVoteInfos[height]
|
||||
}
|
||||
|
|
|
@ -137,7 +137,7 @@ func TestStakeMsgs(t *testing.T) {
|
|||
addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, commissionMsg,
|
||||
)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 1}, []int64{1, 0}, true, true, priv1, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{createValidatorMsgOnBehalfOf}, []int64{0, 0}, []int64{1, 0}, true, true, priv1, priv2)
|
||||
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)})
|
||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||
|
||||
|
@ -161,13 +161,13 @@ func TestStakeMsgs(t *testing.T) {
|
|||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
|
||||
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{1}, []int64{1}, true, true, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{delegateMsg}, []int64{0}, []int64{1}, true, true, priv2)
|
||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10))
|
||||
|
||||
// begin unbonding
|
||||
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10))
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{1}, []int64{2}, true, true, priv2)
|
||||
mock.SignCheckDeliver(t, mApp.BaseApp, []sdk.Msg{beginUnbondingMsg}, []int64{0}, []int64{2}, true, true, priv2)
|
||||
|
||||
// delegation should exist anymore
|
||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
|
||||
|
|
|
@ -25,6 +25,12 @@ const (
|
|||
FlagCommissionRate = "commission-rate"
|
||||
FlagCommissionMaxRate = "commission-max-rate"
|
||||
FlagCommissionMaxChangeRate = "commission-max-change-rate"
|
||||
|
||||
FlagGenesisFormat = "genesis-format"
|
||||
FlagNodeID = "node-id"
|
||||
FlagIP = "ip"
|
||||
|
||||
FlagOutputDocument = "output-document" // inspired by wget -O
|
||||
)
|
||||
|
||||
// common flagsets to add to various functions
|
||||
|
|
|
@ -2,7 +2,6 @@ package cli
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
|
@ -87,7 +86,15 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
|
|||
)
|
||||
}
|
||||
|
||||
if cliCtx.GenerateOnly {
|
||||
if viper.GetBool(FlagGenesisFormat) {
|
||||
ip := viper.GetString(FlagIP)
|
||||
nodeID := viper.GetString(FlagNodeID)
|
||||
if nodeID != "" && ip != "" {
|
||||
txBldr = txBldr.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip))
|
||||
}
|
||||
}
|
||||
|
||||
if viper.GetBool(FlagGenesisFormat) || cliCtx.GenerateOnly {
|
||||
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true)
|
||||
}
|
||||
|
||||
|
@ -101,6 +108,10 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
|
|||
cmd.Flags().AddFlagSet(fsDescriptionCreate)
|
||||
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))
|
||||
cmd.Flags().String(FlagNodeID, "", "Node's ID")
|
||||
cmd.MarkFlagRequired(client.FlagFrom)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue