Merge pull request #889 from cosmos/rigel/878-better-init

Better init
This commit is contained in:
Christopher Goes 2018-04-26 21:17:57 +02:00 committed by GitHub
commit b4af0916b3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1050 additions and 580 deletions

View File

@ -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`

View File

@ -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:

View File

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

View File

@ -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

View File

@ -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
}
}
}

View File

@ -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]

View File

@ -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
}

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

@ -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
}

View File

@ -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
}

View File

@ -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)

View File

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

View File

@ -1,7 +1,6 @@
package main
import (
"os"
"path/filepath"
"github.com/spf13/cobra"
@ -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()
}

View File

@ -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, "")

View File

@ -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()
}

View File

@ -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, "")

View File

@ -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")

View File

@ -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
}

View File

@ -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()

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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?")
}

41
server/util_test.go Normal file
View File

@ -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)
}

View File

@ -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)
}

View File

@ -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
}

107
tests/util.go Normal file
View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}
}
//_____________________________________________________________________

View File

@ -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"`
}
//_________________________________________________________________________