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"
|
version = "v0.11.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:a69eebd15b05045ffdb10a984e001fadc5666f74383de3d2a9ee5862ee99cfdc"
|
digest = "1:f9c7a1f3ee087476f4883c33cc7c1bdbe56b9670b2fb27855ea2f386393272f5"
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
packages = [
|
packages = [
|
||||||
"abci/client",
|
"abci/client",
|
||||||
|
@ -518,8 +518,8 @@
|
||||||
"version",
|
"version",
|
||||||
]
|
]
|
||||||
pruneopts = "UT"
|
pruneopts = "UT"
|
||||||
revision = "0c9c3292c918617624f6f3fbcd95eceade18bcd5"
|
revision = "90eda9bfb6e6daeed1c8015df41cb36772d91778"
|
||||||
version = "v0.25.0"
|
version = "v0.25.1-rc0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
digest = "1:7886f86064faff6f8d08a3eb0e8c773648ff5a2e27730831e2bfbf07467f6666"
|
||||||
|
|
|
@ -57,11 +57,11 @@
|
||||||
|
|
||||||
[[override]]
|
[[override]]
|
||||||
name = "github.com/tendermint/tendermint"
|
name = "github.com/tendermint/tendermint"
|
||||||
version = "=0.25.0"
|
version = "=0.25.1-rc0"
|
||||||
|
|
||||||
## deps without releases:
|
## deps without releases:
|
||||||
|
|
||||||
[[constraint]]
|
[[override]]
|
||||||
name = "golang.org/x/crypto"
|
name = "golang.org/x/crypto"
|
||||||
source = "https://github.com/tendermint/crypto"
|
source = "https://github.com/tendermint/crypto"
|
||||||
revision = "3764759f34a542a3aef74d6b02e35be7ab893bba"
|
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] [\#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] \#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] [\#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
|
* Gaia
|
||||||
* Make the transient store key use a distinct store key. [#2013](https://github.com/cosmos/cosmos-sdk/pull/2013)
|
* 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/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] \#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
|
* [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
|
* SDK
|
||||||
* [core] \#2219 Update to Tendermint 0.24.0
|
* [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
|
* [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
|
* [stake][cli] [\#1672](https://github.com/cosmos/cosmos-sdk/issues/1672) Introduced
|
||||||
new commission flags for validator commands `create-validator` and `edit-validator`.
|
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
|
* Gaia
|
||||||
* [cli] #2170 added ability to show the node's address via `gaiad tendermint show-address`
|
* [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))
|
require.Equal(t, 1, len(operAddrs))
|
||||||
|
|
||||||
validators := getValidators(t, port)
|
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)
|
// make sure all the validators were found (order unknown because sorted by operator addr)
|
||||||
foundVal := false
|
foundVal := false
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
"github.com/tendermint/tendermint/crypto/secp256k1"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
@ -14,7 +16,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"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"
|
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
|
@ -26,6 +28,7 @@ import (
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
||||||
|
txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
tmcfg "github.com/tendermint/tendermint/config"
|
tmcfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
@ -205,42 +208,43 @@ func InitializeTestLCD(
|
||||||
|
|
||||||
genesisFile := config.GenesisFile()
|
genesisFile := config.GenesisFile()
|
||||||
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
genDoc, err := tmtypes.GenesisDocFromFile(genesisFile)
|
||||||
require.NoError(t, err)
|
require.Nil(t, err)
|
||||||
|
genDoc.Validators = nil
|
||||||
// append initial (proposing) validator
|
genDoc.SaveAs(genesisFile)
|
||||||
genDoc.Validators[0] = tmtypes.GenesisValidator{
|
genTxs := []json.RawMessage{}
|
||||||
PubKey: privVal.GetPubKey(),
|
|
||||||
Power: 100, // create enough power to enable 2/3 voting power
|
|
||||||
Name: "validator-1",
|
|
||||||
}
|
|
||||||
|
|
||||||
// append any additional (non-proposing) validators
|
// append any additional (non-proposing) validators
|
||||||
for i := 1; i < nValidators; i++ {
|
for i := 0; i < nValidators; i++ {
|
||||||
genDoc.Validators = append(genDoc.Validators,
|
operPrivKey := secp256k1.GenPrivKey()
|
||||||
tmtypes.GenesisValidator{
|
operAddr := operPrivKey.PubKey().Address()
|
||||||
PubKey: ed25519.GenPrivKey().PubKey(),
|
pubKey := privVal.PubKey
|
||||||
Power: 1,
|
delegation := 100
|
||||||
Name: fmt.Sprintf("validator-%d", i+1),
|
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()),
|
||||||
)
|
)
|
||||||
}
|
stdSignMsg := txbuilder.StdSignMsg{
|
||||||
|
ChainID: genDoc.ChainID,
|
||||||
var appGenTxs []json.RawMessage
|
Msgs: []sdk.Msg{msg},
|
||||||
|
}
|
||||||
for _, gdValidator := range genDoc.Validators {
|
sig, err := operPrivKey.Sign(stdSignMsg.Bytes())
|
||||||
operAddr := ed25519.GenPrivKey().PubKey().Address()
|
require.Nil(t, err)
|
||||||
pk := gdValidator.PubKey
|
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
|
||||||
|
txBytes, err := cdc.MarshalJSON(tx)
|
||||||
valConsPubKeys = append(valConsPubKeys, pk)
|
require.Nil(t, err)
|
||||||
|
genTxs = append(genTxs, txBytes)
|
||||||
|
valConsPubKeys = append(valConsPubKeys, pubKey)
|
||||||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
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)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// add some tokens to init accounts
|
// 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
|
// 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.
|
// 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
|
var signedStdTx auth.StdTx
|
||||||
|
|
||||||
keybase, err := keys.GetKeyBase()
|
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
|
// Check whether the address is a signer
|
||||||
if !isTxSigner(sdk.AccAddress(addr), stdTx.GetSigners()) {
|
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)
|
accNum, err := cliCtx.GetAccountNumber(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return signedStdTx, err
|
return signedStdTx, err
|
||||||
|
@ -133,7 +134,7 @@ func SignStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, name string,
|
||||||
txBldr = txBldr.WithAccountNumber(accNum)
|
txBldr = txBldr.WithAccountNumber(accNum)
|
||||||
}
|
}
|
||||||
|
|
||||||
if txBldr.Sequence == 0 {
|
if !offline && txBldr.Sequence == 0 {
|
||||||
accSeq, err := cliCtx.GetAccountSequence(addr)
|
accSeq, err := cliCtx.GetAccountSequence(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return signedStdTx, err
|
return signedStdTx, err
|
||||||
|
|
|
@ -2,15 +2,7 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io"
|
"fmt"
|
||||||
"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"
|
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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/params"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"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 (
|
const (
|
||||||
appName = "GaiaApp"
|
appName = "GaiaApp"
|
||||||
|
// DefaultKeyPass contains the default key password for genesis transactions
|
||||||
|
DefaultKeyPass = "12345678"
|
||||||
)
|
)
|
||||||
|
|
||||||
// default home directories for expected binaries
|
// 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
|
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{
|
return abci.ResponseInitChain{
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,31 +4,27 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"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/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/cosmos/cosmos-sdk/server/config"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||||
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DefaultKeyPass contains the default key password for genesis transactions
|
|
||||||
const DefaultKeyPass = "12345678"
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// bonded tokens given to genesis validators/accounts
|
// bonded tokens given to genesis validators/accounts
|
||||||
freeFermionVal = int64(100)
|
freeFermionVal = int64(100)
|
||||||
freeFermionsAcc = sdk.NewInt(50)
|
freeFermionsAcc = sdk.NewInt(150)
|
||||||
)
|
)
|
||||||
|
|
||||||
// State to Unmarshal
|
// State to Unmarshal
|
||||||
|
@ -38,6 +34,7 @@ type GenesisState struct {
|
||||||
DistrData distr.GenesisState `json:"distr"`
|
DistrData distr.GenesisState `json:"distr"`
|
||||||
GovData gov.GenesisState `json:"gov"`
|
GovData gov.GenesisState `json:"gov"`
|
||||||
SlashingData slashing.GenesisState `json:"slashing"`
|
SlashingData slashing.GenesisState `json:"slashing"`
|
||||||
|
GenTxs []json.RawMessage `json:"gentxs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenesisAccount doesn't need pubkey or sequence
|
// 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
|
// get app init parameters for server init command
|
||||||
func GaiaAppInit() server.AppInit {
|
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{
|
return server.AppInit{
|
||||||
FlagsAppGenState: fsAppGenState,
|
AppGenState: GaiaAppGenStateJSON,
|
||||||
FlagsAppGenTx: fsAppGenTx,
|
|
||||||
AppGenTx: GaiaAppGenTx,
|
|
||||||
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
|
// Create the core parameters for genesis initialization for gaia
|
||||||
// note that the pubkey input is this machines pubkey
|
// note that the pubkey input is this machines pubkey
|
||||||
func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisState GenesisState, err error) {
|
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
|
// start with the default staking genesis state
|
||||||
stakeData := stake.DefaultGenesisState()
|
stakeData := stake.DefaultGenesisState()
|
||||||
|
|
||||||
slashingData := slashing.DefaultGenesisState()
|
slashingData := slashing.DefaultGenesisState()
|
||||||
|
|
||||||
// get genesis flag account information
|
// get genesis flag account information
|
||||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||||
for i, appGenTx := range appGenTxs {
|
|
||||||
|
|
||||||
var genTx GaiaGenTx
|
for i, genTx := range appGenTxs {
|
||||||
err = cdc.UnmarshalJSON(appGenTx, &genTx)
|
var tx auth.StdTx
|
||||||
|
err = cdc.UnmarshalJSON(genTx, &tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
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
|
// 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
|
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
|
// create the final app state
|
||||||
|
@ -201,41 +113,17 @@ func GaiaAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (genesisStat
|
||||||
DistrData: distr.DefaultGenesisState(),
|
DistrData: distr.DefaultGenesisState(),
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
SlashingData: slashingData,
|
SlashingData: slashingData,
|
||||||
|
GenTxs: appGenTxs,
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func addValidatorToStakeData(genTx GaiaGenTx, stakeData stake.GenesisState) stake.GenesisState {
|
func genesisAccountFromMsgCreateValidator(msg stake.MsgCreateValidator, amount sdk.Int) GenesisAccount {
|
||||||
desc := stake.NewDescription(genTx.Name, "", "", "")
|
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddr))
|
||||||
validator := stake.NewValidator(
|
accAuth.Coins = []sdk.Coin{
|
||||||
sdk.ValAddress(genTx.Address), sdk.MustGetConsPubKeyBech32(genTx.PubKey), desc,
|
{msg.Description.Moniker + "Token", sdk.NewInt(1000)},
|
||||||
)
|
{"steak", amount},
|
||||||
|
|
||||||
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},
|
|
||||||
}
|
}
|
||||||
return NewGenesisAccount(&accAuth)
|
return NewGenesisAccount(&accAuth)
|
||||||
}
|
}
|
||||||
|
@ -249,11 +137,11 @@ func GaiaValidateGenesisState(genesisState GenesisState) (err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = stake.ValidateGenesis(genesisState.StakeData)
|
// skip stakeData validation as genesis is created from txs
|
||||||
if err != nil {
|
if len(genesisState.GenTxs) > 0 {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
return
|
return stake.ValidateGenesis(genesisState.StakeData)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensures that there are no duplicate accounts in the genesis state,
|
// 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
|
// GaiaAppGenState but with JSON
|
||||||
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||||
|
|
||||||
// create the final app state
|
// create the final app state
|
||||||
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
genesisState, err := GaiaAppGenState(cdc, appGenTxs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -281,3 +168,75 @@ func GaiaAppGenStateJSON(cdc *codec.Codec, appGenTxs []json.RawMessage) (appStat
|
||||||
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
appState, err = codec.MarshalJSONIndent(cdc, genesisState)
|
||||||
return
|
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
|
emptyPubkey crypto.PubKey
|
||||||
)
|
)
|
||||||
|
|
||||||
func makeGenesisState(genTxs []GaiaGenTx) GenesisState {
|
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
|
||||||
// start with the default staking genesis state
|
// start with the default staking genesis state
|
||||||
stakeData := stake.DefaultGenesisState()
|
stakeData := stake.DefaultGenesisState()
|
||||||
|
genAccs := make([]GenesisAccount, len(genTxs))
|
||||||
|
|
||||||
// get genesis flag account information
|
|
||||||
genaccs := make([]GenesisAccount, len(genTxs))
|
|
||||||
for i, genTx := range genTxs {
|
for i, genTx := range genTxs {
|
||||||
genaccs[i] = genesisAccountFromGenTx(genTx)
|
msgs := genTx.GetMsgs()
|
||||||
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
require.Equal(t, 1, len(msgs))
|
||||||
|
msg := msgs[0].(stake.MsgCreateValidator)
|
||||||
|
|
||||||
// add the validator
|
// get genesis flag account information
|
||||||
if len(genTx.Name) > 0 {
|
genAccs[i] = genesisAccountFromMsgCreateValidator(msg, freeFermionsAcc)
|
||||||
stakeData = addValidatorToStakeData(genTx, stakeData)
|
stakeData.Pool.LooseTokens = stakeData.Pool.LooseTokens.Add(sdk.NewDecFromInt(freeFermionsAcc)) // increase the supply
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the final app state
|
// create the final app state
|
||||||
return GenesisState{
|
return GenesisState{
|
||||||
Accounts: genaccs,
|
Accounts: genAccs,
|
||||||
StakeData: stakeData,
|
StakeData: stakeData,
|
||||||
GovData: gov.DefaultGenesisState(),
|
GovData: gov.DefaultGenesisState(),
|
||||||
}
|
}
|
||||||
|
@ -75,17 +74,23 @@ func TestGaiaAppGenState(t *testing.T) {
|
||||||
// TODO correct: genesis account created, canididates created, pool token variance
|
// 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) {
|
func TestGaiaGenesisValidation(t *testing.T) {
|
||||||
genTxs := make([]GaiaGenTx, 2)
|
genTxs := make([]auth.StdTx, 2)
|
||||||
addr := pk1.Address()
|
|
||||||
// Test duplicate accounts fails
|
// Test duplicate accounts fails
|
||||||
genTxs[0] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
|
genTxs[0] = makeMsg("test-0", pk1)
|
||||||
genTxs[1] = GaiaGenTx{"", sdk.AccAddress(addr), ""}
|
genTxs[1] = makeMsg("test-1", pk1)
|
||||||
genesisState := makeGenesisState(genTxs)
|
genesisState := makeGenesisState(t, genTxs)
|
||||||
err := GaiaValidateGenesisState(genesisState)
|
err := GaiaValidateGenesisState(genesisState)
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
// Test bonded + jailed validator fails
|
// Test bonded + jailed validator fails
|
||||||
genesisState = makeGenesisState(genTxs[:1])
|
genesisState = makeGenesisState(t, genTxs)
|
||||||
val1 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #2"})
|
val1 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #2"})
|
||||||
val1.Jailed = true
|
val1.Jailed = true
|
||||||
val1.Status = sdk.Bonded
|
val1.Status = sdk.Bonded
|
||||||
|
@ -94,7 +99,7 @@ func TestGaiaGenesisValidation(t *testing.T) {
|
||||||
require.NotNil(t, err)
|
require.NotNil(t, err)
|
||||||
// Test duplicate validator fails
|
// Test duplicate validator fails
|
||||||
val1.Jailed = false
|
val1.Jailed = false
|
||||||
genesisState = makeGenesisState(genTxs[:1])
|
genesisState = makeGenesisState(t, genTxs)
|
||||||
val2 := stakeTypes.NewValidator(addr1, pk1, stakeTypes.Description{Moniker: "test #3"})
|
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, val1)
|
||||||
genesisState.StakeData.Validators = append(genesisState.StakeData.Validators, val2)
|
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))
|
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli query account %s %v", fooAddr, flags))
|
||||||
require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64())
|
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)
|
require.Equal(t, "No matching proposals found", proposalsQuery)
|
||||||
|
|
||||||
// submit a test proposal
|
// submit a test proposal
|
||||||
|
@ -346,7 +346,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
require.Equal(t, int64(1), proposal1.GetProposalID())
|
require.Equal(t, int64(1), proposal1.GetProposalID())
|
||||||
require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus())
|
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)
|
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||||
|
|
||||||
depositStr := fmt.Sprintf("gaiacli tx deposit %v", flags)
|
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, int64(1), votes[0].ProposalID)
|
||||||
require.Equal(t, gov.OptionYes, votes[0].Option)
|
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)
|
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)
|
require.Equal(t, " 1 - Test", proposalsQuery)
|
||||||
|
|
||||||
// submit a second test proposal
|
// submit a second test proposal
|
||||||
|
@ -417,7 +417,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) {
|
||||||
executeWrite(t, spStr, app.DefaultKeyPass)
|
executeWrite(t, spStr, app.DefaultKeyPass)
|
||||||
tests.WaitForNextNBlocksTM(2, port)
|
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)
|
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) {
|
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
|
var initRes map[string]json.RawMessage
|
||||||
err := json.Unmarshal([]byte(out), &initRes)
|
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
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) {
|
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
|
var ko keys.KeyOutput
|
||||||
keys.UnmarshalJSON([]byte(out), &ko)
|
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 {
|
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
|
var initRes map[string]json.RawMessage
|
||||||
err := json.Unmarshal([]byte(out), &initRes)
|
err := json.Unmarshal([]byte(out), &initRes)
|
||||||
require.NoError(t, err, "out %v, err %v", out, err)
|
require.NoError(t, err, "out %v, err %v", out, err)
|
||||||
|
@ -672,7 +672,7 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||||
// stake
|
// stake
|
||||||
|
|
||||||
func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
func executeGetValidator(t *testing.T, cmdStr string) stake.Validator {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var validator stake.Validator
|
var validator stake.Validator
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &validator)
|
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 {
|
func executeGetPool(t *testing.T, cmdStr string) stake.Pool {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var pool stake.Pool
|
var pool stake.Pool
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &pool)
|
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 {
|
func executeGetParams(t *testing.T, cmdStr string) stake.Params {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var params stake.Params
|
var params stake.Params
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), ¶ms)
|
err := cdc.UnmarshalJSON([]byte(out), ¶ms)
|
||||||
|
@ -702,7 +702,7 @@ func executeGetParams(t *testing.T, cmdStr string) stake.Params {
|
||||||
// gov
|
// gov
|
||||||
|
|
||||||
func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var proposal gov.Proposal
|
var proposal gov.Proposal
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &proposal)
|
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 {
|
func executeGetVote(t *testing.T, cmdStr string) gov.Vote {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var vote gov.Vote
|
var vote gov.Vote
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &vote)
|
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 {
|
func executeGetVotes(t *testing.T, cmdStr string) []gov.Vote {
|
||||||
out := tests.ExecuteT(t, cmdStr, "")
|
out, _ := tests.ExecuteT(t, cmdStr, "")
|
||||||
var votes []gov.Vote
|
var votes []gov.Vote
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
err := cdc.UnmarshalJSON([]byte(out), &votes)
|
err := cdc.UnmarshalJSON([]byte(out), &votes)
|
||||||
|
|
|
@ -32,6 +32,7 @@ func main() {
|
||||||
appInit := app.GaiaAppInit()
|
appInit := app.GaiaAppInit()
|
||||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
||||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||||
|
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
server.AddCommands(ctx, cdc, rootCmd, appInit,
|
||||||
newApp, exportAppStateAndTMValidators)
|
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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"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"
|
"os"
|
||||||
"path"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sort"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"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/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
"github.com/tendermint/tendermint/libs/common"
|
"github.com/tendermint/tendermint/libs/common"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
"github.com/tendermint/tendermint/privval"
|
|
||||||
"github.com/tendermint/tendermint/types"
|
"github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// get cmd to initialize all files for tendermint and application
|
const (
|
||||||
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
flagWithTxs = "with-txs"
|
||||||
cmd := &cobra.Command{
|
flagOverwrite = "overwrite"
|
||||||
Use: "gen-tx",
|
flagClientHome = "home-client"
|
||||||
Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)",
|
flagOverwriteKey = "overwrite-key"
|
||||||
Args: cobra.NoArgs,
|
flagSkipGenesis = "skip-genesis"
|
||||||
RunE: func(_ *cobra.Command, args []string) error {
|
flagMoniker = "moniker"
|
||||||
config := ctx.Config
|
)
|
||||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
|
||||||
|
|
||||||
ip := viper.GetString(server.FlagIP)
|
type initConfig struct {
|
||||||
if len(ip) == 0 {
|
ChainID string
|
||||||
eip, err := server.ExternalIP()
|
GenTxsDir string
|
||||||
if err != nil {
|
Name string
|
||||||
return err
|
NodeID string
|
||||||
}
|
ClientHome string
|
||||||
ip = eip
|
WithTxs bool
|
||||||
}
|
Overwrite bool
|
||||||
|
OverwriteKey bool
|
||||||
genTxConfig := servercfg.GenTx{
|
ValPubKey crypto.PubKey
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: This will update (write) the config file with
|
type printInfo struct {
|
||||||
// updated name (moniker) for node.
|
Moniker string `json:"moniker"`
|
||||||
func gentxWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, genTxConfig servercfg.GenTx) (
|
ChainID string `json:"chain_id"`
|
||||||
cliPrint json.RawMessage, genTxFile json.RawMessage, err error) {
|
NodeID string `json:"node_id"`
|
||||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
AppMessage json.RawMessage `json:"app_message"`
|
||||||
if err != nil {
|
}
|
||||||
return
|
|
||||||
}
|
|
||||||
nodeID := string(nodeKey.ID())
|
|
||||||
pubKey := readOrCreatePrivValidator(config)
|
|
||||||
|
|
||||||
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 {
|
if err != nil {
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
|
fmt.Fprintf(os.Stderr, "%s\n", string(out))
|
||||||
tx := server.GenesisTx{
|
return nil
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// get cmd to initialize all files for tendermint and application
|
// 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 {
|
func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command {
|
||||||
cmd := &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: "init",
|
Use: "init",
|
||||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
Short: "Initialize private validator, p2p, genesis, and application configuration files",
|
||||||
Args: cobra.NoArgs,
|
Long: `Initialize validators's and node's configuration files.
|
||||||
RunE: func(_ *cobra.Command, _ []string) error {
|
|
||||||
|
|
||||||
|
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 := ctx.Config
|
||||||
config.SetRoot(viper.GetString(cli.HomeFlag))
|
config.SetRoot(viper.GetString(cli.HomeFlag))
|
||||||
initConfig := server.InitConfig{
|
|
||||||
viper.GetString(server.FlagChainID),
|
name := viper.GetString(client.FlagName)
|
||||||
viper.GetBool(server.FlagWithTxs),
|
chainID := viper.GetString(client.FlagChainID)
|
||||||
filepath.Join(config.RootDir, "config", "gentx"),
|
if chainID == "" {
|
||||||
viper.GetBool(server.FlagOverwrite),
|
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 viper.GetString(flagMoniker) != "" {
|
||||||
if err != nil {
|
config.Moniker = viper.GetString(flagMoniker)
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
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
|
// 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 {
|
if err != nil {
|
||||||
return err
|
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().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
|
||||||
cmd.Flags().Bool(server.FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenState)
|
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided
|
cmd.Flags().Bool(flagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/")
|
||||||
cmd.AddCommand(GenTxCmd(ctx, cdc, appInit))
|
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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
func initWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, initConfig server.InitConfig) (
|
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
|
||||||
chainID string, nodeID string, appMessage json.RawMessage, err error) {
|
func InitializeNodeValidatorFiles(config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error) {
|
||||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nodeID = string(nodeKey.ID())
|
nodeID = string(nodeKey.ID())
|
||||||
pubKey := readOrCreatePrivValidator(config)
|
valPubKey = ReadOrCreatePrivValidator(config.PrivValidatorFile())
|
||||||
|
return
|
||||||
if initConfig.ChainID == "" {
|
}
|
||||||
initConfig.ChainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
|
|
||||||
}
|
|
||||||
chainID = initConfig.ChainID
|
|
||||||
|
|
||||||
|
func initWithConfig(cdc *codec.Codec, config *cfg.Config, initCfg initConfig) (
|
||||||
|
appMessage json.RawMessage, err error) {
|
||||||
genFile := config.GenesisFile()
|
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)
|
err = fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// process genesis transactions, or otherwise create one for defaults
|
// process genesis transactions, else create default genesis.json
|
||||||
var appGenTxs []json.RawMessage
|
var appGenTxs []auth.StdTx
|
||||||
var validators []types.GenesisValidator
|
|
||||||
var persistentPeers string
|
var persistentPeers string
|
||||||
|
var genTxs []json.RawMessage
|
||||||
|
var appState json.RawMessage
|
||||||
|
var jsonRawTx json.RawMessage
|
||||||
|
chainID := initCfg.ChainID
|
||||||
|
|
||||||
if initConfig.GenTxs {
|
if initCfg.WithTxs {
|
||||||
validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc)
|
_, appGenTxs, persistentPeers, err = app.CollectStdTxs(config.Moniker, initCfg.GenTxsDir, cdc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
genTxs = make([]json.RawMessage, len(appGenTxs))
|
||||||
config.P2P.PersistentPeers = persistentPeers
|
config.P2P.PersistentPeers = persistentPeers
|
||||||
configFilePath := filepath.Join(config.RootDir, "config", "config.toml")
|
for i, stdTx := range appGenTxs {
|
||||||
cfg.WriteConfigFile(configFilePath, config)
|
jsonRawTx, err = cdc.MarshalJSON(stdTx)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
genTxs[i] = jsonRawTx
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
genTxConfig := servercfg.GenTx{
|
var ip, keyPass, secret string
|
||||||
viper.GetString(server.FlagName),
|
var addr sdk.AccAddress
|
||||||
viper.GetString(server.FlagClientHome),
|
var signedTx auth.StdTx
|
||||||
viper.GetBool(server.FlagOWK),
|
|
||||||
"127.0.0.1",
|
if initCfg.Name == "" {
|
||||||
|
err = errors.New("must specify validator's moniker (--name)")
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write updated config with moniker
|
config.Moniker = initCfg.Name
|
||||||
config.Moniker = genTxConfig.Name
|
ip, err = server.ExternalIP()
|
||||||
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)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
var genTx server.GenesisTx
|
memo := fmt.Sprintf("%s@%s:26656", initCfg.NodeID, ip)
|
||||||
err = cdc.UnmarshalJSON(bz, &genTx)
|
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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
genTxs[genTx.NodeID] = genTx
|
msg := stake.NewMsgCreateValidator(
|
||||||
nodeIDs = append(nodeIDs, genTx.NodeID)
|
sdk.ValAddress(addr),
|
||||||
}
|
initCfg.ValPubKey,
|
||||||
|
sdk.NewInt64Coin("steak", 100),
|
||||||
sort.Strings(nodeIDs)
|
stake.NewDescription(config.Moniker, "", "", ""),
|
||||||
|
stake.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
|
||||||
for _, nodeID := range nodeIDs {
|
)
|
||||||
genTx := genTxs[nodeID]
|
txBldr := authtx.NewTxBuilderFromCLI().WithCodec(cdc).WithMemo(memo).WithChainID(chainID)
|
||||||
|
signedTx, err = txBldr.SignStdTx(
|
||||||
// combine some stuff
|
initCfg.Name, keyPass, auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo), false,
|
||||||
validators = append(validators, genTx.Validator)
|
)
|
||||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
if err != nil {
|
||||||
|
return
|
||||||
// Add a persistent peer
|
|
||||||
comma := ","
|
|
||||||
if len(persistentPeers) == 0 {
|
|
||||||
comma = ""
|
|
||||||
}
|
}
|
||||||
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// read of create the private key file for this config
|
// WriteGenesisFile creates and writes the genesis configuration to disk. An
|
||||||
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
|
|
||||||
// error is returned if building or writing the configuration to file fails.
|
// error is returned if building or writing the configuration to file fails.
|
||||||
// nolint: unparam
|
// 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{
|
genDoc := types.GenesisDoc{
|
||||||
ChainID: chainID,
|
ChainID: chainID,
|
||||||
Validators: validators,
|
Validators: validators,
|
||||||
|
@ -319,3 +266,16 @@ func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators
|
||||||
|
|
||||||
return genDoc.SaveAs(genesisFile)
|
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 (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/cosmos/cosmos-sdk/server/mock"
|
"github.com/cosmos/cosmos-sdk/server/mock"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
abciServer "github.com/tendermint/tendermint/abci/server"
|
abciServer "github.com/tendermint/tendermint/abci/server"
|
||||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
|
|
||||||
|
"github.com/spf13/viper"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitCmd(t *testing.T) {
|
func TestInitCmd(t *testing.T) {
|
||||||
defer server.SetupViper(t)()
|
defer server.SetupViper(t)()
|
||||||
|
defer setupClientHome(t)()
|
||||||
|
|
||||||
logger := log.NewNopLogger()
|
logger := log.NewNopLogger()
|
||||||
cfg, err := tcmd.ParseConfig()
|
cfg, err := tcmd.ParseConfig()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ctx := server.NewContext(cfg, logger)
|
ctx := server.NewContext(cfg, logger)
|
||||||
cdc := codec.New()
|
cdc := app.MakeCodec()
|
||||||
appInit := server.AppInit{
|
appInit := server.AppInit{
|
||||||
AppGenState: mock.AppGenState,
|
AppGenState: mock.AppGenState,
|
||||||
AppGenTx: mock.AppGenTx,
|
|
||||||
}
|
}
|
||||||
cmd := InitCmd(ctx, cdc, appInit)
|
cmd := InitCmd(ctx, cdc, appInit)
|
||||||
err = cmd.RunE(nil, nil)
|
err = cmd.RunE(nil, nil)
|
||||||
require.NoError(t, err)
|
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) {
|
func TestEmptyState(t *testing.T) {
|
||||||
defer server.SetupViper(t)()
|
defer server.SetupViper(t)()
|
||||||
|
defer setupClientHome(t)()
|
||||||
logger := log.NewNopLogger()
|
logger := log.NewNopLogger()
|
||||||
cfg, err := tcmd.ParseConfig()
|
cfg, err := tcmd.ParseConfig()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ctx := server.NewContext(cfg, logger)
|
ctx := server.NewContext(cfg, logger)
|
||||||
cdc := codec.New()
|
cdc := app.MakeCodec()
|
||||||
appInit := server.AppInit{
|
appInit := server.AppInit{
|
||||||
AppGenTx: mock.AppGenTx,
|
|
||||||
AppGenState: mock.AppGenStateEmpty,
|
AppGenState: mock.AppGenStateEmpty,
|
||||||
}
|
}
|
||||||
cmd := InitCmd(ctx, cdc, appInit)
|
cmd := InitCmd(ctx, cdc, appInit)
|
||||||
|
@ -80,15 +97,17 @@ func TestStartStandAlone(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
os.RemoveAll(home)
|
os.RemoveAll(home)
|
||||||
}()
|
}()
|
||||||
|
viper.Set(cli.HomeFlag, home)
|
||||||
|
viper.Set(client.FlagName, "moniker")
|
||||||
|
defer setupClientHome(t)()
|
||||||
|
|
||||||
logger := log.NewNopLogger()
|
logger := log.NewNopLogger()
|
||||||
cfg, err := tcmd.ParseConfig()
|
cfg, err := tcmd.ParseConfig()
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ctx := server.NewContext(cfg, logger)
|
ctx := server.NewContext(cfg, logger)
|
||||||
cdc := codec.New()
|
cdc := app.MakeCodec()
|
||||||
appInit := server.AppInit{
|
appInit := server.AppInit{
|
||||||
AppGenState: mock.AppGenState,
|
AppGenState: mock.AppGenState,
|
||||||
AppGenTx: mock.AppGenTx,
|
|
||||||
}
|
}
|
||||||
initCmd := InitCmd(ctx, cdc, appInit)
|
initCmd := InitCmd(ctx, cdc, appInit)
|
||||||
err = initCmd.RunE(nil, nil)
|
err = initCmd.RunE(nil, nil)
|
||||||
|
@ -109,3 +128,19 @@ func TestStartStandAlone(t *testing.T) {
|
||||||
svr.Stop()
|
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
|
package init
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"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"
|
"net"
|
||||||
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
gc "github.com/cosmos/cosmos-sdk/server/config"
|
|
||||||
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
cfg "github.com/tendermint/tendermint/config"
|
cfg "github.com/tendermint/tendermint/config"
|
||||||
|
"github.com/tendermint/tendermint/crypto"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -46,8 +50,7 @@ Example:
|
||||||
`,
|
`,
|
||||||
RunE: func(_ *cobra.Command, _ []string) error {
|
RunE: func(_ *cobra.Command, _ []string) error {
|
||||||
config := ctx.Config
|
config := ctx.Config
|
||||||
err := testnetWithConfig(config, cdc, appInit)
|
return testnetWithConfig(config, cdc, appInit)
|
||||||
return err
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
cmd.Flags().Int(nValidators, 4,
|
cmd.Flags().Int(nValidators, 4,
|
||||||
|
@ -70,6 +73,12 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppI
|
||||||
outDir := viper.GetString(outputDir)
|
outDir := viper.GetString(outputDir)
|
||||||
numValidators := viper.GetInt(nValidators)
|
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
|
// Generate private key, node ID, initial transaction
|
||||||
for i := 0; i < numValidators; i++ {
|
for i := 0; i < numValidators; i++ {
|
||||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), 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
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monikers = append(monikers, nodeDirName)
|
||||||
config.Moniker = nodeDirName
|
config.Moniker = nodeDirName
|
||||||
ip, err := getIP(i)
|
ip, err := getIP(i)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
_ = os.RemoveAll(outDir)
|
||||||
return err
|
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{
|
buf := client.BufferStdin()
|
||||||
nodeDirName,
|
prompt := fmt.Sprintf("Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass)
|
||||||
clientDir,
|
keyPass, err := client.GetPassword(prompt, buf)
|
||||||
true,
|
if err != nil && keyPass != "" {
|
||||||
ip,
|
// 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
|
addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true)
|
||||||
cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig)
|
if err != nil {
|
||||||
|
_ = os.RemoveAll(outDir)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
info := map[string]string{"secret": secret}
|
||||||
|
cliPrint, err := json.Marshal(info)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save private key seed words
|
// Save private key seed words
|
||||||
name := fmt.Sprintf("%v.json", "key_seed")
|
err = writeFile(fmt.Sprintf("%v.json", "key_seed"), clientDir, cliPrint)
|
||||||
err = writeFile(name, clientDir, cliPrint)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
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
|
// Gather gentxs folder
|
||||||
name = fmt.Sprintf("%v.json", nodeDirName)
|
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
|
||||||
err = writeFile(name, gentxsDir, genTxFile)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
_ = os.RemoveAll(outDir)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate genesis.json and config.toml
|
|
||||||
chainID := "chain-" + cmn.RandStr(6)
|
|
||||||
for i := 0; i < numValidators; i++ {
|
for i := 0; i < numValidators; i++ {
|
||||||
|
|
||||||
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(nodeDirPrefix), i)
|
||||||
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
nodeDaemonHomeName := viper.GetString(nodeDaemonHome)
|
||||||
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
|
||||||
gentxsDir := filepath.Join(outDir, "gentxs")
|
gentxsDir := filepath.Join(outDir, "gentxs")
|
||||||
initConfig := server.InitConfig{
|
moniker := monikers[i]
|
||||||
chainID,
|
|
||||||
true,
|
|
||||||
gentxsDir,
|
|
||||||
true,
|
|
||||||
}
|
|
||||||
config.Moniker = nodeDirName
|
config.Moniker = nodeDirName
|
||||||
config.SetRoot(nodeDir)
|
config.SetRoot(nodeDir)
|
||||||
|
|
||||||
|
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
|
||||||
// Run `init` and generate genesis.json and config.toml
|
// Run `init` and generate genesis.json and config.toml
|
||||||
_, _, _, err := initWithConfig(cdc, appInit, config, initConfig)
|
initCfg := initConfig{
|
||||||
if err != nil {
|
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
|
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:
|
First, initialize the node and create the necessary config files:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
gaiad init --name <your_custom_name>
|
gaiad init --skip-genesis --name <your_custom_name>
|
||||||
```
|
```
|
||||||
|
|
||||||
::: warning Note
|
::: warning Note
|
||||||
|
|
|
@ -2,6 +2,7 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
|
@ -21,6 +22,12 @@ const (
|
||||||
appName = "BasecoinApp"
|
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,
|
// BasecoinApp implements an extended ABCI application. It contains a BaseApp,
|
||||||
// a codec for serialization, KVStore keys for multistore state management, and
|
// a codec for serialization, KVStore keys for multistore state management, and
|
||||||
// various mappers and keepers to manage getting, setting, and serializing the
|
// various mappers and keepers to manage getting, setting, and serializing the
|
||||||
|
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/cosmos/cosmos-sdk/tests"
|
"github.com/cosmos/cosmos-sdk/tests"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
@ -13,10 +14,11 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
basecoindHome = ""
|
basecoindHome = ""
|
||||||
|
basecliHome = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
basecoindHome = getTestingHomeDir()
|
basecoindHome, basecliHome = getTestingHomeDirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitStartSequence(t *testing.T) {
|
func TestInitStartSequence(t *testing.T) {
|
||||||
|
@ -32,8 +34,8 @@ func executeInit(t *testing.T) {
|
||||||
chainID string
|
chainID string
|
||||||
initRes map[string]json.RawMessage
|
initRes map[string]json.RawMessage
|
||||||
)
|
)
|
||||||
out := tests.ExecuteT(t, fmt.Sprintf("basecoind --home=%s init", basecoindHome), "")
|
_, stderr := tests.ExecuteT(t, fmt.Sprintf("basecoind --home=%s --home-client=%s init --name=test", basecoindHome, basecliHome), app.DefaultKeyPass)
|
||||||
err := json.Unmarshal([]byte(out), &initRes)
|
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -45,8 +47,9 @@ func executeStart(t *testing.T, servAddr, port string) {
|
||||||
tests.WaitForTMStart(port)
|
tests.WaitForTMStart(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTestingHomeDir() string {
|
func getTestingHomeDirs() (string, string) {
|
||||||
tmpDir := os.TempDir()
|
tmpDir := os.TempDir()
|
||||||
basecoindHome := fmt.Sprintf("%s%s.test_basecoind", tmpDir, string(os.PathSeparator))
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||||
|
@ -86,7 +84,7 @@ func main() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.basecli"))
|
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
|
||||||
err := executor.Execute()
|
err := executor.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Note: Handle with #870
|
// Note: Handle with #870
|
||||||
|
|
|
@ -2,23 +2,32 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/tendermint/tendermint/p2p"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/baseapp"
|
"github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
|
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/examples/basecoin/app"
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/spf13/viper"
|
"github.com/spf13/viper"
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
"github.com/tendermint/tendermint/libs/common"
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
tmtypes "github.com/tendermint/tendermint/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagClientHome = "home-client"
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
cdc := app.MakeCodec()
|
cdc := app.MakeCodec()
|
||||||
ctx := server.NewDefaultContext()
|
ctx := server.NewDefaultContext()
|
||||||
|
@ -30,7 +39,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
appInit := server.DefaultAppInit
|
appInit := server.DefaultAppInit
|
||||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit))
|
rootCmd.AddCommand(InitCmd(ctx, cdc, appInit))
|
||||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit))
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, 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 {
|
func newApp(logger log.Logger, db dbm.DB, storeTracer io.Writer) abci.Application {
|
||||||
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
return app.NewBasecoinApp(logger, db, baseapp.SetPruning(viper.GetString("pruning")))
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package app
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"os"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
cmn "github.com/tendermint/tendermint/libs/common"
|
cmn "github.com/tendermint/tendermint/libs/common"
|
||||||
|
@ -27,6 +28,12 @@ const (
|
||||||
appName = "DemocoinApp"
|
appName = "DemocoinApp"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// default home directories for expected binaries
|
||||||
|
var (
|
||||||
|
DefaultCLIHome = os.ExpandEnv("$HOME/.democli")
|
||||||
|
DefaultNodeHome = os.ExpandEnv("$HOME/.democoind")
|
||||||
|
)
|
||||||
|
|
||||||
// Extended ABCI application
|
// Extended ABCI application
|
||||||
type DemocoinApp struct {
|
type DemocoinApp struct {
|
||||||
*bam.BaseApp
|
*bam.BaseApp
|
||||||
|
|
|
@ -3,6 +3,7 @@ package clitest
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -13,10 +14,11 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
democoindHome = ""
|
democoindHome = ""
|
||||||
|
democliHome = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
democoindHome = getTestingHomeDir()
|
democoindHome, democliHome = getTestingHomeDirs()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitStartSequence(t *testing.T) {
|
func TestInitStartSequence(t *testing.T) {
|
||||||
|
@ -32,8 +34,8 @@ func executeInit(t *testing.T) {
|
||||||
chainID string
|
chainID string
|
||||||
initRes map[string]json.RawMessage
|
initRes map[string]json.RawMessage
|
||||||
)
|
)
|
||||||
out := tests.ExecuteT(t, fmt.Sprintf("democoind --home=%s init", democoindHome), "")
|
_, stderr := tests.ExecuteT(t, fmt.Sprintf("democoind --home=%s --home-client=%s init --name=test", democoindHome, democliHome), app.DefaultKeyPass)
|
||||||
err := json.Unmarshal([]byte(out), &initRes)
|
err := json.Unmarshal([]byte(stderr), &initRes)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -45,8 +47,9 @@ func executeStart(t *testing.T, servAddr, port string) {
|
||||||
tests.WaitForTMStart(port)
|
tests.WaitForTMStart(port)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getTestingHomeDir() string {
|
func getTestingHomeDirs() (string, string) {
|
||||||
tmpDir := os.TempDir()
|
tmpDir := os.TempDir()
|
||||||
democoindHome := fmt.Sprintf("%s%s.test_democoind", tmpDir, string(os.PathSeparator))
|
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
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/libs/cli"
|
"github.com/tendermint/tendermint/libs/cli"
|
||||||
|
@ -91,7 +89,7 @@ func main() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// prepare and add flags
|
// prepare and add flags
|
||||||
executor := cli.PrepareMainCmd(rootCmd, "BC", os.ExpandEnv("$HOME/.democli"))
|
executor := cli.PrepareMainCmd(rootCmd, "BC", app.DefaultCLIHome)
|
||||||
err := executor.Execute()
|
err := executor.Execute()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// handle with #870
|
// handle with #870
|
||||||
|
|
|
@ -2,6 +2,11 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"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"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
@ -19,10 +24,13 @@ import (
|
||||||
"github.com/cosmos/cosmos-sdk/server"
|
"github.com/cosmos/cosmos-sdk/server"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
flagClientHome = "home-client"
|
||||||
|
)
|
||||||
|
|
||||||
// init parameters
|
// init parameters
|
||||||
var CoolAppInit = server.AppInit{
|
var CoolAppInit = server.AppInit{
|
||||||
AppGenState: CoolAppGenState,
|
AppGenState: CoolAppGenState,
|
||||||
AppGenTx: server.SimpleAppGenTx,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||||
|
@ -52,6 +60,69 @@ func CoolAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState js
|
||||||
return
|
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 {
|
func newApp(logger log.Logger, db dbm.DB, _ io.Writer) abci.Application {
|
||||||
return app.NewDemocoinApp(logger, db)
|
return app.NewDemocoinApp(logger, db)
|
||||||
}
|
}
|
||||||
|
@ -71,7 +142,7 @@ func main() {
|
||||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||||
}
|
}
|
||||||
|
|
||||||
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, CoolAppInit))
|
rootCmd.AddCommand(InitCmd(ctx, cdc, CoolAppInit))
|
||||||
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit))
|
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit))
|
||||||
|
|
||||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit,
|
||||||
|
|
|
@ -35,16 +35,3 @@ func (c *Config) MinimumFees() sdk.Coins {
|
||||||
|
|
||||||
// DefaultConfig returns server's default configuration.
|
// DefaultConfig returns server's default configuration.
|
||||||
func DefaultConfig() *Config { return &Config{BaseConfig{MinFees: defaultMinimumFees}} }
|
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 (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||||
"github.com/pkg/errors"
|
|
||||||
"github.com/spf13/pflag"
|
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
|
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
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"
|
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
serverconfig "github.com/cosmos/cosmos-sdk/server/config"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
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
|
// Core functionality passed from the application to the server init command
|
||||||
type AppInit struct {
|
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
|
// AppGenState creates the core parameters initialization. It takes in a
|
||||||
// pubkey meant to represent the pubkey of the validator of this machine.
|
// pubkey meant to represent the pubkey of the validator of this machine.
|
||||||
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
|
// simple default application init
|
||||||
var DefaultAppInit = AppInit{
|
var DefaultAppInit = AppInit{
|
||||||
AppGenTx: SimpleAppGenTx,
|
|
||||||
AppGenState: SimpleAppGenState,
|
AppGenState: SimpleAppGenState,
|
||||||
}
|
}
|
||||||
|
|
||||||
// simple genesis tx
|
|
||||||
type SimpleGenTx struct {
|
|
||||||
Addr sdk.AccAddress `json:"addr"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate a genesis transaction
|
// Generate a genesis transaction
|
||||||
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey, genTxConfig serverconfig.GenTx) (
|
func SimpleAppGenTx(cdc *codec.Codec, pk crypto.PubKey) (appGenTx, cliPrint json.RawMessage, validator types.GenesisValidator, err error) {
|
||||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
|
||||||
|
|
||||||
var addr sdk.AccAddress
|
var addr sdk.AccAddress
|
||||||
var secret string
|
var secret string
|
||||||
addr, secret, err = GenerateCoinKey()
|
addr, secret, err = GenerateCoinKey()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var bz []byte
|
var bz []byte
|
||||||
simpleGenTx := SimpleGenTx{addr}
|
simpleGenTx := SimpleGenTx{Addr: addr}
|
||||||
bz, err = cdc.MarshalJSON(simpleGenTx)
|
bz, err = cdc.MarshalJSON(simpleGenTx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
appGenTx = json.RawMessage(bz)
|
appGenTx = json.RawMessage(bz)
|
||||||
|
|
||||||
mm := map[string]string{"secret": secret}
|
mm := map[string]string{"secret": secret}
|
||||||
bz, err = cdc.MarshalJSON(mm)
|
bz, err = cdc.MarshalJSON(mm)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
cliPrint = json.RawMessage(bz)
|
cliPrint = json.RawMessage(bz)
|
||||||
|
|
||||||
validator = tmtypes.GenesisValidator{
|
validator = tmtypes.GenesisValidator{
|
||||||
PubKey: pk,
|
PubKey: pk,
|
||||||
Power: 10,
|
Power: 10,
|
||||||
|
@ -122,8 +70,8 @@ func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var genTx SimpleGenTx
|
var tx SimpleGenTx
|
||||||
err = cdc.UnmarshalJSON(appGenTxs[0], &genTx)
|
err = cdc.UnmarshalJSON(appGenTxs[0], &tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -138,7 +86,7 @@ func SimpleAppGenState(cdc *codec.Codec, appGenTxs []json.RawMessage) (appState
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}]
|
}]
|
||||||
}`, genTx.Addr))
|
}`, tx.Addr))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +124,8 @@ func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (s
|
||||||
if !overwrite {
|
if !overwrite {
|
||||||
_, err := keybase.Get(keyName)
|
_, err := keybase.Get(keyName)
|
||||||
if err == nil {
|
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"
|
"path/filepath"
|
||||||
|
|
||||||
abci "github.com/tendermint/tendermint/abci/types"
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
|
||||||
dbm "github.com/tendermint/tendermint/libs/db"
|
dbm "github.com/tendermint/tendermint/libs/db"
|
||||||
"github.com/tendermint/tendermint/libs/log"
|
"github.com/tendermint/tendermint/libs/log"
|
||||||
tmtypes "github.com/tendermint/tendermint/types"
|
|
||||||
|
|
||||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||||
"github.com/cosmos/cosmos-sdk/codec"
|
"github.com/cosmos/cosmos-sdk/codec"
|
||||||
gc "github.com/cosmos/cosmos-sdk/server/config"
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -126,14 +123,3 @@ func AppGenStateEmpty(_ *codec.Codec, _ []json.RawMessage) (appState json.RawMes
|
||||||
appState = json.RawMessage(``)
|
appState = json.RawMessage(``)
|
||||||
return
|
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 (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -42,6 +43,7 @@ func SetupViper(t *testing.T) func() {
|
||||||
rootDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
rootDir, err := ioutil.TempDir("", "mock-sdk-cmd")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
viper.Set(cli.HomeFlag, rootDir)
|
viper.Set(cli.HomeFlag, rootDir)
|
||||||
|
viper.Set(client.FlagName, "moniker")
|
||||||
return func() {
|
return func() {
|
||||||
err := os.RemoveAll(rootDir)
|
err := os.RemoveAll(rootDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
// ExecuteT executes the command, pipes any input to STDIN and return STDOUT,
|
||||||
// logging STDOUT/STDERR to t.
|
// logging STDOUT/STDERR to t.
|
||||||
// nolint: errcheck
|
// 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))
|
t.Log("Running", cmn.Cyan(cmd))
|
||||||
|
|
||||||
// split cmd to name and args
|
// 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)))
|
t.Log("Stderr:", cmn.Red(string(errbz)))
|
||||||
}
|
}
|
||||||
|
|
||||||
out = strings.Trim(string(outbz), "\n")
|
stdout = strings.Trim(string(outbz), "\n")
|
||||||
return out
|
stderr = strings.Trim(string(errbz), "\n")
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute the command, launch goroutines to log stdout/err to t.
|
// Execute the command, launch goroutines to log stdout/err to t.
|
||||||
|
|
|
@ -4,7 +4,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
"github.com/tendermint/tendermint/crypto"
|
"github.com/tendermint/tendermint/crypto"
|
||||||
"github.com/tendermint/tendermint/crypto/ed25519"
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
||||||
|
@ -81,7 +80,7 @@ func NewAnteHandler(am AccountMapper, fck FeeCollectionKeeper) sdk.AnteHandler {
|
||||||
if !res.IsOK() {
|
if !res.IsOK() {
|
||||||
return newCtx, res, true
|
return newCtx, res, true
|
||||||
}
|
}
|
||||||
res = validateAccNumAndSequence(signerAccs, stdSigs)
|
res = validateAccNumAndSequence(ctx, signerAccs, stdSigs)
|
||||||
if !res.IsOK() {
|
if !res.IsOK() {
|
||||||
return newCtx, res, true
|
return newCtx, res, true
|
||||||
}
|
}
|
||||||
|
@ -149,17 +148,23 @@ func getSignerAccs(ctx sdk.Context, am AccountMapper, addrs []sdk.AccAddress) (a
|
||||||
return
|
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++ {
|
for i := 0; i < len(accs); i++ {
|
||||||
accnum := accs[i].GetAccountNumber()
|
// On InitChain, make sure account number == 0
|
||||||
seq := accs[i].GetSequence()
|
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.
|
// Check account number.
|
||||||
if accnum != sigs[i].AccountNumber {
|
accnum := accs[i].GetAccountNumber()
|
||||||
|
if ctx.BlockHeight() != 0 && accnum != sigs[i].AccountNumber {
|
||||||
return sdk.ErrInvalidSequence(
|
return sdk.ErrInvalidSequence(
|
||||||
fmt.Sprintf("Invalid account number. Got %d, expected %d", sigs[i].AccountNumber, accnum)).Result()
|
fmt.Sprintf("Invalid account number. Got %d, expected %d", sigs[i].AccountNumber, accnum)).Result()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check sequence number.
|
// Check sequence number.
|
||||||
|
seq := accs[i].GetSequence()
|
||||||
if seq != sigs[i].Sequence {
|
if seq != sigs[i].Sequence {
|
||||||
return sdk.ErrInvalidSequence(
|
return sdk.ErrInvalidSequence(
|
||||||
fmt.Sprintf("Invalid sequence. Got %d, expected %d", sigs[i].Sequence, seq)).Result()
|
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 {
|
func setGasMeter(simulate bool, ctx sdk.Context, stdTx StdTx) sdk.Context {
|
||||||
// set the gas meter
|
// set the gas meter
|
||||||
if simulate {
|
if simulate || ctx.BlockHeight() == 0 {
|
||||||
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
return ctx.WithGasMeter(sdk.NewInfiniteGasMeter())
|
||||||
}
|
}
|
||||||
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
return ctx.WithGasMeter(sdk.NewGasMeter(stdTx.Fee.Gas))
|
||||||
|
|
|
@ -169,6 +169,7 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
@ -218,6 +219,66 @@ func TestAnteHandlerAccountNumbers(t *testing.T) {
|
||||||
checkValidTx(t, anteHandler, ctx, tx, false)
|
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.
|
// Test logic around sequence checking with one signer and many signers.
|
||||||
func TestAnteHandlerSequences(t *testing.T) {
|
func TestAnteHandlerSequences(t *testing.T) {
|
||||||
// setup
|
// setup
|
||||||
|
@ -228,6 +289,7 @@ func TestAnteHandlerSequences(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
@ -348,6 +410,7 @@ func TestAnteHandlerMemoGas(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
@ -391,6 +454,7 @@ func TestAnteHandlerMultiSigner(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
@ -442,6 +506,7 @@ func TestAnteHandlerBadSignBytes(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
@ -523,6 +588,7 @@ func TestAnteHandlerSetPubKey(t *testing.T) {
|
||||||
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
feeCollector := NewFeeCollectionKeeper(cdc, capKey2)
|
||||||
anteHandler := NewAnteHandler(mapper, feeCollector)
|
anteHandler := NewAnteHandler(mapper, feeCollector)
|
||||||
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
ctx := sdk.NewContext(ms, abci.Header{ChainID: "mychainid"}, false, log.NewNopLogger())
|
||||||
|
ctx = ctx.WithBlockHeight(1)
|
||||||
|
|
||||||
// keys and addresses
|
// keys and addresses
|
||||||
priv1, addr1 := privAndAddr()
|
priv1, addr1 := privAndAddr()
|
||||||
|
|
|
@ -19,6 +19,7 @@ import (
|
||||||
const (
|
const (
|
||||||
flagAppend = "append"
|
flagAppend = "append"
|
||||||
flagPrintSigs = "print-sigs"
|
flagPrintSigs = "print-sigs"
|
||||||
|
flagOffline = "offline"
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetSignCommand returns the sign command
|
// GetSignCommand returns the sign command
|
||||||
|
@ -27,13 +28,18 @@ func GetSignCommand(codec *amino.Codec, decoder auth.AccountDecoder) *cobra.Comm
|
||||||
Use: "sign <file>",
|
Use: "sign <file>",
|
||||||
Short: "Sign transactions generated offline",
|
Short: "Sign transactions generated offline",
|
||||||
Long: `Sign transactions created with the --generate-only flag.
|
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),
|
RunE: makeSignCmd(codec, decoder),
|
||||||
Args: cobra.ExactArgs(1),
|
Args: cobra.ExactArgs(1),
|
||||||
}
|
}
|
||||||
cmd.Flags().String(client.FlagName, "", "Name of private key with which to sign")
|
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(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(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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +59,7 @@ func makeSignCmd(cdc *amino.Codec, decoder auth.AccountDecoder) func(cmd *cobra.
|
||||||
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(decoder)
|
||||||
txBldr := authtxb.NewTxBuilderFromCLI()
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
@ -210,7 +210,7 @@ func TestSengMsgMultipleInOut(t *testing.T) {
|
||||||
testCases := []appTestCase{
|
testCases := []appTestCase{
|
||||||
{
|
{
|
||||||
msgs: []sdk.Msg{sendMsg3},
|
msgs: []sdk.Msg{sendMsg3},
|
||||||
accNums: []int64{0, 2},
|
accNums: []int64{0, 0},
|
||||||
accSeqs: []int64{0, 0},
|
accSeqs: []int64{0, 0},
|
||||||
expSimPass: true,
|
expSimPass: true,
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
@ -258,7 +258,7 @@ func TestMsgSendDependent(t *testing.T) {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
msgs: []sdk.Msg{sendMsg4},
|
msgs: []sdk.Msg{sendMsg4},
|
||||||
accNums: []int64{1},
|
accNums: []int64{0},
|
||||||
accSeqs: []int64{0},
|
accSeqs: []int64{0},
|
||||||
expSimPass: true,
|
expSimPass: true,
|
||||||
expPass: true,
|
expPass: true,
|
||||||
|
|
|
@ -14,9 +14,9 @@ func (k Keeper) onValidatorCreated(ctx sdk.Context, addr sdk.ValAddress) {
|
||||||
vdi := types.ValidatorDistInfo{
|
vdi := types.ValidatorDistInfo{
|
||||||
OperatorAddr: addr,
|
OperatorAddr: addr,
|
||||||
FeePoolWithdrawalHeight: height,
|
FeePoolWithdrawalHeight: height,
|
||||||
Pool: types.DecCoins{},
|
Pool: types.DecCoins{},
|
||||||
PoolCommission: types.DecCoins{},
|
PoolCommission: types.DecCoins{},
|
||||||
DelAccum: types.NewTotalAccum(height),
|
DelAccum: types.NewTotalAccum(height),
|
||||||
}
|
}
|
||||||
k.SetValidatorDistInfo(ctx, vdi)
|
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
|
// Initially this is the same as the initial validator set
|
||||||
nextValidators := validators
|
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
|
opCount := 0
|
||||||
|
|
||||||
// Setup code to catch SIGTERM's
|
// Setup code to catch SIGTERM's
|
||||||
|
@ -384,7 +384,7 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
|
||||||
time := header.Time
|
time := header.Time
|
||||||
vals := voteInfos
|
vals := voteInfos
|
||||||
if r.Float64() < pastEvidenceFraction {
|
if r.Float64() < pastEvidenceFraction {
|
||||||
height = int64(r.Intn(int(header.Height)))
|
height = int64(r.Intn(int(header.Height) - 1))
|
||||||
time = pastTimes[height]
|
time = pastTimes[height]
|
||||||
vals = pastVoteInfos[height]
|
vals = pastVoteInfos[height]
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,7 +137,7 @@ func TestStakeMsgs(t *testing.T) {
|
||||||
addr1, sdk.ValAddress(addr2), priv2.PubKey(), bondCoin, description, commissionMsg,
|
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)})
|
mock.CheckBalance(t, mApp, addr1, sdk.Coins{genCoin.Minus(bondCoin).Minus(bondCoin)})
|
||||||
mApp.BeginBlock(abci.RequestBeginBlock{})
|
mApp.BeginBlock(abci.RequestBeginBlock{})
|
||||||
|
|
||||||
|
@ -161,13 +161,13 @@ func TestStakeMsgs(t *testing.T) {
|
||||||
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin})
|
||||||
delegateMsg := NewMsgDelegate(addr2, sdk.ValAddress(addr1), bondCoin)
|
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)})
|
mock.CheckBalance(t, mApp, addr2, sdk.Coins{genCoin.Minus(bondCoin)})
|
||||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10))
|
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), true, sdk.NewDec(10))
|
||||||
|
|
||||||
// begin unbonding
|
// begin unbonding
|
||||||
beginUnbondingMsg := NewMsgBeginUnbonding(addr2, sdk.ValAddress(addr1), sdk.NewDec(10))
|
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
|
// delegation should exist anymore
|
||||||
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
|
checkDelegation(t, mApp, keeper, addr2, sdk.ValAddress(addr1), false, sdk.Dec{})
|
||||||
|
|
|
@ -25,6 +25,12 @@ const (
|
||||||
FlagCommissionRate = "commission-rate"
|
FlagCommissionRate = "commission-rate"
|
||||||
FlagCommissionMaxRate = "commission-max-rate"
|
FlagCommissionMaxRate = "commission-max-rate"
|
||||||
FlagCommissionMaxChangeRate = "commission-max-change-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
|
// common flagsets to add to various functions
|
||||||
|
|
|
@ -2,7 +2,6 @@ package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/cosmos/cosmos-sdk/client"
|
"github.com/cosmos/cosmos-sdk/client"
|
||||||
"github.com/cosmos/cosmos-sdk/client/context"
|
"github.com/cosmos/cosmos-sdk/client/context"
|
||||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
"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)
|
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(fsDescriptionCreate)
|
||||||
cmd.Flags().AddFlagSet(fsCommissionCreate)
|
cmd.Flags().AddFlagSet(fsCommissionCreate)
|
||||||
cmd.Flags().AddFlagSet(fsDelegator)
|
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
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue