commit
b4af0916b3
|
@ -11,6 +11,10 @@ FEATURES:
|
|||
* MountStoreWithDB without providing a custom store works.
|
||||
* Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI
|
||||
* Better key output, pubkey go-amino hex bytes now output by default
|
||||
* gaiad init overhaul
|
||||
* Create genesis transactions with `gaiad init gen-tx`
|
||||
* New genesis account keys are automatically added to the client keybase (introduce `--client-home` flag)
|
||||
* Initialize with genesis txs using `--gen-txs` flag
|
||||
|
||||
BREAKING CHANGES
|
||||
|
||||
|
@ -25,6 +29,7 @@ BREAKING CHANGES
|
|||
* Type as a prefix naming convention applied (ex. BondMsg -> MsgBond)
|
||||
* Removed redundancy in names (ex. stake.StakeKeeper -> stake.Keeper)
|
||||
* Removed SealedAccountMapper
|
||||
* gaiad init now requires use of `--name` flag
|
||||
|
||||
BUG FIXES
|
||||
* Gaia now uses stake, ported from github.com/cosmos/gaia
|
||||
|
@ -74,7 +79,7 @@ BREAKING CHANGES
|
|||
to allow mounting multiple stores with their own DB until they can share one
|
||||
* [x/staking] Renamed to `simplestake`
|
||||
* [builder] Functions don't take `passphrase` as argument
|
||||
* [server] GenAppState returns generated seed and address
|
||||
* [server] GenAppParams returns generated seed and address
|
||||
* [basecoind] `init` command outputs JSON of everything necessary for testnet
|
||||
* [basecoind] `basecoin.db -> data/basecoin.db`
|
||||
* [basecli] `data/keys.db -> keys/keys.db`
|
||||
|
|
3
Makefile
3
Makefile
|
@ -85,6 +85,9 @@ godocs:
|
|||
|
||||
test: test_unit # test_cli
|
||||
|
||||
test_nocli:
|
||||
go test `go list ./... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test`
|
||||
|
||||
# Must be run in each package seperately for the visualization
|
||||
# Added here for easy reference
|
||||
# coverage:
|
||||
|
|
|
@ -24,8 +24,13 @@ var keybase keys.Keybase
|
|||
|
||||
// initialize a keybase based on the configuration
|
||||
func GetKeyBase() (keys.Keybase, error) {
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
return GetKeyBaseFromDir(rootDir)
|
||||
}
|
||||
|
||||
// initialize a keybase based on the configuration
|
||||
func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) {
|
||||
if keybase == nil {
|
||||
rootDir := viper.GetString(cli.HomeFlag)
|
||||
db, err := dbm.NewGoLevelDB(KeyDBName, filepath.Join(rootDir, "keys"))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
@ -7,33 +7,14 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||
)
|
||||
|
||||
var globalConfig *cfg.Config
|
||||
|
||||
func waitForRPC() {
|
||||
laddr := GetConfig().RPC.ListenAddress
|
||||
fmt.Println("LADDR", laddr)
|
||||
client := rpcclient.NewJSONRPCClient(laddr)
|
||||
ctypes.RegisterAmino(client.Codec())
|
||||
result := new(ctypes.ResultStatus)
|
||||
for {
|
||||
_, err := client.Call("status", map[string]interface{}{}, result)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
fmt.Println("error", err)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
// f**ing long, but unique for each test
|
||||
func makePathname() string {
|
||||
// get path
|
||||
|
|
|
@ -10,7 +10,6 @@ import (
|
|||
"os"
|
||||
"regexp"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
@ -34,6 +33,7 @@ import (
|
|||
keys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app"
|
||||
btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types"
|
||||
tests "github.com/cosmos/cosmos-sdk/tests"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
|
@ -157,7 +157,7 @@ func TestNodeStatus(t *testing.T) {
|
|||
|
||||
func TestBlock(t *testing.T) {
|
||||
|
||||
waitForHeight(2)
|
||||
tests.WaitForHeight(2, port)
|
||||
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
|
@ -224,7 +224,7 @@ func TestCoinSend(t *testing.T) {
|
|||
|
||||
// create TX
|
||||
receiveAddr, resultTx := doSend(t, port, seed)
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
// check if tx was commited
|
||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
|
@ -253,7 +253,7 @@ func TestIBCTransfer(t *testing.T) {
|
|||
// create TX
|
||||
resultTx := doIBCTransfer(t, port, seed)
|
||||
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
// check if tx was commited
|
||||
assert.Equal(t, uint32(0), resultTx.CheckTx.Code)
|
||||
|
@ -286,7 +286,7 @@ func TestTxs(t *testing.T) {
|
|||
// create TX
|
||||
_, resultTx := doSend(t, port, seed)
|
||||
|
||||
waitForHeight(resultTx.Height + 1)
|
||||
tests.WaitForHeight(resultTx.Height+1, port)
|
||||
|
||||
// check if tx is findable
|
||||
res, body := request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil)
|
||||
|
@ -380,7 +380,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) {
|
|||
return nil, nil, err
|
||||
}
|
||||
|
||||
waitForStart()
|
||||
tests.WaitForStart(port)
|
||||
|
||||
return node, lcd, nil
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, p
|
|||
}
|
||||
|
||||
// wait for rpc
|
||||
waitForRPC()
|
||||
tests.WaitForRPC(GetConfig().RPC.ListenAddress)
|
||||
|
||||
logger.Info("Tendermint running!")
|
||||
return n, err
|
||||
|
@ -490,71 +490,3 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad
|
|||
|
||||
return resultTx
|
||||
}
|
||||
|
||||
func waitForHeight(height int64) {
|
||||
for {
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= height {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 2 blocks
|
||||
func waitForStart() {
|
||||
waitHeight := int64(2)
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// waiting for server to start ...
|
||||
if res.StatusCode != http.StatusOK {
|
||||
res.Body.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
resultBlock := new(ctypes.ResultBlock)
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= waitHeight {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import (
|
|||
"strconv"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
abci "github.com/tendermint/abci/types"
|
||||
|
@ -25,10 +24,8 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command {
|
|||
cmd := &cobra.Command{
|
||||
Use: "tx [hash]",
|
||||
Short: "Matches this txhash over all committed blocks",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 || len(args[0]) == 0 {
|
||||
return errors.New("You must provide a tx hash")
|
||||
}
|
||||
|
||||
// find the key to look up the account
|
||||
hashHexStr := args[0]
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
|
@ -21,6 +21,12 @@ const (
|
|||
appName = "GaiaApp"
|
||||
)
|
||||
|
||||
// default home directories for expected binaries
|
||||
var (
|
||||
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
|
||||
)
|
||||
|
||||
// Extended ABCI application
|
||||
type GaiaApp struct {
|
||||
*bam.BaseApp
|
||||
|
@ -130,7 +136,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(GenesisState)
|
||||
err := json.Unmarshal(stateJSON, genesisState)
|
||||
err := app.cdc.UnmarshalJSON(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
|
@ -147,54 +153,3 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci
|
|||
|
||||
return abci.ResponseInitChain{}
|
||||
}
|
||||
|
||||
//__________________________________________________________
|
||||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
type GenesisAccount struct {
|
||||
Address sdk.Address `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to GaiaAccount
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||
return &auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
}
|
||||
}
|
||||
|
||||
// DefaultGenAppState expects two args: an account address
|
||||
// and a coin denomination, and gives lots of coins to that address.
|
||||
func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
accAuth.Coins = sdk.Coins{{"fermion", 100000}}
|
||||
acc := NewGenesisAccount(&accAuth)
|
||||
genaccs := []GenesisAccount{acc}
|
||||
|
||||
genesisState := GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stake.GetDefaultGenesisState(),
|
||||
}
|
||||
|
||||
stateBytes, err := json.MarshalIndent(genesisState, "", "\t")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return stateBytes, nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
// State to Unmarshal
|
||||
type GenesisState struct {
|
||||
Accounts []GenesisAccount `json:"accounts"`
|
||||
StakeData stake.GenesisState `json:"stake"`
|
||||
}
|
||||
|
||||
// GenesisAccount doesn't need pubkey or sequence
|
||||
type GenesisAccount struct {
|
||||
Address sdk.Address `json:"address"`
|
||||
Coins sdk.Coins `json:"coins"`
|
||||
}
|
||||
|
||||
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
|
||||
return GenesisAccount{
|
||||
Address: acc.Address,
|
||||
Coins: acc.Coins,
|
||||
}
|
||||
}
|
||||
|
||||
// convert GenesisAccount to auth.BaseAccount
|
||||
func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) {
|
||||
return &auth.BaseAccount{
|
||||
Address: ga.Address,
|
||||
Coins: ga.Coins.Sort(),
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
flagName = "name"
|
||||
flagClientHome = "home-client"
|
||||
flagOWK = "owk"
|
||||
|
||||
// bonded tokens given to genesis validators/accounts
|
||||
freeFermionVal = int64(100)
|
||||
freeFermionsAcc = int64(50)
|
||||
)
|
||||
|
||||
// get app init parameters for server init command
|
||||
func GaiaAppInit() server.AppInit {
|
||||
fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
|
||||
fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||
fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator")
|
||||
fsAppGenTx.String(flagClientHome, DefaultCLIHome, "home directory for the client, used for key generation")
|
||||
fsAppGenTx.Bool(flagOWK, false, "overwrite the for the accounts created")
|
||||
|
||||
return server.AppInit{
|
||||
FlagsAppGenState: fsAppGenState,
|
||||
FlagsAppGenTx: fsAppGenTx,
|
||||
AppGenTx: GaiaAppGenTx,
|
||||
AppGenState: GaiaAppGenState,
|
||||
}
|
||||
}
|
||||
|
||||
// simple genesis tx
|
||||
type GaiaGenTx struct {
|
||||
Name string `json:"name"`
|
||||
Address sdk.Address `json:"address"`
|
||||
PubKey crypto.PubKey `json:"pub_key"`
|
||||
}
|
||||
|
||||
// Generate a gaia genesis transaction
|
||||
func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
var addr sdk.Address
|
||||
var secret string
|
||||
clientRoot := viper.GetString(flagClientHome)
|
||||
overwrite := viper.GetBool(flagOWK)
|
||||
name := viper.GetString(flagName)
|
||||
addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var bz []byte
|
||||
gaiaGenTx := GaiaGenTx{
|
||||
Name: name,
|
||||
Address: addr,
|
||||
PubKey: pk,
|
||||
}
|
||||
bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appGenTx = json.RawMessage(bz)
|
||||
|
||||
mm := map[string]string{"secret": secret}
|
||||
bz, err = cdc.MarshalJSON(mm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cliPrint = json.RawMessage(bz)
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
Power: freeFermionVal,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Create the core parameters for genesis initialization for gaia
|
||||
// note that the pubkey input is this machines pubkey
|
||||
func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
|
||||
if len(appGenTxs) == 0 {
|
||||
err = errors.New("must provide at least genesis transaction")
|
||||
return
|
||||
}
|
||||
|
||||
// start with the default staking genesis state
|
||||
stakeData := stake.GetDefaultGenesisState()
|
||||
|
||||
// get genesis flag account information
|
||||
genaccs := make([]GenesisAccount, len(appGenTxs))
|
||||
for i, appGenTx := range appGenTxs {
|
||||
|
||||
var genTx GaiaGenTx
|
||||
err = cdc.UnmarshalJSON(appGenTx, &genTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// create the genesis account, give'm few fermions and a buncha token with there name
|
||||
accAuth := auth.NewBaseAccountWithAddress(genTx.Address)
|
||||
accAuth.Coins = sdk.Coins{
|
||||
{genTx.Name + "Token", 1000},
|
||||
{"fermion", freeFermionsAcc},
|
||||
}
|
||||
acc := NewGenesisAccount(&accAuth)
|
||||
genaccs[i] = acc
|
||||
stakeData.Pool.TotalSupply += freeFermionsAcc // increase the supply
|
||||
|
||||
// add the validator
|
||||
if len(genTx.Name) > 0 {
|
||||
desc := stake.NewDescription(genTx.Name, "", "", "")
|
||||
candidate := stake.NewCandidate(genTx.Address, genTx.PubKey, desc)
|
||||
candidate.Assets = sdk.NewRat(freeFermionVal)
|
||||
stakeData.Candidates = append(stakeData.Candidates, candidate)
|
||||
|
||||
// pool logic
|
||||
stakeData.Pool.TotalSupply += freeFermionVal
|
||||
stakeData.Pool.BondedPool += freeFermionVal
|
||||
stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool)
|
||||
}
|
||||
}
|
||||
|
||||
// create the final app state
|
||||
genesisState := GenesisState{
|
||||
Accounts: genaccs,
|
||||
StakeData: stakeData,
|
||||
}
|
||||
appState, err = wire.MarshalJSONIndent(cdc, genesisState)
|
||||
return
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/stretchr/testify/assert"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
)
|
||||
|
||||
func TestToAccount(t *testing.T) {
|
||||
priv := crypto.GenPrivKeyEd25519()
|
||||
addr := sdk.Address(priv.PubKey().Address())
|
||||
authAcc := auth.NewBaseAccountWithAddress(addr)
|
||||
genAcc := NewGenesisAccount(&authAcc)
|
||||
assert.Equal(t, authAcc, *genAcc.ToAccount())
|
||||
}
|
||||
|
||||
func TestGaiaAppGenTx(t *testing.T) {
|
||||
cdc := MakeCodec()
|
||||
_ = cdc
|
||||
|
||||
//TODO test that key overwrite flags work / no overwrites if set off
|
||||
//TODO test validator created has provided pubkey
|
||||
//TODO test the account created has the correct pubkey
|
||||
}
|
||||
|
||||
func TestGaiaAppGenState(t *testing.T) {
|
||||
cdc := MakeCodec()
|
||||
_ = cdc
|
||||
|
||||
// TODO test must provide at least genesis transaction
|
||||
// TODO test with both one and two genesis transactions:
|
||||
// TODO correct: genesis account created, canididates created, pool token variance
|
||||
}
|
|
@ -3,7 +3,6 @@ package clitest
|
|||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -14,17 +13,19 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/stake"
|
||||
)
|
||||
|
||||
func TestGaiaCLISend(t *testing.T) {
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
executeWrite(t, "gaiacli keys delete foo", pass)
|
||||
executeWrite(t, "gaiacli keys delete bar", pass)
|
||||
masterKey, chainID := executeInit(t, "gaiad init")
|
||||
chainID := executeInit(t, "gaiad init -o --name=foo")
|
||||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
|
||||
// get a free port, also setup some common flags
|
||||
servAddr := server.FreeTCPAddr(t)
|
||||
|
@ -34,14 +35,11 @@ func TestGaiaCLISend(t *testing.T) {
|
|||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
|
||||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
|
||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
|
||||
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
|
@ -49,15 +47,17 @@ func TestGaiaCLISend(t *testing.T) {
|
|||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion"))
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
|
||||
assert.Equal(t, int64(99990), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
}
|
||||
|
||||
func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
||||
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all", 1)
|
||||
tests.ExecuteT(t, "gaiad unsafe_reset_all")
|
||||
pass := "1234567890"
|
||||
executeWrite(t, "gaiacli keys delete foo", pass)
|
||||
masterKey, chainID := executeInit(t, "gaiad init")
|
||||
executeWrite(t, "gaiacli keys delete bar", pass)
|
||||
chainID := executeInit(t, "gaiad init -o --name=foo")
|
||||
executeWrite(t, "gaiacli keys add bar", pass)
|
||||
|
||||
// get a free port, also setup some common flags
|
||||
servAddr := server.FreeTCPAddr(t)
|
||||
|
@ -67,42 +67,48 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) {
|
|||
cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr))
|
||||
defer cmd.Process.Kill()
|
||||
|
||||
executeWrite(t, "gaiacli keys add foo --recover", pass, masterKey)
|
||||
fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json")
|
||||
barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json")
|
||||
|
||||
executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
|
||||
fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
|
||||
assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion"))
|
||||
|
||||
// declare candidacy
|
||||
declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags)
|
||||
declStr += fmt.Sprintf(" --name=%v", "foo")
|
||||
declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
|
||||
declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey)
|
||||
declStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
declStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
|
||||
declStr += fmt.Sprintf(" --pubkey=%v", barPubKey)
|
||||
declStr += fmt.Sprintf(" --amount=%v", "3fermion")
|
||||
declStr += fmt.Sprintf(" --moniker=%v", "foo-vally")
|
||||
declStr += fmt.Sprintf(" --moniker=%v", "bar-vally")
|
||||
fmt.Printf("debug declStr: %v\n", declStr)
|
||||
executeWrite(t, declStr, pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
|
||||
assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
|
||||
assert.Equal(t, candidate.Address.String(), fooAddr)
|
||||
time.Sleep(time.Second) // waiting for some blocks to pass
|
||||
barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("fermion"))
|
||||
candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
||||
assert.Equal(t, candidate.Address.String(), barAddr)
|
||||
assert.Equal(t, int64(3), candidate.Assets.Evaluate())
|
||||
|
||||
// TODO timeout issues if not connected to the internet
|
||||
// unbond a single share
|
||||
unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
|
||||
unbondStr += fmt.Sprintf(" --name=%v", "foo")
|
||||
unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr)
|
||||
unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr)
|
||||
unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
||||
unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
||||
fmt.Printf("debug unbondStr: %v\n", unbondStr)
|
||||
executeWrite(t, unbondStr, pass)
|
||||
time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags))
|
||||
assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion"))
|
||||
candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr))
|
||||
assert.Equal(t, int64(2), candidate.Assets.Evaluate())
|
||||
//unbondStr := fmt.Sprintf("gaiacli unbond %v", flags)
|
||||
//unbondStr += fmt.Sprintf(" --name=%v", "bar")
|
||||
//unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr)
|
||||
//unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr)
|
||||
//unbondStr += fmt.Sprintf(" --shares=%v", "1")
|
||||
//unbondStr += fmt.Sprintf(" --sequence=%v", "1")
|
||||
//fmt.Printf("debug unbondStr: %v\n", unbondStr)
|
||||
//executeWrite(t, unbondStr, pass)
|
||||
//time.Sleep(time.Second * 3) // waiting for some blocks to pass
|
||||
//barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags))
|
||||
//assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("fermion"))
|
||||
//candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr))
|
||||
//assert.Equal(t, int64(2), candidate.Assets.Evaluate())
|
||||
}
|
||||
|
||||
func executeWrite(t *testing.T, cmdStr string, writes ...string) {
|
||||
|
@ -112,6 +118,7 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) {
|
|||
_, err := wc.Write([]byte(write + "\n"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
fmt.Printf("debug waiting cmdStr: %v\n", cmdStr)
|
||||
cmd.Wait()
|
||||
}
|
||||
|
||||
|
@ -122,6 +129,7 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) {
|
|||
_, err := wc.Write([]byte(write + "\n"))
|
||||
require.NoError(t, err)
|
||||
}
|
||||
fmt.Printf("debug waiting cmdStr: %v\n", cmdStr)
|
||||
cmd.Wait()
|
||||
|
||||
bz := make([]byte, 100000)
|
||||
|
@ -129,41 +137,42 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) {
|
|||
fmt.Printf("debug read: %v\n", string(bz))
|
||||
}
|
||||
|
||||
func executeInit(t *testing.T, cmdStr string) (masterKey, chainID string) {
|
||||
out := tests.ExecuteT(t, cmdStr, 1)
|
||||
outCut := "{" + strings.SplitN(out, "{", 2)[1] // weird I'm sorry
|
||||
func executeInit(t *testing.T, cmdStr string) (chainID string) {
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
|
||||
var initRes map[string]json.RawMessage
|
||||
err := json.Unmarshal([]byte(outCut), &initRes)
|
||||
require.NoError(t, err)
|
||||
err = json.Unmarshal(initRes["secret"], &masterKey)
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = json.Unmarshal(initRes["chain_id"], &chainID)
|
||||
require.NoError(t, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func executeGetAddrPK(t *testing.T, cmdStr string) (addr, pubKey string) {
|
||||
out := tests.ExecuteT(t, cmdStr, 2)
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
var ko keys.KeyOutput
|
||||
keys.UnmarshalJSON([]byte(out), &ko)
|
||||
return ko.Address, ko.PubKey
|
||||
}
|
||||
|
||||
func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount {
|
||||
out := tests.ExecuteT(t, cmdStr, 2)
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
var initRes map[string]json.RawMessage
|
||||
err := json.Unmarshal([]byte(out), &initRes)
|
||||
require.NoError(t, err, "out %v, err %v", out, err)
|
||||
value := initRes["value"]
|
||||
var acc auth.BaseAccount
|
||||
_ = json.Unmarshal(value, &acc) //XXX pubkey can't be decoded go amino issue
|
||||
cdc := wire.NewCodec()
|
||||
wire.RegisterCrypto(cdc)
|
||||
err = cdc.UnmarshalJSON(value, &acc)
|
||||
require.NoError(t, err, "value %v, err %v", string(value), err)
|
||||
return acc
|
||||
}
|
||||
|
||||
func executeGetCandidate(t *testing.T, cmdStr string) stake.Candidate {
|
||||
out := tests.ExecuteT(t, cmdStr, 2)
|
||||
out := tests.ExecuteT(t, cmdStr)
|
||||
var candidate stake.Candidate
|
||||
cdc := app.MakeCodec()
|
||||
err := cdc.UnmarshalJSON([]byte(out), &candidate)
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
@ -73,6 +71,6 @@ func main() {
|
|||
)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareMainCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli"))
|
||||
executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome)
|
||||
executor.Execute()
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
@ -15,15 +14,21 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/server"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
ctx := server.NewDefaultContext()
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "gaiad",
|
||||
Short: "Gaia Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
)
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp)
|
||||
|
||||
// prepare and add flags
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
|
||||
executor.Execute()
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
|
@ -34,12 +39,3 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
|||
bapp := app.NewGaiaApp(logger, db)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
server.AddCommands(rootCmd, app.DefaultGenAppState, generateApp, context)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.gaiad")
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir)
|
||||
executor.Execute()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
@ -133,7 +131,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain)
|
|||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(types.GenesisState)
|
||||
err := json.Unmarshal(stateJSON, genesisState)
|
||||
err := app.cdc.UnmarshalJSON(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
|
|
|
@ -15,15 +15,23 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/server"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
func main() {
|
||||
cdc := app.MakeCodec()
|
||||
ctx := server.NewDefaultContext()
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "basecoind",
|
||||
Short: "Basecoin Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
)
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, generateApp)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
|
||||
executor.Execute()
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
dataDir := filepath.Join(rootDir, "data")
|
||||
|
@ -34,12 +42,3 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
|||
bapp := app.NewBasecoinApp(logger, db)
|
||||
return bapp, nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.basecoind")
|
||||
executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir)
|
||||
executor.Execute()
|
||||
}
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
@ -147,7 +145,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep
|
|||
stateJSON := req.AppStateBytes
|
||||
|
||||
genesisState := new(types.GenesisState)
|
||||
err := json.Unmarshal(stateJSON, genesisState)
|
||||
err := app.cdc.UnmarshalJSON(stateJSON, genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
|
|
|
@ -14,36 +14,27 @@ import (
|
|||
|
||||
"github.com/cosmos/cosmos-sdk/examples/democoin/app"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
// rootCmd is the entry point for this binary
|
||||
var (
|
||||
context = server.NewDefaultContext()
|
||||
rootCmd = &cobra.Command{
|
||||
Use: "democoind",
|
||||
Short: "Democoin Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(context),
|
||||
}
|
||||
)
|
||||
// init parameters
|
||||
var CoolAppInit = server.AppInit{
|
||||
AppGenState: CoolAppGenState,
|
||||
AppGenTx: server.SimpleAppGenTx,
|
||||
}
|
||||
|
||||
// defaultAppState sets up the app_state for the
|
||||
// default genesis file
|
||||
func defaultAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
baseJSON, err := server.DefaultGenAppState(args, addr, coinDenom)
|
||||
// coolGenAppParams sets up the app_state and appends the cool app state
|
||||
func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
appState, err = server.SimpleAppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return
|
||||
}
|
||||
var jsonMap map[string]json.RawMessage
|
||||
err = json.Unmarshal(baseJSON, &jsonMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonMap["cool"] = json.RawMessage(`{
|
||||
key := "cool"
|
||||
value := json.RawMessage(`{
|
||||
"trend": "ice-cold"
|
||||
}`)
|
||||
bz, err := json.Marshal(jsonMap)
|
||||
return json.RawMessage(bz), err
|
||||
appState, err = server.AppendJSON(cdc, appState, key, value)
|
||||
return
|
||||
}
|
||||
|
||||
func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
|
@ -56,7 +47,16 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
server.AddCommands(rootCmd, defaultAppState, generateApp, context)
|
||||
cdc := app.MakeCodec()
|
||||
ctx := server.NewDefaultContext()
|
||||
|
||||
rootCmd := &cobra.Command{
|
||||
Use: "democoind",
|
||||
Short: "Democoin Daemon (server)",
|
||||
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
|
||||
}
|
||||
|
||||
server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, generateApp)
|
||||
|
||||
// prepare and add flags
|
||||
rootDir := os.ExpandEnv("$HOME/.democoind")
|
||||
|
|
30
mock/app.go
30
mock/app.go
|
@ -6,16 +6,18 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
abci "github.com/tendermint/abci/types"
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
// NewApp creates a simple mock kvstore app for testing.
|
||||
// It should work similar to a real app.
|
||||
// Make sure rootDir is empty before running the test,
|
||||
// NewApp creates a simple mock kvstore app for testing. It should work
|
||||
// similar to a real app. Make sure rootDir is empty before running the test,
|
||||
// in order to guarantee consistent results
|
||||
func NewApp(rootDir string, logger log.Logger) (abci.Application, error) {
|
||||
db, err := dbm.NewGoLevelDB("mock", filepath.Join(rootDir, "data"))
|
||||
|
@ -103,11 +105,10 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci
|
|||
}
|
||||
}
|
||||
|
||||
// GenInitOptions can be passed into InitCmd,
|
||||
// returns a static string of a few key-values that can be parsed
|
||||
// by InitChainer
|
||||
func GenInitOptions(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
opts := []byte(`{
|
||||
// AppGenState can be passed into InitCmd, returns a static string of a few
|
||||
// key-values that can be parsed by InitChainer
|
||||
func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
appState = json.RawMessage(`{
|
||||
"values": [
|
||||
{
|
||||
"key": "hello",
|
||||
|
@ -119,5 +120,16 @@ func GenInitOptions(args []string, addr sdk.Address, coinDenom string) (json.Raw
|
|||
}
|
||||
]
|
||||
}`)
|
||||
return opts, nil
|
||||
return
|
||||
}
|
||||
|
||||
// Return a validator, not much else
|
||||
func AppGenTx(_ *wire.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
Power: 10,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
@ -21,9 +21,13 @@ func TestInitApp(t *testing.T) {
|
|||
require.NoError(t, err)
|
||||
|
||||
// initialize it future-way
|
||||
opts, err := GenInitOptions(nil, nil, "")
|
||||
appState, err := AppGenState(nil, nil)
|
||||
require.NoError(t, err)
|
||||
req := abci.RequestInitChain{AppStateBytes: opts}
|
||||
|
||||
//TODO test validators in the init chain?
|
||||
req := abci.RequestInitChain{
|
||||
AppStateBytes: appState,
|
||||
}
|
||||
app.InitChain(req)
|
||||
app.Commit()
|
||||
|
||||
|
|
522
server/init.go
522
server/init.go
|
@ -4,218 +4,388 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
crypto "github.com/tendermint/go-crypto"
|
||||
"github.com/tendermint/go-crypto/keys"
|
||||
"github.com/tendermint/go-crypto/keys/words"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tendermint/p2p"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
pvm "github.com/tendermint/tendermint/types/priv_validator"
|
||||
tmcli "github.com/tendermint/tmlibs/cli"
|
||||
cmn "github.com/tendermint/tmlibs/common"
|
||||
dbm "github.com/tendermint/tmlibs/db"
|
||||
|
||||
clkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
// testnetInformation contains the info necessary
|
||||
// to setup a testnet including this account and validator.
|
||||
type testnetInformation struct {
|
||||
Secret string `json:"secret"`
|
||||
|
||||
ChainID string `json:"chain_id"`
|
||||
Account string `json:"account"`
|
||||
// genesis piece structure for creating combined genesis
|
||||
type GenesisTx struct {
|
||||
NodeID string `json:"node_id"`
|
||||
IP string `json:"ip"`
|
||||
Validator tmtypes.GenesisValidator `json:"validator"`
|
||||
NodeID p2p.ID `json:"node_id"`
|
||||
AppGenTx json.RawMessage `json:"app_gen_tx"`
|
||||
}
|
||||
|
||||
type initCmd struct {
|
||||
genAppState GenAppState
|
||||
context *Context
|
||||
}
|
||||
var (
|
||||
flagOverwrite = "overwrite"
|
||||
flagGenTxs = "gen-txs"
|
||||
flagIP = "ip"
|
||||
flagChainID = "chain-id"
|
||||
)
|
||||
|
||||
// InitCmd will initialize all files for tendermint,
|
||||
// along with proper app_state.
|
||||
// The application can pass in a function to generate
|
||||
// proper state. And may want to use GenerateCoinKey
|
||||
// to create default account(s).
|
||||
func InitCmd(gen GenAppState, ctx *Context) *cobra.Command {
|
||||
cmd := initCmd{
|
||||
genAppState: gen,
|
||||
context: ctx,
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "gen-tx",
|
||||
Short: "Create genesis transaction file (under [--home]/gentx-[nodeID].json)",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, args []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ip := viper.GetString(flagIP)
|
||||
if len(ip) == 0 {
|
||||
ip, err = externalIP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
tx := GenesisTx{
|
||||
NodeID: nodeID,
|
||||
IP: ip,
|
||||
Validator: validator,
|
||||
AppGenTx: appGenTx,
|
||||
}
|
||||
bz, err := wire.MarshalJSONIndent(cdc, tx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genTxFile := json.RawMessage(bz)
|
||||
name := fmt.Sprintf("gentx-%v.json", nodeID)
|
||||
file := filepath.Join(viper.GetString(tmcli.HomeFlag), name)
|
||||
err = cmn.WriteFile(file, bz, 0644)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// print out some key information
|
||||
toPrint := struct {
|
||||
AppMessage json.RawMessage `json:"app_message"`
|
||||
GenTxFile json.RawMessage `json:"gen_tx_file"`
|
||||
}{
|
||||
cliPrint,
|
||||
genTxFile,
|
||||
}
|
||||
out, err := wire.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
cobraCmd := cobra.Command{
|
||||
cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx)
|
||||
return cmd
|
||||
}
|
||||
|
||||
// get cmd to initialize all files for tendermint and application
|
||||
func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "init",
|
||||
Short: "Initialize genesis files",
|
||||
RunE: cmd.run,
|
||||
Short: "Initialize genesis config, priv-validator file, and p2p-node file",
|
||||
Args: cobra.NoArgs,
|
||||
RunE: func(_ *cobra.Command, _ []string) error {
|
||||
|
||||
config := ctx.Config
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
nodeID := string(nodeKey.ID())
|
||||
pubKey := readOrCreatePrivValidator(config)
|
||||
|
||||
chainID := viper.GetString(flagChainID)
|
||||
if chainID == "" {
|
||||
chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6))
|
||||
}
|
||||
|
||||
genFile := config.GenesisFile()
|
||||
if !viper.GetBool(flagOverwrite) && cmn.FileExists(genFile) {
|
||||
return fmt.Errorf("genesis.json file already exists: %v", genFile)
|
||||
}
|
||||
|
||||
// process genesis transactions, or otherwise create one for defaults
|
||||
var appMessage json.RawMessage
|
||||
var appGenTxs []json.RawMessage
|
||||
var validators []tmtypes.GenesisValidator
|
||||
var persistentPeers string
|
||||
|
||||
genTxsDir := viper.GetString(flagGenTxs)
|
||||
if genTxsDir != "" {
|
||||
validators, appGenTxs, persistentPeers, err = processGenTxs(genTxsDir, cdc, appInit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
config.P2P.PersistentPeers = persistentPeers
|
||||
configFilePath := filepath.Join(viper.GetString(tmcli.HomeFlag), "config", "config.toml") //TODO this is annoying should be easier to get
|
||||
cfg.WriteConfigFile(configFilePath, config)
|
||||
} else {
|
||||
appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey)
|
||||
appMessage = am
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
validators = []tmtypes.GenesisValidator{validator}
|
||||
appGenTxs = []json.RawMessage{appGenTx}
|
||||
}
|
||||
|
||||
appState, err := appInit.AppGenState(cdc, appGenTxs)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = writeGenesisFile(cdc, genFile, chainID, validators, appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 := wire.MarshalJSONIndent(cdc, toPrint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
return &cobraCmd
|
||||
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
|
||||
cmd.Flags().String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
||||
cmd.Flags().String(flagGenTxs, "", "directory containing the genesis transactions")
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenState)
|
||||
cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided
|
||||
cmd.AddCommand(GenTxCmd(ctx, cdc, appInit))
|
||||
return cmd
|
||||
}
|
||||
|
||||
func (c initCmd) run(cmd *cobra.Command, args []string) error {
|
||||
// Store testnet information as we go
|
||||
var testnetInfo testnetInformation
|
||||
// append a genesis-piece
|
||||
func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) (
|
||||
validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) {
|
||||
|
||||
// Run the basic tendermint initialization,
|
||||
// set up a default genesis with no app_options
|
||||
config := c.context.Config
|
||||
err := c.initTendermintFiles(config, &testnetInfo)
|
||||
// XXX sort the files by contents just incase people renamed their files
|
||||
var fos []os.FileInfo
|
||||
fos, err = ioutil.ReadDir(genTxsDir)
|
||||
if err != nil {
|
||||
return err
|
||||
return
|
||||
}
|
||||
for _, fo := range fos {
|
||||
filename := path.Join(genTxsDir, fo.Name())
|
||||
if !fo.IsDir() && (path.Ext(filename) != ".json") {
|
||||
return
|
||||
}
|
||||
|
||||
// get the genTx
|
||||
var bz []byte
|
||||
bz, err = ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
var genTx GenesisTx
|
||||
err = cdc.UnmarshalJSON(bz, &genTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// combine some stuff
|
||||
validators = append(validators, genTx.Validator)
|
||||
appGenTxs = append(appGenTxs, genTx.AppGenTx)
|
||||
|
||||
// Add a persistent peer
|
||||
comma := ","
|
||||
if len(persistentPeers) == 0 {
|
||||
comma = ""
|
||||
}
|
||||
persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, genTx.NodeID, genTx.IP)
|
||||
}
|
||||
|
||||
// no app_options, leave like tendermint
|
||||
if c.genAppState == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
// generate secret and address
|
||||
addr, secret, err := GenerateCoinKey()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var defaultDenom = "mycoin"
|
||||
|
||||
// Now, we want to add the custom app_state
|
||||
appState, err := c.genAppState(args, addr, defaultDenom)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
testnetInfo.Secret = secret
|
||||
testnetInfo.Account = addr.String()
|
||||
|
||||
// And add them to the genesis file
|
||||
genFile := config.GenesisFile()
|
||||
if err := addGenesisState(genFile, appState); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
testnetInfo.NodeID = nodeKey.ID()
|
||||
out, err := wire.MarshalJSONIndent(cdc, testnetInfo)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(out))
|
||||
return nil
|
||||
return
|
||||
}
|
||||
|
||||
// This was copied from tendermint/cmd/tendermint/commands/init.go
|
||||
// so we could pass in the config and the logger.
|
||||
func (c initCmd) initTendermintFiles(config *cfg.Config, info *testnetInformation) error {
|
||||
//________________________________________________________________________________________
|
||||
|
||||
// read of create the private key file for this config
|
||||
func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey {
|
||||
// private validator
|
||||
privValFile := config.PrivValidatorFile()
|
||||
privValFile := tmConfig.PrivValidatorFile()
|
||||
var privValidator *pvm.FilePV
|
||||
if cmn.FileExists(privValFile) {
|
||||
privValidator = pvm.LoadFilePV(privValFile)
|
||||
c.context.Logger.Info("Found private validator", "path", privValFile)
|
||||
} else {
|
||||
privValidator = pvm.GenFilePV(privValFile)
|
||||
privValidator.Save()
|
||||
c.context.Logger.Info("Generated private validator", "path", privValFile)
|
||||
}
|
||||
|
||||
// genesis file
|
||||
genFile := config.GenesisFile()
|
||||
if cmn.FileExists(genFile) {
|
||||
c.context.Logger.Info("Found genesis file", "path", genFile)
|
||||
} else {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)),
|
||||
}
|
||||
genDoc.Validators = []tmtypes.GenesisValidator{{
|
||||
PubKey: privValidator.GetPubKey(),
|
||||
Power: 10,
|
||||
}}
|
||||
|
||||
if err := genDoc.SaveAs(genFile); err != nil {
|
||||
return err
|
||||
}
|
||||
c.context.Logger.Info("Generated genesis file", "path", genFile)
|
||||
}
|
||||
|
||||
// reload the config file and find our validator info
|
||||
loadedDoc, err := tmtypes.GenesisDocFromFile(genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, validator := range loadedDoc.Validators {
|
||||
if validator.PubKey == privValidator.GetPubKey() {
|
||||
info.Validator = validator
|
||||
}
|
||||
}
|
||||
info.ChainID = loadedDoc.ChainID
|
||||
|
||||
return nil
|
||||
return privValidator.GetPubKey()
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// GenAppState takes the command line args, as well
|
||||
// as an address and coin denomination.
|
||||
// It returns a default app_state to be included in
|
||||
// in the genesis file.
|
||||
// This is application-specific
|
||||
type GenAppState func(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error)
|
||||
|
||||
// DefaultGenAppState expects two args: an account address
|
||||
// and a coin denomination, and gives lots of coins to that address.
|
||||
func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) {
|
||||
opts := fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "%s",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, addr.String(), coinDenom)
|
||||
return json.RawMessage(opts), nil
|
||||
// create the genesis file
|
||||
func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error {
|
||||
genDoc := tmtypes.GenesisDoc{
|
||||
ChainID: chainID,
|
||||
Validators: validators,
|
||||
}
|
||||
if err := genDoc.ValidateAndComplete(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := genDoc.SaveAs(genesisFile); err != nil {
|
||||
return err
|
||||
}
|
||||
return addAppStateToGenesis(cdc, genesisFile, appState)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
// GenesisDoc involves some tendermint-specific structures we don't
|
||||
// want to parse, so we just grab it into a raw object format,
|
||||
// so we can add one line.
|
||||
type GenesisDoc map[string]json.RawMessage
|
||||
|
||||
func addGenesisState(filename string, appState json.RawMessage) error {
|
||||
bz, err := ioutil.ReadFile(filename)
|
||||
// Add one line to the genesis file
|
||||
func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState json.RawMessage) error {
|
||||
bz, err := ioutil.ReadFile(genesisConfigPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var doc GenesisDoc
|
||||
err = cdc.UnmarshalJSON(bz, &doc)
|
||||
out, err := AppendJSON(cdc, bz, "app_state", appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
doc["app_state"] = appState
|
||||
out, err := wire.MarshalJSONIndent(cdc, doc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return ioutil.WriteFile(filename, out, 0600)
|
||||
return ioutil.WriteFile(genesisConfigPath, out, 0600)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
//_____________________________________________________________________
|
||||
|
||||
// GenerateCoinKey returns the address of a public key,
|
||||
// along with the secret phrase to recover the private key.
|
||||
// You can give coins to this address and return the recovery
|
||||
// phrase to the user to access them.
|
||||
// Core functionality passed from the application to the server init command
|
||||
type AppInit struct {
|
||||
|
||||
// flags required for application init functions
|
||||
FlagsAppGenState *pflag.FlagSet
|
||||
FlagsAppGenTx *pflag.FlagSet
|
||||
|
||||
// create the application genesis tx
|
||||
AppGenTx func(cdc *wire.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error)
|
||||
|
||||
// AppGenState creates the core parameters initialization. It takes in a
|
||||
// pubkey meant to represent the pubkey of the validator of this machine.
|
||||
AppGenState func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error)
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
||||
// simple default application init
|
||||
var DefaultAppInit = AppInit{
|
||||
AppGenTx: SimpleAppGenTx,
|
||||
AppGenState: SimpleAppGenState,
|
||||
}
|
||||
|
||||
// simple genesis tx
|
||||
type SimpleGenTx struct {
|
||||
Addr sdk.Address `json:"addr"`
|
||||
}
|
||||
|
||||
// Generate a genesis transaction
|
||||
func SimpleAppGenTx(cdc *wire.Codec, pk crypto.PubKey) (
|
||||
appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) {
|
||||
|
||||
var addr sdk.Address
|
||||
var secret string
|
||||
addr, secret, err = GenerateCoinKey()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
var bz []byte
|
||||
simpleGenTx := SimpleGenTx{addr}
|
||||
bz, err = cdc.MarshalJSON(simpleGenTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
appGenTx = json.RawMessage(bz)
|
||||
|
||||
mm := map[string]string{"secret": secret}
|
||||
bz, err = cdc.MarshalJSON(mm)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
cliPrint = json.RawMessage(bz)
|
||||
|
||||
validator = tmtypes.GenesisValidator{
|
||||
PubKey: pk,
|
||||
Power: 10,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// create the genesis app state
|
||||
func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) {
|
||||
|
||||
if len(appGenTxs) != 1 {
|
||||
err = errors.New("must provide a single genesis transaction")
|
||||
return
|
||||
}
|
||||
|
||||
var genTx SimpleGenTx
|
||||
err = cdc.UnmarshalJSON(appGenTxs[0], &genTx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
appState = json.RawMessage(fmt.Sprintf(`{
|
||||
"accounts": [{
|
||||
"address": "%s",
|
||||
"coins": [
|
||||
{
|
||||
"denom": "mycoin",
|
||||
"amount": 9007199254740992
|
||||
}
|
||||
]
|
||||
}]
|
||||
}`, genTx.Addr.String()))
|
||||
return
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________________
|
||||
|
||||
// GenerateCoinKey returns the address of a public key, along with the secret
|
||||
// phrase to recover the private key.
|
||||
func GenerateCoinKey() (sdk.Address, string, error) {
|
||||
|
||||
// construct an in-memory key store
|
||||
codec, err := words.LoadCodec("english")
|
||||
if err != nil {
|
||||
|
@ -231,7 +401,33 @@ func GenerateCoinKey() (sdk.Address, string, error) {
|
|||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
addr := info.PubKey.Address()
|
||||
return addr, secret, nil
|
||||
}
|
||||
|
||||
// GenerateSaveCoinKey returns the address of a public key, along with the secret
|
||||
// phrase to recover the private key.
|
||||
func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (sdk.Address, string, error) {
|
||||
|
||||
// get the keystore from the client
|
||||
keybase, err := clkeys.GetKeyBaseFromDir(clientRoot)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
// ensure no overwrite
|
||||
if !overwrite {
|
||||
_, err := keybase.Get(keyName)
|
||||
if err == nil {
|
||||
return nil, "", errors.New("key already exists, overwrite is disabled")
|
||||
}
|
||||
}
|
||||
|
||||
// generate a private key, with recovery phrase
|
||||
info, secret, err := keybase.Create(keyName, keyPass, keys.AlgoEd25519)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
addr := info.PubKey.Address()
|
||||
return addr, secret, nil
|
||||
}
|
||||
|
|
|
@ -8,17 +8,36 @@ import (
|
|||
"github.com/tendermint/tmlibs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/mock"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
)
|
||||
|
||||
func TestInit(t *testing.T) {
|
||||
// TODO update
|
||||
func TestInitCmd(t *testing.T) {
|
||||
defer setupViper(t)()
|
||||
|
||||
logger := log.NewNopLogger()
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
cmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
cdc := wire.NewCodec()
|
||||
appInit := AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
cmd := InitCmd(ctx, cdc, appInit)
|
||||
err = cmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGenTxCmd(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestSimpleAppGenTx(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
func TestSimpleAppGenState(t *testing.T) {
|
||||
// TODO
|
||||
}
|
||||
|
|
|
@ -27,45 +27,34 @@ type AppCreator func(string, log.Logger) (abci.Application, error)
|
|||
|
||||
// StartCmd runs the service passed in, either
|
||||
// stand-alone, or in-process with tendermint
|
||||
func StartCmd(app AppCreator, ctx *Context) *cobra.Command {
|
||||
start := startCmd{
|
||||
appCreator: app,
|
||||
context: ctx,
|
||||
}
|
||||
func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "start",
|
||||
Short: "Run the full node",
|
||||
RunE: start.run,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if !viper.GetBool(flagWithTendermint) {
|
||||
ctx.Logger.Info("Starting ABCI without Tendermint")
|
||||
return startStandAlone(ctx, appCreator)
|
||||
}
|
||||
ctx.Logger.Info("Starting ABCI with Tendermint")
|
||||
return startInProcess(ctx, appCreator)
|
||||
},
|
||||
}
|
||||
|
||||
// basic flags for abci app
|
||||
cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint")
|
||||
cmd.Flags().String(flagAddress, "tcp://0.0.0.0:46658", "Listen address")
|
||||
|
||||
// AddNodeFlags adds support for all
|
||||
// tendermint-specific command line options
|
||||
// AddNodeFlags adds support for all tendermint-specific command line options
|
||||
tcmd.AddNodeFlags(cmd)
|
||||
return cmd
|
||||
}
|
||||
|
||||
type startCmd struct {
|
||||
appCreator AppCreator
|
||||
context *Context
|
||||
}
|
||||
|
||||
func (s startCmd) run(cmd *cobra.Command, args []string) error {
|
||||
if !viper.GetBool(flagWithTendermint) {
|
||||
s.context.Logger.Info("Starting ABCI without Tendermint")
|
||||
return s.startStandAlone()
|
||||
}
|
||||
s.context.Logger.Info("Starting ABCI with Tendermint")
|
||||
return s.startInProcess()
|
||||
}
|
||||
|
||||
func (s startCmd) startStandAlone() error {
|
||||
func startStandAlone(ctx *Context, appCreator AppCreator) error {
|
||||
// Generate the app in the proper dir
|
||||
addr := viper.GetString(flagAddress)
|
||||
home := viper.GetString("home")
|
||||
app, err := s.appCreator(home, s.context.Logger)
|
||||
app, err := appCreator(home, ctx.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -74,7 +63,7 @@ func (s startCmd) startStandAlone() error {
|
|||
if err != nil {
|
||||
return errors.Errorf("Error creating listener: %v\n", err)
|
||||
}
|
||||
svr.SetLogger(s.context.Logger.With("module", "abci-server"))
|
||||
svr.SetLogger(ctx.Logger.With("module", "abci-server"))
|
||||
svr.Start()
|
||||
|
||||
// Wait forever
|
||||
|
@ -85,10 +74,10 @@ func (s startCmd) startStandAlone() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s startCmd) startInProcess() error {
|
||||
cfg := s.context.Config
|
||||
func startInProcess(ctx *Context, appCreator AppCreator) error {
|
||||
cfg := ctx.Config
|
||||
home := cfg.RootDir
|
||||
app, err := s.appCreator(home, s.context.Logger)
|
||||
app, err := appCreator(home, ctx.Logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -99,7 +88,7 @@ func (s startCmd) startInProcess() error {
|
|||
proxy.NewLocalClientCreator(app),
|
||||
node.DefaultGenesisDocProviderFunc(cfg),
|
||||
node.DefaultDBProvider,
|
||||
s.context.Logger.With("module", "node"))
|
||||
ctx.Logger.With("module", "node"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/mock"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/tendermint/abci/server"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
|
@ -25,7 +26,12 @@ func TestStartStandAlone(t *testing.T) {
|
|||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
cdc := wire.NewCodec()
|
||||
appInit := AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
initCmd := InitCmd(ctx, cdc, appInit)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
|
@ -51,13 +57,18 @@ func TestStartWithTendermint(t *testing.T) {
|
|||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
ctx := NewContext(cfg, logger)
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
cdc := wire.NewCodec()
|
||||
appInit := AppInit{
|
||||
AppGenState: mock.AppGenState,
|
||||
AppGenTx: mock.AppGenTx,
|
||||
}
|
||||
initCmd := InitCmd(ctx, cdc, appInit)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// set up app and start up
|
||||
viper.Set(flagWithTendermint, true)
|
||||
startCmd := StartCmd(mock.NewApp, ctx)
|
||||
startCmd := StartCmd(ctx, mock.NewApp)
|
||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
||||
timeout := time.Duration(5) * time.Second
|
||||
|
||||
|
|
|
@ -8,13 +8,10 @@ import (
|
|||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/mock"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
"github.com/tendermint/tmlibs/log"
|
||||
)
|
||||
|
||||
// Get a free address for a test tendermint server
|
||||
|
@ -40,30 +37,6 @@ func setupViper(t *testing.T) func() {
|
|||
}
|
||||
}
|
||||
|
||||
// Begin the server pass up the channel to close
|
||||
// NOTE pass up the channel so it can be closed at the end of the process
|
||||
func StartServer(t *testing.T) chan error {
|
||||
defer setupViper(t)()
|
||||
|
||||
cfg, err := tcmd.ParseConfig()
|
||||
require.Nil(t, err)
|
||||
|
||||
// init server
|
||||
ctx := NewContext(cfg, log.NewNopLogger())
|
||||
initCmd := InitCmd(mock.GenInitOptions, ctx)
|
||||
err = initCmd.RunE(nil, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// start server
|
||||
viper.Set(flagWithTendermint, true)
|
||||
startCmd := StartCmd(mock.NewApp, ctx)
|
||||
startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address
|
||||
startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address
|
||||
timeout := time.Duration(3) * time.Second
|
||||
|
||||
return RunOrTimeout(startCmd, timeout, t)
|
||||
}
|
||||
|
||||
// Run or Timout RunE of command passed in
|
||||
func RunOrTimeout(cmd *cobra.Command, timeout time.Duration, t *testing.T) chan error {
|
||||
done := make(chan error)
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
|
@ -35,7 +36,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
flagJSON := "json"
|
||||
cmd := cobra.Command{
|
||||
Use: "show_validator",
|
||||
Short: "Show this node's validator info",
|
||||
Short: "Show this node's tendermint validator info",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
cfg := ctx.Config
|
||||
|
@ -43,6 +44,9 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
pubKey := privValidator.PubKey
|
||||
|
||||
if viper.GetBool(flagJSON) {
|
||||
|
||||
cdc := wire.NewCodec()
|
||||
wire.RegisterCrypto(cdc)
|
||||
pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -63,7 +67,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command {
|
|||
func UnsafeResetAllCmd(ctx *Context) *cobra.Command {
|
||||
return &cobra.Command{
|
||||
Use: "unsafe_reset_all",
|
||||
Short: "Reset all blockchain data",
|
||||
Short: "Reset blockchain database, priv_validator.json file, and the logger",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
cfg := ctx.Config
|
||||
tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
|
||||
cfg "github.com/tendermint/tendermint/config"
|
||||
"github.com/tendermint/tmlibs/cli"
|
||||
|
@ -31,7 +35,7 @@ func NewContext(config *cfg.Config, logger log.Logger) *Context {
|
|||
return &Context{config, logger}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// PersistentPreRunEFn returns a PersistentPreRunE function for cobra
|
||||
// that initailizes the passed in context with a properly configured
|
||||
|
@ -62,18 +66,71 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error
|
|||
|
||||
// add server commands
|
||||
func AddCommands(
|
||||
rootCmd *cobra.Command,
|
||||
appState GenAppState, appCreator AppCreator,
|
||||
context *Context) {
|
||||
ctx *Context, cdc *wire.Codec,
|
||||
rootCmd *cobra.Command, appInit AppInit,
|
||||
appCreator AppCreator) {
|
||||
|
||||
rootCmd.PersistentFlags().String("log_level", context.Config.LogLevel, "Log level")
|
||||
rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level")
|
||||
|
||||
rootCmd.AddCommand(
|
||||
InitCmd(appState, context),
|
||||
StartCmd(appCreator, context),
|
||||
UnsafeResetAllCmd(context),
|
||||
ShowNodeIDCmd(context),
|
||||
ShowValidatorCmd(context),
|
||||
InitCmd(ctx, cdc, appInit),
|
||||
StartCmd(ctx, appCreator),
|
||||
UnsafeResetAllCmd(ctx),
|
||||
ShowNodeIDCmd(ctx),
|
||||
ShowValidatorCmd(ctx),
|
||||
version.VersionCmd,
|
||||
)
|
||||
}
|
||||
|
||||
//___________________________________________________________________________________
|
||||
|
||||
// append a new json field to existing json message
|
||||
func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) {
|
||||
var jsonMap map[string]json.RawMessage
|
||||
err = cdc.UnmarshalJSON(baseJSON, &jsonMap)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
jsonMap[key] = value
|
||||
bz, err := wire.MarshalJSONIndent(cdc, jsonMap)
|
||||
return json.RawMessage(bz), err
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go
|
||||
// TODO there must be a better way to get external IP
|
||||
func externalIP() (string, error) {
|
||||
ifaces, err := net.Interfaces()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, iface := range ifaces {
|
||||
if iface.Flags&net.FlagUp == 0 {
|
||||
continue // interface down
|
||||
}
|
||||
if iface.Flags&net.FlagLoopback != 0 {
|
||||
continue // loopback interface
|
||||
}
|
||||
addrs, err := iface.Addrs()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
for _, addr := range addrs {
|
||||
var ip net.IP
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
ip = v.IP
|
||||
case *net.IPAddr:
|
||||
ip = v.IP
|
||||
}
|
||||
if ip == nil || ip.IsLoopback() {
|
||||
continue
|
||||
}
|
||||
ip = ip.To4()
|
||||
if ip == nil {
|
||||
continue // not an ipv4 address
|
||||
}
|
||||
return ip.String(), nil
|
||||
}
|
||||
}
|
||||
return "", errors.New("are you connected to the network?")
|
||||
}
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestAppendJSON(t *testing.T) {
|
||||
cdc := wire.NewCodec()
|
||||
|
||||
foo := map[string]string{"foo": "foofoo"}
|
||||
bar := map[string]string{"barInner": "barbar"}
|
||||
|
||||
// create raw messages
|
||||
bz, err := cdc.MarshalJSON(foo)
|
||||
require.NoError(t, err)
|
||||
fooRaw := json.RawMessage(bz)
|
||||
|
||||
bz, err = cdc.MarshalJSON(bar)
|
||||
require.NoError(t, err)
|
||||
barRaw := json.RawMessage(bz)
|
||||
|
||||
// make the append
|
||||
appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw)
|
||||
require.NoError(t, err)
|
||||
|
||||
// test the append
|
||||
var appended map[string]json.RawMessage
|
||||
err = cdc.UnmarshalJSON(appBz, &appended)
|
||||
require.NoError(t, err)
|
||||
|
||||
var resBar map[string]string
|
||||
err = cdc.UnmarshalJSON(appended["barOuter"], &resBar)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, bar, resBar, "appended: %v", appended)
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package server
|
||||
|
||||
import (
|
||||
"github.com/cosmos/cosmos-sdk/wire"
|
||||
)
|
||||
|
||||
var cdc *wire.Codec
|
||||
|
||||
func init() {
|
||||
cdc = wire.NewCodec()
|
||||
wire.RegisterCrypto(cdc)
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
@ -27,13 +26,11 @@ func getCmd(t *testing.T, command string) *exec.Cmd {
|
|||
}
|
||||
|
||||
// Execute the command, return standard output and error, try a few times if requested
|
||||
func ExecuteT(t *testing.T, command string, trials int) (out string) {
|
||||
func ExecuteT(t *testing.T, command string) (out string) {
|
||||
cmd := getCmd(t, command)
|
||||
bz, err := cmd.CombinedOutput()
|
||||
if err != nil && trials > 1 {
|
||||
fmt.Printf("trial %v, retrying: %v\n", trials, command)
|
||||
time.Sleep(time.Second * 10)
|
||||
return ExecuteT(t, command, trials-1)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
require.NoError(t, err, string(bz))
|
||||
out = strings.Trim(string(bz), "\n") //trim any new lines
|
||||
|
@ -48,7 +45,7 @@ func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteClo
|
|||
require.NoError(t, err)
|
||||
pipeOut, err = cmd.StdoutPipe()
|
||||
require.NoError(t, err)
|
||||
go cmd.Start()
|
||||
cmd.Start()
|
||||
time.Sleep(time.Second)
|
||||
return cmd, pipeIn, pipeOut
|
||||
}
|
||||
|
|
|
@ -0,0 +1,107 @@
|
|||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
amino "github.com/tendermint/go-amino"
|
||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||
rpcclient "github.com/tendermint/tendermint/rpc/lib/client"
|
||||
)
|
||||
|
||||
// TODO: these functions just print to Stdout.
|
||||
// consider using the logger.
|
||||
|
||||
// Uses localhost
|
||||
func WaitForHeight(height int64, port string) {
|
||||
for {
|
||||
var resultBlock ctypes.ResultBlock
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= height {
|
||||
return
|
||||
}
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
|
||||
// wait for 2 blocks.
|
||||
// uses localhost
|
||||
func WaitForStart(port string) {
|
||||
waitHeight := int64(2)
|
||||
for {
|
||||
time.Sleep(time.Second)
|
||||
|
||||
url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest")
|
||||
res, err := http.Get(url)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// waiting for server to start ...
|
||||
if res.StatusCode != http.StatusOK {
|
||||
res.Body.Close()
|
||||
continue
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(res.Body)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
res.Body.Close()
|
||||
|
||||
resultBlock := new(ctypes.ResultBlock)
|
||||
err = cdc.UnmarshalJSON([]byte(body), &resultBlock)
|
||||
if err != nil {
|
||||
fmt.Println("RES", res)
|
||||
fmt.Println("BODY", string(body))
|
||||
panic(err)
|
||||
}
|
||||
|
||||
if resultBlock.Block.Height >= waitHeight {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the RPC server to respond to /status
|
||||
func WaitForRPC(laddr string) {
|
||||
fmt.Println("LADDR", laddr)
|
||||
client := rpcclient.NewJSONRPCClient(laddr)
|
||||
ctypes.RegisterAmino(client.Codec())
|
||||
result := new(ctypes.ResultStatus)
|
||||
for {
|
||||
_, err := client.Call("status", map[string]interface{}{}, result)
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
fmt.Printf("Waiting for RPC server to start on %s:%v\n", laddr, err)
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
|
||||
func init() {
|
||||
ctypes.RegisterAmino(cdc)
|
||||
}
|
|
@ -4,7 +4,6 @@ import (
|
|||
"encoding/hex"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/context"
|
||||
|
@ -32,56 +31,40 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder {
|
|||
// GetAccountCmd returns a query account that will display the
|
||||
// state of the account at a given address
|
||||
func GetAccountCmd(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) *cobra.Command {
|
||||
cmdr := commander{
|
||||
storeName,
|
||||
cdc,
|
||||
decoder,
|
||||
}
|
||||
return &cobra.Command{
|
||||
Use: "account <address>",
|
||||
Use: "account [address]",
|
||||
Short: "Query account balance",
|
||||
RunE: cmdr.getAccountCmd,
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
// find the key to look up the account
|
||||
addr := args[0]
|
||||
bz, err := hex.DecodeString(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := sdk.Address(bz)
|
||||
|
||||
// perform query
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
res, err := ctx.Query(key, storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// decode the value
|
||||
account, err := decoder(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// print out whole account
|
||||
output, err := wire.MarshalJSONIndent(cdc, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
type commander struct {
|
||||
storeName string
|
||||
cdc *wire.Codec
|
||||
decoder sdk.AccountDecoder
|
||||
}
|
||||
|
||||
func (c commander) getAccountCmd(cmd *cobra.Command, args []string) error {
|
||||
if len(args) != 1 || len(args[0]) == 0 {
|
||||
return errors.New("You must provide an account name")
|
||||
}
|
||||
|
||||
// find the key to look up the account
|
||||
addr := args[0]
|
||||
bz, err := hex.DecodeString(addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
key := sdk.Address(bz)
|
||||
|
||||
ctx := context.NewCoreContextFromViper()
|
||||
|
||||
res, err := ctx.Query(key, c.storeName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// decode the value
|
||||
account, err := c.decoder(res)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// print out whole account
|
||||
output, err := wire.MarshalJSONIndent(c.cdc, account)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println(string(output))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -52,6 +52,9 @@ func NewEndBlocker(k Keeper) sdk.EndBlocker {
|
|||
func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) {
|
||||
k.setPool(ctx, data.Pool)
|
||||
k.setParams(ctx, data.Params)
|
||||
for _, candidate := range data.Candidates {
|
||||
k.setCandidate(ctx, candidate)
|
||||
}
|
||||
}
|
||||
|
||||
//_____________________________________________________________________
|
||||
|
|
|
@ -9,8 +9,9 @@ import (
|
|||
|
||||
// GenesisState - all staking state that must be provided at genesis
|
||||
type GenesisState struct {
|
||||
Pool Pool `json:"pool"`
|
||||
Params Params `json:"params"`
|
||||
Pool Pool `json:"pool"`
|
||||
Params Params `json:"params"`
|
||||
Candidates []Candidate `json:"candidates"`
|
||||
}
|
||||
|
||||
//_________________________________________________________________________
|
||||
|
|
Loading…
Reference in New Issue