add 0.34 gaia

This commit is contained in:
rhuairahrighairigh 2019-06-20 14:37:57 +01:00
parent 061c27bbc6
commit 76a7f3dd57
36 changed files with 5867 additions and 562 deletions

View File

@ -1,254 +0,0 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package app
import (
"io"
"os"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrclient "github.com/cosmos/cosmos-sdk/x/distribution/client"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
paramsclient "github.com/cosmos/cosmos-sdk/x/params/client"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const appName = "KavaApp"
var (
// default home directories for cli
DefaultCLIHome = os.ExpandEnv("$HOME/.kvcli")
// default home directories for daemon
DefaultNodeHome = os.ExpandEnv("$HOME/.kvd")
// The ModuleBasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration
// and genesis verification.
ModuleBasics module.BasicManager
)
func init() {
ModuleBasics = module.NewBasicManager(
genaccounts.AppModuleBasic{},
genutil.AppModuleBasic{},
auth.AppModuleBasic{},
bank.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.NewAppModuleBasic(paramsclient.ProposalHandler, distrclient.ProposalHandler),
params.AppModuleBasic{},
crisis.AppModuleBasic{},
slashing.AppModuleBasic{},
)
}
// custom tx codec
func MakeCodec() *codec.Codec {
var cdc = codec.New()
ModuleBasics.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
return cdc
}
// SetAddressPrefixes sets the bech32 address prefixes on an sdk config.
func SetAddressPrefixes(config *sdk.Config) {
config.SetBech32PrefixForAccount("k", "k"+"pub")
config.SetBech32PrefixForValidator("k"+"val"+"oper", "k"+"val"+"oper"+"pub")
config.SetBech32PrefixForConsensusNode("k"+"val"+"cons", "k"+"val"+"cons"+"pub")
}
// Extended ABCI application
type App struct {
*bam.BaseApp
cdc *codec.Codec
invCheckPeriod uint
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyMint *sdk.KVStoreKey
keyDistr *sdk.KVStoreKey
tkeyDistr *sdk.TransientStoreKey
keyGov *sdk.KVStoreKey
keyFeeCollection *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// keepers
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
mintKeeper mint.Keeper
distrKeeper distr.Keeper
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
// the module manager
mm *module.Manager
}
// NewApp returns a reference to an initialized App.
func NewApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp)) *App {
cdc := MakeCodec()
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
bApp.SetAppVersion(version.Version)
var app = &App{
BaseApp: bApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
keyFeeCollection: sdk.NewKVStoreKey(auth.FeeStoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
}
// init params keeper and subspaces
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams, params.DefaultCodespace)
authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace)
bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace)
stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace)
mintSubspace := app.paramsKeeper.Subspace(mint.DefaultParamspace)
distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace)
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace)
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
// add keepers
app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.keyAccount, authSubspace, auth.ProtoBaseAccount)
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace)
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper,
stakingSubspace, staking.DefaultCodespace)
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.feeCollectionKeeper)
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, app.bankKeeper, &stakingKeeper,
app.feeCollectionKeeper, distr.DefaultCodespace)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, &stakingKeeper,
slashingSubspace, slashing.DefaultCodespace)
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.distrKeeper,
app.bankKeeper, app.feeCollectionKeeper)
// register the proposal types
govRouter := gov.NewRouter()
govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler).
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)).
AddRoute(distr.RouterKey, distr.NewCommunityPoolSpendProposalHandler(app.distrKeeper))
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper, govSubspace,
app.bankKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
// register the staking hooks
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.stakingKeeper = *stakingKeeper.SetHooks(
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
app.mm = module.NewManager(
genaccounts.NewAppModule(app.accountKeeper),
genutil.NewAppModule(app.accountKeeper, app.stakingKeeper, app.BaseApp.DeliverTx),
auth.NewAppModule(app.accountKeeper, app.feeCollectionKeeper),
bank.NewAppModule(app.bankKeeper, app.accountKeeper),
crisis.NewAppModule(app.crisisKeeper, app.Logger()),
distr.NewAppModule(app.distrKeeper),
gov.NewAppModule(app.govKeeper),
mint.NewAppModule(app.mintKeeper),
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
staking.NewAppModule(app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
)
// During begin block slashing happens after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool, so as to keep the
// CanWithdrawInvariant invariant.
app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName)
app.mm.SetOrderEndBlockers(gov.ModuleName, staking.ModuleName)
// genutils must occur after staking so that pools are properly
// initialized with tokens from genesis accounts.
app.mm.SetOrderInitGenesis(genaccounts.ModuleName, distr.ModuleName,
staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName,
gov.ModuleName, mint.ModuleName, crisis.ModuleName, genutil.ModuleName)
app.mm.RegisterInvariants(&app.crisisKeeper)
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
// initialize stores
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint,
app.keyDistr, app.keySlashing, app.keyGov, app.keyFeeCollection,
app.keyParams, app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
// initialize BaseApp
app.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper, auth.DefaultSigVerificationGasConsumer))
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
}
return app
}
// application updates every begin block
func (app *App) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
return app.mm.BeginBlock(ctx, req)
}
// application updates every end block
func (app *App) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
return app.mm.EndBlock(ctx, req)
}
// application update at chain initialization
func (app *App) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
var genesisState GenesisState
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
return app.mm.InitGenesis(ctx, genesisState)
}
// load a particular height
func (app *App) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keyMain)
}

View File

@ -1,22 +0,0 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package app
import (
"encoding/json"
)
// The genesis state of the blockchain is represented here as a map of raw json
// messages key'd by a identifier string.
// The identifier is used to determine which module genesis information belongs
// to so it may be appropriately routed during init chain.
// Within this application default genesis information is retrieved from
// the ModuleBasicManager which populates json from each BasicModule
// object provided to it during init.
type GenesisState map[string]json.RawMessage
// NewDefaultGenesisState generates the default state for gaia.
func NewDefaultGenesisState() GenesisState {
return ModuleBasics.DefaultGenesis()
}

408
gaia/app/app.go Normal file
View File

@ -0,0 +1,408 @@
package app
import (
"fmt"
"io"
"os"
"sort"
abci "github.com/tendermint/tendermint/abci/types"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
appName = "GaiaApp"
// DefaultKeyPass contains the default key password for genesis transactions
DefaultKeyPass = "12345678"
)
// 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
cdc *codec.Codec
invCheckPeriod uint
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyMint *sdk.KVStoreKey
keyDistr *sdk.KVStoreKey
tkeyDistr *sdk.TransientStoreKey
keyGov *sdk.KVStoreKey
keyFeeCollection *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// Manage getting and setting accounts
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
mintKeeper mint.Keeper
distrKeeper distr.Keeper
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
}
// NewGaiaApp returns a reference to an initialized GaiaApp.
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
invCheckPeriod uint,
baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
cdc := MakeCodec()
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(traceStore)
var app = &GaiaApp{
BaseApp: bApp,
cdc: cdc,
invCheckPeriod: invCheckPeriod,
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keyMint: sdk.NewKVStoreKey(mint.StoreKey),
keyDistr: sdk.NewKVStoreKey(distr.StoreKey),
tkeyDistr: sdk.NewTransientStoreKey(distr.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyGov: sdk.NewKVStoreKey(gov.StoreKey),
keyFeeCollection: sdk.NewKVStoreKey(auth.FeeStoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
}
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
// define the accountKeeper
app.accountKeeper = auth.NewAccountKeeper(
app.cdc,
app.keyAccount,
app.paramsKeeper.Subspace(auth.DefaultParamspace),
auth.ProtoBaseAccount,
)
// add handlers
app.bankKeeper = bank.NewBaseKeeper(
app.accountKeeper,
app.paramsKeeper.Subspace(bank.DefaultParamspace),
bank.DefaultCodespace,
)
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
app.cdc,
app.keyFeeCollection,
)
stakingKeeper := staking.NewKeeper(
app.cdc,
app.keyStaking, app.tkeyStaking,
app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace),
staking.DefaultCodespace,
)
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
app.paramsKeeper.Subspace(mint.DefaultParamspace),
&stakingKeeper, app.feeCollectionKeeper,
)
app.distrKeeper = distr.NewKeeper(
app.cdc,
app.keyDistr,
app.paramsKeeper.Subspace(distr.DefaultParamspace),
app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper,
distr.DefaultCodespace,
)
app.slashingKeeper = slashing.NewKeeper(
app.cdc,
app.keySlashing,
&stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
slashing.DefaultCodespace,
)
app.govKeeper = gov.NewKeeper(
app.cdc,
app.keyGov,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
gov.DefaultCodespace,
)
app.crisisKeeper = crisis.NewKeeper(
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
app.distrKeeper,
app.bankKeeper,
app.feeCollectionKeeper,
)
// register the staking hooks
// NOTE: The stakingKeeper above is passed by reference, so that it can be
// modified like below:
app.stakingKeeper = *stakingKeeper.SetHooks(
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
)
// register the crisis routes
bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper)
distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper)
staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper)
// register message routes
app.Router().
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)).
AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper))
app.QueryRouter().
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)).
AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc)).
AddRoute(mint.QuerierRoute, mint.NewQuerier(app.mintKeeper))
// initialize BaseApp
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams,
app.tkeyParams, app.tkeyStaking, app.tkeyDistr,
)
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
app.SetEndBlocker(app.EndBlocker)
if loadLatest {
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
}
return app
}
// custom tx codec
func MakeCodec() *codec.Codec {
var cdc = codec.New()
bank.RegisterCodec(cdc)
staking.RegisterCodec(cdc)
distr.RegisterCodec(cdc)
slashing.RegisterCodec(cdc)
gov.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
crisis.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
return cdc
}
// application updates every end block
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
// mint new tokens for the previous block
mint.BeginBlocker(ctx, app.mintKeeper)
// distribute rewards for the previous block
distr.BeginBlocker(ctx, req, app.distrKeeper)
// slash anyone who double signed.
// NOTE: This should happen after distr.BeginBlocker so that
// there is nothing left over in the validator fee pool,
// so as to keep the CanWithdrawInvariant invariant.
// TODO: This should really happen at EndBlocker.
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
return abci.ResponseBeginBlock{
Tags: tags.ToKVPairs(),
}
}
// application updates every end block
// nolint: unparam
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
tags := gov.EndBlocker(ctx, app.govKeeper)
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
tags = append(tags, endBlockerTags...)
if app.invCheckPeriod != 0 && ctx.BlockHeight()%int64(app.invCheckPeriod) == 0 {
app.assertRuntimeInvariants()
}
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
Tags: tags,
}
}
// initialize store from a genesis state
func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisState) []abci.ValidatorUpdate {
genesisState.Sanitize()
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
acc = app.accountKeeper.NewAccount(ctx, acc) // set account number
app.accountKeeper.SetAccount(ctx, acc)
}
// initialize distribution (must happen before staking)
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
// load the initial staking information
validators, err := staking.InitGenesis(ctx, app.stakingKeeper, genesisState.StakingData)
if err != nil {
panic(err) // TODO find a way to do this w/o panics
}
// initialize module-specific stores
auth.InitGenesis(ctx, app.accountKeeper, app.feeCollectionKeeper, genesisState.AuthData)
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData)
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
// validate genesis state
if err := GaiaValidateGenesisState(genesisState); err != nil {
panic(err) // TODO find a way to do this w/o panics
}
if len(genesisState.GenTxs) > 0 {
for _, genTx := range genesisState.GenTxs {
var tx auth.StdTx
err = app.cdc.UnmarshalJSON(genTx, &tx)
if err != nil {
panic(err)
}
bz := app.cdc.MustMarshalBinaryLengthPrefixed(tx)
res := app.BaseApp.DeliverTx(bz)
if !res.IsOK() {
panic(res.Log)
}
}
validators = app.stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}
return validators
}
// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
// TODO is this now the whole genesis file?
var genesisState 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, "")
}
validators := app.initFromGenesisState(ctx, genesisState)
// sanity check
if len(req.Validators) > 0 {
if len(req.Validators) != len(validators) {
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d)",
len(req.Validators), len(validators)))
}
sort.Sort(abci.ValidatorUpdates(req.Validators))
sort.Sort(abci.ValidatorUpdates(validators))
for i, val := range validators {
if !val.Equal(req.Validators[i]) {
panic(fmt.Errorf("validators[%d] != req.Validators[%d] ", i, i))
}
}
}
// assert runtime invariants
app.assertRuntimeInvariants()
return abci.ResponseInitChain{
Validators: validators,
}
}
// load a particular height
func (app *GaiaApp) LoadHeight(height int64) error {
return app.LoadVersion(height, app.keyMain)
}
// ______________________________________________________________________________________________
var _ sdk.StakingHooks = StakingHooks{}
// StakingHooks contains combined distribution and slashing hooks needed for the
// staking module.
type StakingHooks struct {
dh distr.Hooks
sh slashing.Hooks
}
func NewStakingHooks(dh distr.Hooks, sh slashing.Hooks) StakingHooks {
return StakingHooks{dh, sh}
}
// nolint
func (h StakingHooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.AfterValidatorCreated(ctx, valAddr)
h.sh.AfterValidatorCreated(ctx, valAddr)
}
func (h StakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
h.dh.BeforeValidatorModified(ctx, valAddr)
h.sh.BeforeValidatorModified(ctx, valAddr)
}
func (h StakingHooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorRemoved(ctx, consAddr, valAddr)
h.sh.AfterValidatorRemoved(ctx, consAddr, valAddr)
}
func (h StakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorBonded(ctx, consAddr, valAddr)
h.sh.AfterValidatorBonded(ctx, consAddr, valAddr)
}
func (h StakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
h.sh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
}
func (h StakingHooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationCreated(ctx, delAddr, valAddr)
h.sh.BeforeDelegationCreated(ctx, delAddr, valAddr)
}
func (h StakingHooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
h.sh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
}
func (h StakingHooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
h.sh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
}
func (h StakingHooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
h.dh.AfterDelegationModified(ctx, delAddr, valAddr)
h.sh.AfterDelegationModified(ctx, delAddr, valAddr)
}
func (h StakingHooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {
h.dh.BeforeValidatorSlashed(ctx, valAddr, fraction)
h.sh.BeforeValidatorSlashed(ctx, valAddr, fraction)
}

65
gaia/app/app_test.go Normal file
View File

@ -0,0 +1,65 @@
package app
import (
"os"
"testing"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
abci "github.com/tendermint/tendermint/abci/types"
)
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
genaccs := make([]GenesisAccount, len(accs))
for i, acc := range accs {
genaccs[i] = NewGenesisAccount(acc)
}
genesisState := NewGenesisState(
genaccs,
auth.DefaultGenesisState(),
bank.DefaultGenesisState(),
staking.DefaultGenesisState(),
mint.DefaultGenesisState(),
distr.DefaultGenesisState(),
gov.DefaultGenesisState(),
crisis.DefaultGenesisState(),
slashing.DefaultGenesisState(),
)
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
if err != nil {
return err
}
// Initialize the chain
vals := []abci.ValidatorUpdate{}
gapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
gapp.Commit()
return nil
}
func TestGaiadExport(t *testing.T) {
db := db.NewMemDB()
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
setGenesis(gapp)
// Making a new app object with the db, so that initchain hasn't been called
newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}

View File

@ -0,0 +1,40 @@
package app
import (
"fmt"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
)
// This will fail half the time with the second output being 173
// This is due to secp256k1 signatures not being constant size.
// nolint: vet
func ExampleTxSendSize() {
cdc := app.MakeCodec()
var gas uint64 = 1
priv1 := secp256k1.GenPrivKeySecp256k1([]byte{0})
addr1 := sdk.AccAddress(priv1.PubKey().Address())
priv2 := secp256k1.GenPrivKeySecp256k1([]byte{1})
addr2 := sdk.AccAddress(priv2.PubKey().Address())
coins := sdk.Coins{sdk.NewCoin("denom", sdk.NewInt(10))}
msg1 := bank.MsgMultiSend{
Inputs: []bank.Input{bank.NewInput(addr1, coins)},
Outputs: []bank.Output{bank.NewOutput(addr2, coins)},
}
fee := auth.NewStdFee(gas, coins)
signBytes := auth.StdSignBytes("example-chain-ID",
1, 1, fee, []sdk.Msg{msg1}, "")
sig, _ := priv1.Sign(signBytes)
sigs := []auth.StdSignature{{nil, sig}}
tx := auth.NewStdTx([]sdk.Msg{msg1}, fee, sigs, "")
fmt.Println(len(cdc.MustMarshalBinaryBare([]sdk.Msg{msg1})))
fmt.Println(len(cdc.MustMarshalBinaryBare(tx)))
// output: 80
// 169
}

View File

@ -1,6 +1,3 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package app package app
import ( import (
@ -12,13 +9,19 @@ import (
"github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing" "github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/staking"
) )
// export the state of the app for a genesis file // export the state of gaia for a genesis file
func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string, func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string) (
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) { appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
// as if they could withdraw from the start of the next block // as if they could withdraw from the start of the next block
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()}) ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
@ -27,7 +30,26 @@ func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []
app.prepForZeroHeightGenesis(ctx, jailWhiteList) app.prepForZeroHeightGenesis(ctx, jailWhiteList)
} }
genState := app.mm.ExportGenesis(ctx) // iterate to get the accounts
accounts := []GenesisAccount{}
appendAccount := func(acc auth.Account) (stop bool) {
account := NewGenesisAccountI(acc)
accounts = append(accounts, account)
return false
}
app.accountKeeper.IterateAccounts(ctx, appendAccount)
genState := NewGenesisState(
accounts,
auth.ExportGenesis(ctx, app.accountKeeper, app.feeCollectionKeeper),
bank.ExportGenesis(ctx, app.bankKeeper),
staking.ExportGenesis(ctx, app.stakingKeeper),
mint.ExportGenesis(ctx, app.mintKeeper),
distr.ExportGenesis(ctx, app.distrKeeper),
gov.ExportGenesis(ctx, app.govKeeper),
crisis.ExportGenesis(ctx, app.crisisKeeper),
slashing.ExportGenesis(ctx, app.slashingKeeper),
)
appState, err = codec.MarshalJSONIndent(app.cdc, genState) appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
@ -37,9 +59,7 @@ func (app *App) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []
} }
// prepare for fresh start at zero height // prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature which will be deprecated func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) {
// in favour of export at a block height
func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) {
applyWhiteList := false applyWhiteList := false
//Check if there is a whitelist //Check if there is a whitelist
@ -58,12 +78,12 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
} }
/* Just to be safe, assert the invariants on current state. */ /* Just to be safe, assert the invariants on current state. */
app.crisisKeeper.AssertInvariants(ctx, app.Logger()) app.assertRuntimeInvariantsOnContext(ctx)
/* Handle fee distribution state. */ /* Handle fee distribution state. */
// withdraw all validator commission // withdraw all validator commission
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) { app.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
_, _ = app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator()) _, _ = app.distrKeeper.WithdrawValidatorCommission(ctx, val.GetOperator())
return false return false
}) })
@ -85,7 +105,7 @@ func (app *App) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string
ctx = ctx.WithBlockHeight(0) ctx = ctx.WithBlockHeight(0)
// reinitialize all validators // reinitialize all validators
app.stakingKeeper.IterateValidators(ctx, func(_ int64, val staking.ValidatorI) (stop bool) { app.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
// donate any unwithdrawn outstanding reward fraction tokens to the community pool // donate any unwithdrawn outstanding reward fraction tokens to the community pool
scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator()) scraps := app.distrKeeper.GetValidatorOutstandingRewards(ctx, val.GetOperator())

417
gaia/app/genesis.go Normal file
View File

@ -0,0 +1,417 @@
package app
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
"time"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
)
var (
// bonded tokens given to genesis validators/accounts
freeTokensPerAcc = sdk.TokensFromTendermintPower(150)
defaultBondDenom = sdk.DefaultBondDenom
)
// State to Unmarshal
type GenesisState struct {
Accounts []GenesisAccount `json:"accounts"`
AuthData auth.GenesisState `json:"auth"`
BankData bank.GenesisState `json:"bank"`
StakingData staking.GenesisState `json:"staking"`
MintData mint.GenesisState `json:"mint"`
DistrData distr.GenesisState `json:"distr"`
GovData gov.GenesisState `json:"gov"`
CrisisData crisis.GenesisState `json:"crisis"`
SlashingData slashing.GenesisState `json:"slashing"`
GenTxs []json.RawMessage `json:"gentxs"`
}
func NewGenesisState(accounts []GenesisAccount, authData auth.GenesisState,
bankData bank.GenesisState,
stakingData staking.GenesisState, mintData mint.GenesisState,
distrData distr.GenesisState, govData gov.GenesisState, crisisData crisis.GenesisState,
slashingData slashing.GenesisState) GenesisState {
return GenesisState{
Accounts: accounts,
AuthData: authData,
BankData: bankData,
StakingData: stakingData,
MintData: mintData,
DistrData: distrData,
GovData: govData,
CrisisData: crisisData,
SlashingData: slashingData,
}
}
// Sanitize sorts accounts and coin sets.
func (gs GenesisState) Sanitize() {
sort.Slice(gs.Accounts, func(i, j int) bool {
return gs.Accounts[i].AccountNumber < gs.Accounts[j].AccountNumber
})
for _, acc := range gs.Accounts {
acc.Coins = acc.Coins.Sort()
}
}
// GenesisAccount defines an account initialized at genesis.
type GenesisAccount struct {
Address sdk.AccAddress `json:"address"`
Coins sdk.Coins `json:"coins"`
Sequence uint64 `json:"sequence_number"`
AccountNumber uint64 `json:"account_number"`
// vesting account fields
OriginalVesting sdk.Coins `json:"original_vesting"` // total vesting coins upon initialization
DelegatedFree sdk.Coins `json:"delegated_free"` // delegated vested coins at time of delegation
DelegatedVesting sdk.Coins `json:"delegated_vesting"` // delegated vesting coins at time of delegation
StartTime int64 `json:"start_time"` // vesting start time (UNIX Epoch time)
EndTime int64 `json:"end_time"` // vesting end time (UNIX Epoch time)
}
func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount {
return GenesisAccount{
Address: acc.Address,
Coins: acc.Coins,
AccountNumber: acc.AccountNumber,
Sequence: acc.Sequence,
}
}
func NewGenesisAccountI(acc auth.Account) GenesisAccount {
gacc := GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
AccountNumber: acc.GetAccountNumber(),
Sequence: acc.GetSequence(),
}
vacc, ok := acc.(auth.VestingAccount)
if ok {
gacc.OriginalVesting = vacc.GetOriginalVesting()
gacc.DelegatedFree = vacc.GetDelegatedFree()
gacc.DelegatedVesting = vacc.GetDelegatedVesting()
gacc.StartTime = vacc.GetStartTime()
gacc.EndTime = vacc.GetEndTime()
}
return gacc
}
// convert GenesisAccount to auth.BaseAccount
func (ga *GenesisAccount) ToAccount() auth.Account {
bacc := &auth.BaseAccount{
Address: ga.Address,
Coins: ga.Coins.Sort(),
AccountNumber: ga.AccountNumber,
Sequence: ga.Sequence,
}
if !ga.OriginalVesting.IsZero() {
baseVestingAcc := &auth.BaseVestingAccount{
BaseAccount: bacc,
OriginalVesting: ga.OriginalVesting,
DelegatedFree: ga.DelegatedFree,
DelegatedVesting: ga.DelegatedVesting,
EndTime: ga.EndTime,
}
if ga.StartTime != 0 && ga.EndTime != 0 {
return &auth.ContinuousVestingAccount{
BaseVestingAccount: baseVestingAcc,
StartTime: ga.StartTime,
}
} else if ga.EndTime != 0 {
return &auth.DelayedVestingAccount{
BaseVestingAccount: baseVestingAcc,
}
} else {
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
}
}
return bacc
}
// Create the core parameters for genesis initialization for gaia
// note that the pubkey input is this machines pubkey
func GaiaAppGenState(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
genesisState GenesisState, err error) {
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
return genesisState, err
}
// if there are no gen txs to be processed, return the default empty state
if len(appGenTxs) == 0 {
return genesisState, errors.New("there must be at least one genesis tx")
}
stakingData := genesisState.StakingData
for i, genTx := range appGenTxs {
var tx auth.StdTx
if err := cdc.UnmarshalJSON(genTx, &tx); err != nil {
return genesisState, err
}
msgs := tx.GetMsgs()
if len(msgs) != 1 {
return genesisState, errors.New(
"must provide genesis StdTx with exactly 1 CreateValidator message")
}
if _, ok := msgs[0].(staking.MsgCreateValidator); !ok {
return genesisState, fmt.Errorf(
"Genesis transaction %v does not contain a MsgCreateValidator", i)
}
}
for _, acc := range genesisState.Accounts {
for _, coin := range acc.Coins {
if coin.Denom == genesisState.StakingData.Params.BondDenom {
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.
Add(coin.Amount) // increase the supply
}
}
}
genesisState.StakingData = stakingData
genesisState.GenTxs = appGenTxs
return genesisState, nil
}
// NewDefaultGenesisState generates the default state for gaia.
func NewDefaultGenesisState() GenesisState {
return GenesisState{
Accounts: nil,
AuthData: auth.DefaultGenesisState(),
BankData: bank.DefaultGenesisState(),
StakingData: staking.DefaultGenesisState(),
MintData: mint.DefaultGenesisState(),
DistrData: distr.DefaultGenesisState(),
GovData: gov.DefaultGenesisState(),
CrisisData: crisis.DefaultGenesisState(),
SlashingData: slashing.DefaultGenesisState(),
GenTxs: nil,
}
}
// GaiaValidateGenesisState ensures that the genesis state obeys the expected invariants
// TODO: No validators are both bonded and jailed (#2088)
// TODO: Error if there is a duplicate validator (#1708)
// TODO: Ensure all state machine parameters are in genesis (#1704)
func GaiaValidateGenesisState(genesisState GenesisState) error {
if err := validateGenesisStateAccounts(genesisState.Accounts); err != nil {
return err
}
// skip stakingData validation as genesis is created from txs
if len(genesisState.GenTxs) > 0 {
return nil
}
if err := auth.ValidateGenesis(genesisState.AuthData); err != nil {
return err
}
if err := bank.ValidateGenesis(genesisState.BankData); err != nil {
return err
}
if err := staking.ValidateGenesis(genesisState.StakingData); err != nil {
return err
}
if err := mint.ValidateGenesis(genesisState.MintData); err != nil {
return err
}
if err := distr.ValidateGenesis(genesisState.DistrData); err != nil {
return err
}
if err := gov.ValidateGenesis(genesisState.GovData); err != nil {
return err
}
if err := crisis.ValidateGenesis(genesisState.CrisisData); err != nil {
return err
}
return slashing.ValidateGenesis(genesisState.SlashingData)
}
// validateGenesisStateAccounts performs validation of genesis accounts. It
// ensures that there are no duplicate accounts in the genesis state and any
// provided vesting accounts are valid.
func validateGenesisStateAccounts(accs []GenesisAccount) error {
addrMap := make(map[string]bool, len(accs))
for _, acc := range accs {
addrStr := acc.Address.String()
// disallow any duplicate accounts
if _, ok := addrMap[addrStr]; ok {
return fmt.Errorf("duplicate account found in genesis state; address: %s", addrStr)
}
// validate any vesting fields
if !acc.OriginalVesting.IsZero() {
if acc.EndTime == 0 {
return fmt.Errorf("missing end time for vesting account; address: %s", addrStr)
}
if acc.StartTime >= acc.EndTime {
return fmt.Errorf(
"vesting start time must before end time; address: %s, start: %s, end: %s",
addrStr,
time.Unix(acc.StartTime, 0).UTC().Format(time.RFC3339),
time.Unix(acc.EndTime, 0).UTC().Format(time.RFC3339),
)
}
}
addrMap[addrStr] = true
}
return nil
}
// GaiaAppGenState but with JSON
func GaiaAppGenStateJSON(cdc *codec.Codec, genDoc tmtypes.GenesisDoc, appGenTxs []json.RawMessage) (
appState json.RawMessage, err error) {
// create the final app state
genesisState, err := GaiaAppGenState(cdc, genDoc, appGenTxs)
if err != nil {
return nil, err
}
return codec.MarshalJSONIndent(cdc, genesisState)
}
// CollectStdTxs processes and validates application's genesis StdTxs and returns
// the list of appGenTxs, and persistent peers required to generate genesis.json.
func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tmtypes.GenesisDoc) (
appGenTxs []auth.StdTx, persistentPeers string, err error) {
var fos []os.FileInfo
fos, err = ioutil.ReadDir(genTxsDir)
if err != nil {
return appGenTxs, persistentPeers, err
}
// prepare a map of all accounts in genesis state to then validate
// against the validators addresses
var appState GenesisState
if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
return appGenTxs, persistentPeers, err
}
addrMap := make(map[string]GenesisAccount, len(appState.Accounts))
for i := 0; i < len(appState.Accounts); i++ {
acc := appState.Accounts[i]
addrMap[acc.Address.String()] = acc
}
// addresses and IPs (and port) validator server info
var addressesIPs []string
for _, fo := range fos {
filename := filepath.Join(genTxsDir, fo.Name())
if !fo.IsDir() && (filepath.Ext(filename) != ".json") {
continue
}
// get the genStdTx
var jsonRawTx []byte
if jsonRawTx, err = ioutil.ReadFile(filename); err != nil {
return appGenTxs, persistentPeers, err
}
var genStdTx auth.StdTx
if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil {
return appGenTxs, persistentPeers, err
}
appGenTxs = append(appGenTxs, genStdTx)
// the memo flag is used to store
// the ip and node-id, for example this may be:
// "528fd3df22b31f4969b05652bfe8f0fe921321d5@192.168.2.37:26656"
nodeAddrIP := genStdTx.GetMemo()
if len(nodeAddrIP) == 0 {
return appGenTxs, persistentPeers, fmt.Errorf(
"couldn't find node's address and IP in %s", fo.Name())
}
// genesis transactions must be single-message
msgs := genStdTx.GetMsgs()
if len(msgs) != 1 {
return appGenTxs, persistentPeers, errors.New(
"each genesis transaction must provide a single genesis message")
}
msg := msgs[0].(staking.MsgCreateValidator)
// validate delegator and validator addresses and funds against the accounts in the state
delAddr := msg.DelegatorAddress.String()
valAddr := sdk.AccAddress(msg.ValidatorAddress).String()
delAcc, delOk := addrMap[delAddr]
_, valOk := addrMap[valAddr]
accsNotInGenesis := []string{}
if !delOk {
accsNotInGenesis = append(accsNotInGenesis, delAddr)
}
if !valOk {
accsNotInGenesis = append(accsNotInGenesis, valAddr)
}
if len(accsNotInGenesis) != 0 {
return appGenTxs, persistentPeers, fmt.Errorf(
"account(s) %v not in genesis.json: %+v", strings.Join(accsNotInGenesis, " "), addrMap)
}
if delAcc.Coins.AmountOf(msg.Value.Denom).LT(msg.Value.Amount) {
return appGenTxs, persistentPeers, fmt.Errorf(
"insufficient fund for delegation %v: %v < %v",
delAcc.Address, delAcc.Coins.AmountOf(msg.Value.Denom), msg.Value.Amount,
)
}
// exclude itself from persistent peers
if msg.Description.Moniker != moniker {
addressesIPs = append(addressesIPs, nodeAddrIP)
}
}
sort.Strings(addressesIPs)
persistentPeers = strings.Join(addressesIPs, ",")
return appGenTxs, persistentPeers, nil
}
func NewDefaultGenesisAccount(addr sdk.AccAddress) GenesisAccount {
accAuth := auth.NewBaseAccountWithAddress(addr)
coins := sdk.Coins{
sdk.NewCoin("footoken", sdk.NewInt(1000)),
sdk.NewCoin(defaultBondDenom, freeTokensPerAcc),
}
coins.Sort()
accAuth.Coins = coins
return NewGenesisAccount(&accAuth)
}

188
gaia/app/genesis_test.go Normal file
View File

@ -0,0 +1,188 @@
package app
import (
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
tmtypes "github.com/tendermint/tendermint/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/staking"
)
var (
pk1 = ed25519.GenPrivKey().PubKey()
pk2 = ed25519.GenPrivKey().PubKey()
pk3 = ed25519.GenPrivKey().PubKey()
addr1 = sdk.ValAddress(pk1.Address())
addr2 = sdk.ValAddress(pk2.Address())
addr3 = sdk.ValAddress(pk3.Address())
emptyAddr sdk.ValAddress
emptyPubkey crypto.PubKey
)
func makeGenesisState(t *testing.T, genTxs []auth.StdTx) GenesisState {
// start with the default staking genesis state
appState := NewDefaultGenesisState()
stakingData := appState.StakingData
genAccs := make([]GenesisAccount, len(genTxs))
for i, genTx := range genTxs {
msgs := genTx.GetMsgs()
require.Equal(t, 1, len(msgs))
msg := msgs[0].(staking.MsgCreateValidator)
acc := auth.NewBaseAccountWithAddress(sdk.AccAddress(msg.ValidatorAddress))
acc.Coins = sdk.NewCoins(sdk.NewInt64Coin(defaultBondDenom, 150))
genAccs[i] = NewGenesisAccount(&acc)
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(sdk.NewInt(150)) // increase the supply
}
// create the final app state
appState.Accounts = genAccs
return appState
}
func TestToAccount(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
authAcc := auth.NewBaseAccountWithAddress(addr)
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(defaultBondDenom, 150)))
genAcc := NewGenesisAccount(&authAcc)
acc := genAcc.ToAccount()
require.IsType(t, &auth.BaseAccount{}, acc)
require.Equal(t, &authAcc, acc.(*auth.BaseAccount))
vacc := auth.NewContinuousVestingAccount(
&authAcc, time.Now().Unix(), time.Now().Add(24*time.Hour).Unix(),
)
genAcc = NewGenesisAccountI(vacc)
acc = genAcc.ToAccount()
require.IsType(t, &auth.ContinuousVestingAccount{}, acc)
require.Equal(t, vacc, acc.(*auth.ContinuousVestingAccount))
}
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
var genDoc tmtypes.GenesisDoc
// test unmarshalling error
_, err := GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
require.Error(t, err)
appState := makeGenesisState(t, []auth.StdTx{})
genDoc.AppState, err = json.Marshal(appState)
require.NoError(t, err)
// test validation error
_, err = GaiaAppGenState(cdc, genDoc, []json.RawMessage{})
require.Error(t, err)
// TODO test must provide at least genesis transaction
// TODO test with both one and two genesis transactions:
// TODO correct: genesis account created, canididates created, pool token variance
}
func makeMsg(name string, pk crypto.PubKey) auth.StdTx {
desc := staking.NewDescription(name, "", "", "")
comm := staking.CommissionMsg{}
msg := staking.NewMsgCreateValidator(sdk.ValAddress(pk.Address()), pk, sdk.NewInt64Coin(defaultBondDenom,
50), desc, comm, sdk.OneInt())
return auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, nil, "")
}
func TestGaiaGenesisValidation(t *testing.T) {
genTxs := []auth.StdTx{makeMsg("test-0", pk1), makeMsg("test-1", pk2)}
dupGenTxs := []auth.StdTx{makeMsg("test-0", pk1), makeMsg("test-1", pk1)}
// require duplicate accounts fails validation
genesisState := makeGenesisState(t, dupGenTxs)
err := GaiaValidateGenesisState(genesisState)
require.Error(t, err)
// require invalid vesting account fails validation (invalid end time)
genesisState = makeGenesisState(t, genTxs)
genesisState.Accounts[0].OriginalVesting = genesisState.Accounts[0].Coins
err = GaiaValidateGenesisState(genesisState)
require.Error(t, err)
genesisState.Accounts[0].StartTime = 1548888000
genesisState.Accounts[0].EndTime = 1548775410
err = GaiaValidateGenesisState(genesisState)
require.Error(t, err)
// require bonded + jailed validator fails validation
genesisState = makeGenesisState(t, genTxs)
val1 := staking.NewValidator(addr1, pk1, staking.NewDescription("test #2", "", "", ""))
val1.Jailed = true
val1.Status = sdk.Bonded
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val1)
err = GaiaValidateGenesisState(genesisState)
require.Error(t, err)
// require duplicate validator fails validation
val1.Jailed = false
genesisState = makeGenesisState(t, genTxs)
val2 := staking.NewValidator(addr1, pk1, staking.NewDescription("test #3", "", "", ""))
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val1)
genesisState.StakingData.Validators = append(genesisState.StakingData.Validators, val2)
err = GaiaValidateGenesisState(genesisState)
require.Error(t, err)
}
func TestNewDefaultGenesisAccount(t *testing.T) {
addr := secp256k1.GenPrivKeySecp256k1([]byte("")).PubKey().Address()
acc := NewDefaultGenesisAccount(sdk.AccAddress(addr))
require.Equal(t, sdk.NewInt(1000), acc.Coins.AmountOf("footoken"))
require.Equal(t, sdk.TokensFromTendermintPower(150), acc.Coins.AmountOf(defaultBondDenom))
}
func TestGenesisStateSanitize(t *testing.T) {
genesisState := makeGenesisState(t, nil)
require.Nil(t, GaiaValidateGenesisState(genesisState))
addr1 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
authAcc1 := auth.NewBaseAccountWithAddress(addr1)
authAcc1.SetCoins(sdk.Coins{
sdk.NewInt64Coin("bcoin", 150),
sdk.NewInt64Coin("acoin", 150),
})
authAcc1.SetAccountNumber(1)
genAcc1 := NewGenesisAccount(&authAcc1)
addr2 := sdk.AccAddress(ed25519.GenPrivKey().PubKey().Address())
authAcc2 := auth.NewBaseAccountWithAddress(addr2)
authAcc2.SetCoins(sdk.Coins{
sdk.NewInt64Coin("acoin", 150),
sdk.NewInt64Coin("bcoin", 150),
})
genAcc2 := NewGenesisAccount(&authAcc2)
genesisState.Accounts = []GenesisAccount{genAcc1, genAcc2}
require.True(t, genesisState.Accounts[0].AccountNumber > genesisState.Accounts[1].AccountNumber)
require.Equal(t, genesisState.Accounts[0].Coins[0].Denom, "bcoin")
require.Equal(t, genesisState.Accounts[0].Coins[1].Denom, "acoin")
require.Equal(t, genesisState.Accounts[1].Address, addr2)
genesisState.Sanitize()
require.False(t, genesisState.Accounts[0].AccountNumber > genesisState.Accounts[1].AccountNumber)
require.Equal(t, genesisState.Accounts[1].Address, addr1)
require.Equal(t, genesisState.Accounts[1].Coins[0].Denom, "acoin")
require.Equal(t, genesisState.Accounts[1].Coins[1].Denom, "bcoin")
}

31
gaia/app/invariants.go Normal file
View File

@ -0,0 +1,31 @@
package app
import (
"fmt"
"time"
abci "github.com/tendermint/tendermint/abci/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func (app *GaiaApp) assertRuntimeInvariants() {
ctx := app.NewContext(false, abci.Header{Height: app.LastBlockHeight() + 1})
app.assertRuntimeInvariantsOnContext(ctx)
}
func (app *GaiaApp) assertRuntimeInvariantsOnContext(ctx sdk.Context) {
start := time.Now()
invarRoutes := app.crisisKeeper.Routes()
for _, ir := range invarRoutes {
if err := ir.Invar(ctx); err != nil {
panic(fmt.Errorf("invariant broken: %s\n"+
"\tCRITICAL please submit the following transaction:\n"+
"\t\t gaiacli tx crisis invariant-broken %v %v", err, ir.ModuleName, ir.Route))
}
}
end := time.Now()
diff := end.Sub(start)
app.BaseApp.Logger().With("module", "invariants").Info(
"Asserted all invariants", "duration", diff, "height", app.LastBlockHeight())
}

564
gaia/app/sim_test.go Normal file
View File

@ -0,0 +1,564 @@
package app
import (
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"math/rand"
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/secp256k1"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authsim "github.com/cosmos/cosmos-sdk/x/auth/simulation"
"github.com/cosmos/cosmos-sdk/x/bank"
banksim "github.com/cosmos/cosmos-sdk/x/bank/simulation"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrsim "github.com/cosmos/cosmos-sdk/x/distribution/simulation"
"github.com/cosmos/cosmos-sdk/x/gov"
govsim "github.com/cosmos/cosmos-sdk/x/gov/simulation"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/cosmos/cosmos-sdk/x/simulation"
"github.com/cosmos/cosmos-sdk/x/slashing"
slashingsim "github.com/cosmos/cosmos-sdk/x/slashing/simulation"
"github.com/cosmos/cosmos-sdk/x/staking"
stakingsim "github.com/cosmos/cosmos-sdk/x/staking/simulation"
)
var (
genesisFile string
seed int64
numBlocks int
blockSize int
enabled bool
verbose bool
lean bool
commit bool
period int
)
func init() {
flag.StringVar(&genesisFile, "SimulationGenesis", "", "custom simulation genesis file")
flag.Int64Var(&seed, "SimulationSeed", 42, "simulation random seed")
flag.IntVar(&numBlocks, "SimulationNumBlocks", 500, "number of blocks")
flag.IntVar(&blockSize, "SimulationBlockSize", 200, "operations per block")
flag.BoolVar(&enabled, "SimulationEnabled", false, "enable the simulation")
flag.BoolVar(&verbose, "SimulationVerbose", false, "verbose log output")
flag.BoolVar(&lean, "SimulationLean", false, "lean simulation log output")
flag.BoolVar(&commit, "SimulationCommit", false, "have the simulation commit")
flag.IntVar(&period, "SimulationPeriod", 1, "run slow invariants only once every period assertions")
}
// helper function for populating input for SimulateFromSeed
func getSimulateFromSeedInput(tb testing.TB, app *GaiaApp) (
testing.TB, *baseapp.BaseApp, simulation.AppStateFn, int64,
simulation.WeightedOperations, sdk.Invariants, int, int, bool, bool) {
return tb, app.BaseApp, appStateFn, seed,
testAndRunTxs(app), invariants(app), numBlocks, blockSize, commit, lean
}
func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
var genesis tmtypes.GenesisDoc
cdc := MakeCodec()
bytes, err := ioutil.ReadFile(genesisFile)
if err != nil {
panic(err)
}
cdc.MustUnmarshalJSON(bytes, &genesis)
var appState GenesisState
cdc.MustUnmarshalJSON(genesis.AppState, &appState)
var newAccs []simulation.Account
for _, acc := range appState.Accounts {
// Pick a random private key, since we don't know the actual key
// This should be fine as it's only used for mock Tendermint validators
// and these keys are never actually used to sign by mock Tendermint.
privkeySeed := make([]byte, 15)
r.Read(privkeySeed)
privKey := secp256k1.GenPrivKeySecp256k1(privkeySeed)
newAccs = append(newAccs, simulation.Account{privKey, privKey.PubKey(), acc.Address})
}
return genesis.AppState, newAccs, genesis.ChainID
}
func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
var genesisAccounts []GenesisAccount
amount := int64(r.Intn(1e12))
numInitiallyBonded := int64(r.Intn(250))
numAccs := int64(len(accs))
if numInitiallyBonded > numAccs {
numInitiallyBonded = numAccs
}
fmt.Printf("Selected randomly generated parameters for simulated genesis:\n"+
"\t{amount of stake per account: %v, initially bonded validators: %v}\n",
amount, numInitiallyBonded)
// randomly generate some genesis accounts
for i, acc := range accs {
coins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(amount))}
bacc := auth.NewBaseAccountWithAddress(acc.Address)
bacc.SetCoins(coins)
var gacc GenesisAccount
// Only consider making a vesting account once the initial bonded validator
// set is exhausted due to needing to track DelegatedVesting.
if int64(i) > numInitiallyBonded && r.Intn(100) < 50 {
var (
vacc auth.VestingAccount
endTime int64
)
startTime := genesisTimestamp.Unix()
// Allow for some vesting accounts to vest very quickly while others very
// slowly.
if r.Intn(100) < 50 {
endTime = int64(simulation.RandIntBetween(r, int(startTime), int(startTime+(60*60*24*30))))
} else {
endTime = int64(simulation.RandIntBetween(r, int(startTime), int(startTime+(60*60*12))))
}
if startTime == endTime {
endTime += 1
}
if r.Intn(100) < 50 {
vacc = auth.NewContinuousVestingAccount(&bacc, startTime, endTime)
} else {
vacc = auth.NewDelayedVestingAccount(&bacc, endTime)
}
gacc = NewGenesisAccountI(vacc)
} else {
gacc = NewGenesisAccount(&bacc)
}
genesisAccounts = append(genesisAccounts, gacc)
}
authGenesis := auth.GenesisState{
Params: auth.Params{
MaxMemoCharacters: uint64(simulation.RandIntBetween(r, 100, 200)),
TxSigLimit: uint64(r.Intn(7) + 1),
TxSizeCostPerByte: uint64(simulation.RandIntBetween(r, 5, 15)),
SigVerifyCostED25519: uint64(simulation.RandIntBetween(r, 500, 1000)),
SigVerifyCostSecp256k1: uint64(simulation.RandIntBetween(r, 500, 1000)),
},
}
fmt.Printf("Selected randomly generated auth parameters:\n\t%+v\n", authGenesis)
bankGenesis := bank.NewGenesisState(r.Int63n(2) == 0)
fmt.Printf("Selected randomly generated bank parameters:\n\t%+v\n", bankGenesis)
// Random genesis states
vp := time.Duration(r.Intn(2*172800)) * time.Second
govGenesis := gov.GenesisState{
StartingProposalID: uint64(r.Intn(100)),
DepositParams: gov.DepositParams{
MinDeposit: sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, int64(r.Intn(1e3)))},
MaxDepositPeriod: vp,
},
VotingParams: gov.VotingParams{
VotingPeriod: vp,
},
TallyParams: gov.TallyParams{
Quorum: sdk.NewDecWithPrec(334, 3),
Threshold: sdk.NewDecWithPrec(5, 1),
Veto: sdk.NewDecWithPrec(334, 3),
},
}
fmt.Printf("Selected randomly generated governance parameters:\n\t%+v\n", govGenesis)
stakingGenesis := staking.GenesisState{
Pool: staking.InitialPool(),
Params: staking.Params{
UnbondingTime: time.Duration(simulation.RandIntBetween(r, 60, 60*60*24*3*2)) * time.Second,
MaxValidators: uint16(r.Intn(250) + 1),
BondDenom: sdk.DefaultBondDenom,
},
}
fmt.Printf("Selected randomly generated staking parameters:\n\t%+v\n", stakingGenesis)
slashingGenesis := slashing.GenesisState{
Params: slashing.Params{
MaxEvidenceAge: stakingGenesis.Params.UnbondingTime,
SignedBlocksWindow: int64(simulation.RandIntBetween(r, 10, 1000)),
MinSignedPerWindow: sdk.NewDecWithPrec(int64(r.Intn(10)), 1),
DowntimeJailDuration: time.Duration(simulation.RandIntBetween(r, 60, 60*60*24)) * time.Second,
SlashFractionDoubleSign: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(50) + 1))),
SlashFractionDowntime: sdk.NewDec(1).Quo(sdk.NewDec(int64(r.Intn(200) + 1))),
},
}
fmt.Printf("Selected randomly generated slashing parameters:\n\t%+v\n", slashingGenesis)
mintGenesis := mint.GenesisState{
Minter: mint.InitialMinter(
sdk.NewDecWithPrec(int64(r.Intn(99)), 2)),
Params: mint.NewParams(
sdk.DefaultBondDenom,
sdk.NewDecWithPrec(int64(r.Intn(99)), 2),
sdk.NewDecWithPrec(20, 2),
sdk.NewDecWithPrec(7, 2),
sdk.NewDecWithPrec(67, 2),
uint64(60*60*8766/5)),
}
fmt.Printf("Selected randomly generated minting parameters:\n\t%+v\n", mintGenesis)
var validators []staking.Validator
var delegations []staking.Delegation
valAddrs := make([]sdk.ValAddress, numInitiallyBonded)
for i := 0; i < int(numInitiallyBonded); i++ {
valAddr := sdk.ValAddress(accs[i].Address)
valAddrs[i] = valAddr
validator := staking.NewValidator(valAddr, accs[i].PubKey, staking.Description{})
validator.Tokens = sdk.NewInt(amount)
validator.DelegatorShares = sdk.NewDec(amount)
delegation := staking.Delegation{accs[i].Address, valAddr, sdk.NewDec(amount)}
validators = append(validators, validator)
delegations = append(delegations, delegation)
}
stakingGenesis.Pool.NotBondedTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount))
stakingGenesis.Validators = validators
stakingGenesis.Delegations = delegations
distrGenesis := distr.GenesisState{
FeePool: distr.InitialFeePool(),
CommunityTax: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
BaseProposerReward: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
BonusProposerReward: sdk.NewDecWithPrec(1, 2).Add(sdk.NewDecWithPrec(int64(r.Intn(30)), 2)),
}
fmt.Printf("Selected randomly generated distribution parameters:\n\t%+v\n", distrGenesis)
genesis := GenesisState{
Accounts: genesisAccounts,
AuthData: authGenesis,
BankData: bankGenesis,
StakingData: stakingGenesis,
MintData: mintGenesis,
DistrData: distrGenesis,
SlashingData: slashingGenesis,
GovData: govGenesis,
}
// Marshal genesis
appState, err := MakeCodec().MarshalJSON(genesis)
if err != nil {
panic(err)
}
return appState, accs, "simulation"
}
func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
if genesisFile != "" {
return appStateFromGenesisFileFn(r, accs, genesisTimestamp)
}
return appStateRandomizedFn(r, accs, genesisTimestamp)
}
func testAndRunTxs(app *GaiaApp) []simulation.WeightedOperation {
return []simulation.WeightedOperation{
{5, authsim.SimulateDeductFee(app.accountKeeper, app.feeCollectionKeeper)},
{100, banksim.SimulateMsgSend(app.accountKeeper, app.bankKeeper)},
{10, banksim.SimulateSingleInputMsgMultiSend(app.accountKeeper, app.bankKeeper)},
{50, distrsim.SimulateMsgSetWithdrawAddress(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawDelegatorReward(app.accountKeeper, app.distrKeeper)},
{50, distrsim.SimulateMsgWithdrawValidatorCommission(app.accountKeeper, app.distrKeeper)},
{5, govsim.SimulateSubmittingVotingAndSlashingForProposal(app.govKeeper)},
{100, govsim.SimulateMsgDeposit(app.govKeeper)},
{100, stakingsim.SimulateMsgCreateValidator(app.accountKeeper, app.stakingKeeper)},
{5, stakingsim.SimulateMsgEditValidator(app.stakingKeeper)},
{100, stakingsim.SimulateMsgDelegate(app.accountKeeper, app.stakingKeeper)},
{100, stakingsim.SimulateMsgUndelegate(app.accountKeeper, app.stakingKeeper)},
{100, stakingsim.SimulateMsgBeginRedelegate(app.accountKeeper, app.stakingKeeper)},
{100, slashingsim.SimulateMsgUnjail(app.slashingKeeper)},
}
}
func invariants(app *GaiaApp) []sdk.Invariant {
return []sdk.Invariant{
simulation.PeriodicInvariant(bank.NonnegativeBalanceInvariant(app.accountKeeper), period, 0),
simulation.PeriodicInvariant(distr.AllInvariants(app.distrKeeper, app.stakingKeeper), period, 0),
simulation.PeriodicInvariant(staking.AllInvariants(app.stakingKeeper, app.feeCollectionKeeper,
app.distrKeeper, app.accountKeeper), period, 0),
}
}
// Pass this in as an option to use a dbStoreAdapter instead of an IAVLStore for simulation speed.
func fauxMerkleModeOpt(bapp *baseapp.BaseApp) {
bapp.SetFauxMerkleMode()
}
// Profile with:
// /usr/local/go/bin/go test -benchmem -run=^$ github.com/cosmos/cosmos-sdk/cmd/gaia/app -bench ^BenchmarkFullGaiaSimulation$ -SimulationCommit=true -cpuprofile cpu.out
func BenchmarkFullGaiaSimulation(b *testing.B) {
// Setup Gaia application
logger := log.NewNopLogger()
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, 0)
// Run randomized simulation
// TODO parameterize numbers, save for a later PR
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(b, app))
if err != nil {
fmt.Println(err)
b.Fail()
}
if commit {
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
}
func TestFullGaiaSimulation(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia simulation")
}
// Setup Gaia application
var logger log.Logger
if verbose {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, 0, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
require.Nil(t, err)
}
func TestGaiaImportExport(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia import/export simulation")
}
// Setup Gaia application
var logger log.Logger
if verbose {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
var db dbm.DB
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
db, _ = sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, 0, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
_, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
require.Nil(t, err)
fmt.Printf("Exporting genesis...\n")
appState, _, err := app.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err)
fmt.Printf("Importing genesis...\n")
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
newDB, _ := sdk.NewLevelDB("Simulation-2", dir)
defer func() {
newDB.Close()
os.RemoveAll(newDir)
}()
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, 0, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", newApp.Name())
var genesisState GenesisState
err = app.cdc.UnmarshalJSON(appState, &genesisState)
if err != nil {
panic(err)
}
ctxB := newApp.NewContext(true, abci.Header{})
newApp.initFromGenesisState(ctxB, genesisState)
fmt.Printf("Comparing stores...\n")
ctxA := app.NewContext(true, abci.Header{})
type StoreKeysPrefixes struct {
A sdk.StoreKey
B sdk.StoreKey
Prefixes [][]byte
}
storeKeysPrefixes := []StoreKeysPrefixes{
{app.keyMain, newApp.keyMain, [][]byte{}},
{app.keyAccount, newApp.keyAccount, [][]byte{}},
{app.keyStaking, newApp.keyStaking, [][]byte{staking.UnbondingQueueKey,
staking.RedelegationQueueKey, staking.ValidatorQueueKey}}, // ordering may change but it doesn't matter
{app.keySlashing, newApp.keySlashing, [][]byte{}},
{app.keyMint, newApp.keyMint, [][]byte{}},
{app.keyDistr, newApp.keyDistr, [][]byte{}},
{app.keyFeeCollection, newApp.keyFeeCollection, [][]byte{}},
{app.keyParams, newApp.keyParams, [][]byte{}},
{app.keyGov, newApp.keyGov, [][]byte{}},
}
for _, storeKeysPrefix := range storeKeysPrefixes {
storeKeyA := storeKeysPrefix.A
storeKeyB := storeKeysPrefix.B
prefixes := storeKeysPrefix.Prefixes
storeA := ctxA.KVStore(storeKeyA)
storeB := ctxB.KVStore(storeKeyB)
kvA, kvB, count, equal := sdk.DiffKVStores(storeA, storeB, prefixes)
fmt.Printf("Compared %d key/value pairs between %s and %s\n", count, storeKeyA, storeKeyB)
require.True(t, equal,
"unequal stores: %s / %s:\nstore A %X => %X\nstore B %X => %X",
storeKeyA, storeKeyB, kvA.Key, kvA.Value, kvB.Key, kvB.Value,
)
}
}
func TestGaiaSimulationAfterImport(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia simulation after import")
}
// Setup Gaia application
var logger log.Logger
if verbose {
logger = log.TestingLogger()
} else {
logger = log.NewNopLogger()
}
dir, _ := ioutil.TempDir("", "goleveldb-gaia-sim")
db, _ := sdk.NewLevelDB("Simulation", dir)
defer func() {
db.Close()
os.RemoveAll(dir)
}()
app := NewGaiaApp(logger, db, nil, true, 0, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", app.Name())
// Run randomized simulation
stopEarly, err := simulation.SimulateFromSeed(getSimulateFromSeedInput(t, app))
if commit {
// for memdb:
// fmt.Println("Database Size", db.Stats()["database.size"])
fmt.Println("GoLevelDB Stats")
fmt.Println(db.Stats()["leveldb.stats"])
fmt.Println("GoLevelDB cached block size", db.Stats()["leveldb.cachedblock"])
}
require.Nil(t, err)
if stopEarly {
// we can't export or import a zero-validator genesis
fmt.Printf("We can't export or import a zero-validator genesis, exiting test...\n")
return
}
fmt.Printf("Exporting genesis...\n")
appState, _, err := app.ExportAppStateAndValidators(true, []string{})
if err != nil {
panic(err)
}
fmt.Printf("Importing genesis...\n")
newDir, _ := ioutil.TempDir("", "goleveldb-gaia-sim-2")
newDB, _ := sdk.NewLevelDB("Simulation-2", dir)
defer func() {
newDB.Close()
os.RemoveAll(newDir)
}()
newApp := NewGaiaApp(log.NewNopLogger(), newDB, nil, true, 0, fauxMerkleModeOpt)
require.Equal(t, "GaiaApp", newApp.Name())
newApp.InitChain(abci.RequestInitChain{
AppStateBytes: appState,
})
// Run randomized simulation on imported app
_, err = simulation.SimulateFromSeed(getSimulateFromSeedInput(t, newApp))
require.Nil(t, err)
}
// TODO: Make another test for the fuzzer itself, which just has noOp txs
// and doesn't depend on gaia
func TestAppStateDeterminism(t *testing.T) {
if !enabled {
t.Skip("Skipping Gaia simulation")
}
numSeeds := 3
numTimesToRunPerSeed := 5
appHashList := make([]json.RawMessage, numTimesToRunPerSeed)
for i := 0; i < numSeeds; i++ {
seed := rand.Int63()
for j := 0; j < numTimesToRunPerSeed; j++ {
logger := log.NewNopLogger()
db := dbm.NewMemDB()
app := NewGaiaApp(logger, db, nil, true, 0)
// Run randomized simulation
simulation.SimulateFromSeed(
t, app.BaseApp, appStateFn, seed,
testAndRunTxs(app),
[]sdk.Invariant{},
50,
100,
true,
false,
)
appHash := app.LastCommitID().Hash
appHashList[j] = appHash
}
for k := 1; k < numTimesToRunPerSeed; k++ {
require.Equal(t, appHashList[0], appHashList[k], "appHash list: %v", appHashList)
}
}
}

51
gaia/cli_test/README.md Normal file
View File

@ -0,0 +1,51 @@
# Gaia CLI Integration tests
The gaia cli integration tests live in this folder. You can run the full suite by running:
```bash
$ go test -v -p 4 ./cmd/gaia/cli_test/...
# OR!
$ make test_cli
```
> NOTE: While the full suite runs in parallel, some of the tests can take up to a minute to complete
### Test Structure
This integration suite [uses a thin wrapper](https://godoc.org/github.com/cosmos/cosmos-sdk/tests) over the [`os/exec`](https://golang.org/pkg/os/exec/) package. This allows the integration test to run against built binaries (both `gaiad` and `gaiacli` are used) while being written in golang. This allows tests to take advantage of the various golang code we have for operations like marshal/unmarshal, crypto, etc...
> NOTE: The tests will use whatever `gaiad` or `gaiacli` binaries are available in your `$PATH`. You can check which binary will be run by the suite by running `which gaiad` or `which gaiacli`. If you have your `$GOPATH` properly setup they should be in `$GOPATH/bin/gaia*`. This will ensure that your test uses the latest binary you have built
Tests generally follow this structure:
```go
func TestMyNewCommand(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
// start gaiad server
proc := f.GDStart()
defer proc.Stop(false)
// Your test code goes here...
f.Cleanup()
}
```
This boilerplate above:
- Ensures the tests run in parallel. Because the tests are calling out to `os/exec` for many operations these tests can take a long time to run.
- Creates `.gaiad` and `.gaiacli` folders in a new temp folder.
- Uses `gaiacli` to create 2 accounts for use in testing: `foo` and `bar`
- Creates a genesis file with coins (`1000footoken,1000feetoken,150stake`) controlled by the `foo` key
- Generates an initial bonding transaction (`gentx`) to make the `foo` key a validator at genesis
- Starts `gaiad` and stops it once the test exits
- Cleans up test state on a successful run
### Notes when adding/running tests
- Because the tests run against a built binary, you should make sure you build every time the code changes and you want to test again, otherwise you will be testing against an older version. If you are adding new tests this can easily lead to confusing test results.
- The [`test_helpers.go`](./test_helpers.go) file is organized according to the format of `gaiacli` and `gaiad` commands. There are comments with section headers describing the different areas. Helper functions to call CLI functionality are generally named after the command (e.g. `gaiacli query staking validator` would be `QueryStakingValidator`). Try to keep functions grouped by their position in the command tree.
- Test state that is needed by `tx` and `query` commands (`home`, `chain_id`, etc...) is stored on the `Fixtures` object. This makes constructing your new tests almost trivial.
- Sometimes if you exit a test early there can be still running `gaiad` and `gaiacli` processes that will interrupt subsequent runs. Still running `gaiacli` processes will block access to the keybase while still running `gaiad` processes will block ports and prevent new tests from spinning up. You can ensure new tests spin up clean by running `pkill -9 gaiad && pkill -9 gaiacli` before each test run.
- Most `query` and `tx` commands take a variadic `flags` argument. This pattern allows for the creation of a general function which is easily modified by adding flags. See the `TxSend` function and its use for a good example.
- `Tx*` functions follow a general pattern and return `(success bool, stdout string, stderr string)`. This allows for easy testing of multiple different flag configurations. See `TestGaiaCLICreateValidator` or `TestGaiaCLISubmitProposal` for a good example of the pattern.

1093
gaia/cli_test/cli_test.go Normal file

File diff suppressed because it is too large Load Diff

3
gaia/cli_test/doc.go Normal file
View File

@ -0,0 +1,3 @@
package clitest
// package clitest runs integration tests which make use of CLI commands.

View File

@ -0,0 +1,685 @@
package clitest
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"testing"
"time"
"github.com/stretchr/testify/require"
cmn "github.com/tendermint/tendermint/libs/common"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
appInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
)
const (
denom = "stake"
keyFoo = "foo"
keyBar = "bar"
fooDenom = "footoken"
feeDenom = "feetoken"
fee2Denom = "fee2token"
keyBaz = "baz"
keyVesting = "vesting"
keyFooBarBaz = "foobarbaz"
)
var (
startCoins = sdk.Coins{
sdk.NewCoin(feeDenom, sdk.TokensFromTendermintPower(1000000)),
sdk.NewCoin(fee2Denom, sdk.TokensFromTendermintPower(1000000)),
sdk.NewCoin(fooDenom, sdk.TokensFromTendermintPower(1000)),
sdk.NewCoin(denom, sdk.TokensFromTendermintPower(150)),
}
vestingCoins = sdk.Coins{
sdk.NewCoin(feeDenom, sdk.TokensFromTendermintPower(500000)),
}
)
//___________________________________________________________________________________
// Fixtures
// Fixtures is used to setup the testing environment
type Fixtures struct {
ChainID string
RPCAddr string
Port string
GDHome string
GCLIHome string
P2PAddr string
T *testing.T
}
// NewFixtures creates a new instance of Fixtures with many vars set
func NewFixtures(t *testing.T) *Fixtures {
tmpDir, err := ioutil.TempDir("", "gaia_integration_"+t.Name()+"_")
require.NoError(t, err)
servAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
p2pAddr, _, err := server.FreeTCPAddr()
require.NoError(t, err)
return &Fixtures{
T: t,
GDHome: filepath.Join(tmpDir, ".gaiad"),
GCLIHome: filepath.Join(tmpDir, ".gaiacli"),
RPCAddr: servAddr,
P2PAddr: p2pAddr,
Port: port,
}
}
// GenesisFile returns the path of the genesis file
func (f Fixtures) GenesisFile() string {
return filepath.Join(f.GDHome, "config", "genesis.json")
}
// GenesisFile returns the application's genesis state
func (f Fixtures) GenesisState() app.GenesisState {
cdc := codec.New()
genDoc, err := appInit.LoadGenesisDoc(cdc, f.GenesisFile())
require.NoError(f.T, err)
var appState app.GenesisState
require.NoError(f.T, cdc.UnmarshalJSON(genDoc.AppState, &appState))
return appState
}
// InitFixtures is called at the beginning of a test and initializes a chain
// with 1 validator.
func InitFixtures(t *testing.T) (f *Fixtures) {
f = NewFixtures(t)
// reset test state
f.UnsafeResetAll()
// ensure keystore has foo and bar keys
f.KeysDelete(keyFoo)
f.KeysDelete(keyBar)
f.KeysDelete(keyBar)
f.KeysDelete(keyFooBarBaz)
f.KeysAdd(keyFoo)
f.KeysAdd(keyBar)
f.KeysAdd(keyBaz)
f.KeysAdd(keyVesting)
f.KeysAdd(keyFooBarBaz, "--multisig-threshold=2", fmt.Sprintf(
"--multisig=%s,%s,%s", keyFoo, keyBar, keyBaz))
// ensure that CLI output is in JSON format
f.CLIConfig("output", "json")
// NOTE: GDInit sets the ChainID
f.GDInit(keyFoo)
f.CLIConfig("chain-id", f.ChainID)
f.CLIConfig("broadcast-mode", "block")
// start an account with tokens
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
f.AddGenesisAccount(
f.KeyAddress(keyVesting), startCoins,
fmt.Sprintf("--vesting-amount=%s", vestingCoins),
fmt.Sprintf("--vesting-start-time=%d", time.Now().UTC().UnixNano()),
fmt.Sprintf("--vesting-end-time=%d", time.Now().Add(60*time.Second).UTC().UnixNano()),
)
f.GenTx(keyFoo)
f.CollectGenTxs()
return
}
// Cleanup is meant to be run at the end of a test to clean up an remaining test state
func (f *Fixtures) Cleanup(dirs ...string) {
clean := append(dirs, f.GDHome, f.GCLIHome)
for _, d := range clean {
err := os.RemoveAll(d)
require.NoError(f.T, err)
}
}
// Flags returns the flags necessary for making most CLI calls
func (f *Fixtures) Flags() string {
return fmt.Sprintf("--home=%s --node=%s", f.GCLIHome, f.RPCAddr)
}
//___________________________________________________________________________________
// gaiad
// UnsafeResetAll is gaiad unsafe-reset-all
func (f *Fixtures) UnsafeResetAll(flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad --home=%s unsafe-reset-all", f.GDHome)
executeWrite(f.T, addFlags(cmd, flags))
err := os.RemoveAll(filepath.Join(f.GDHome, "config", "gentx"))
require.NoError(f.T, err)
}
// GDInit is gaiad init
// NOTE: GDInit sets the ChainID for the Fixtures instance
func (f *Fixtures) GDInit(moniker string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad init -o --home=%s %s", f.GDHome, moniker)
_, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
var chainID string
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(stderr), &initRes)
require.NoError(f.T, err)
err = json.Unmarshal(initRes["chain_id"], &chainID)
require.NoError(f.T, err)
f.ChainID = chainID
}
// AddGenesisAccount is gaiad add-genesis-account
func (f *Fixtures) AddGenesisAccount(address sdk.AccAddress, coins sdk.Coins, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad add-genesis-account %s %s --home=%s", address, coins, f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
// GenTx is gaiad gentx
func (f *Fixtures) GenTx(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad gentx --name=%s --home=%s --home-client=%s", name, f.GDHome, f.GCLIHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// CollectGenTxs is gaiad collect-gentxs
func (f *Fixtures) CollectGenTxs(flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiad collect-gentxs --home=%s", f.GDHome)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// GDStart runs gaiad start with the appropriate flags and returns a process
func (f *Fixtures) GDStart(flags ...string) *tests.Process {
cmd := fmt.Sprintf("../../../build/gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", f.GDHome, f.RPCAddr, f.P2PAddr)
proc := tests.GoExecuteTWithStdout(f.T, addFlags(cmd, flags))
tests.WaitForTMStart(f.Port)
tests.WaitForNextNBlocksTM(1, f.Port)
return proc
}
// GDTendermint returns the results of gaiad tendermint [query]
func (f *Fixtures) GDTendermint(query string) string {
cmd := fmt.Sprintf("../../../build/gaiad tendermint %s --home=%s", query, f.GDHome)
success, stdout, stderr := executeWriteRetStdStreams(f.T, cmd)
require.Empty(f.T, stderr)
require.True(f.T, success)
return strings.TrimSpace(stdout)
}
// ValidateGenesis runs gaiad validate-genesis
func (f *Fixtures) ValidateGenesis() {
cmd := fmt.Sprintf("../../../build/gaiad validate-genesis --home=%s", f.GDHome)
executeWriteCheckErr(f.T, cmd)
}
//___________________________________________________________________________________
// gaiacli keys
// KeysDelete is gaiacli keys delete
func (f *Fixtures) KeysDelete(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys delete --home=%s %s", f.GCLIHome, name)
executeWrite(f.T, addFlags(cmd, append(append(flags, "-y"), "-f")))
}
// KeysAdd is gaiacli keys add
func (f *Fixtures) KeysAdd(name string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s %s", f.GCLIHome, name)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// KeysAddRecover prepares gaiacli keys add --recover
func (f *Fixtures) KeysAddRecover(name, mnemonic string, flags ...string) (exitSuccess bool, stdout, stderr string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s", f.GCLIHome, name)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
}
// KeysAddRecoverHDPath prepares gaiacli keys add --recover --account --index
func (f *Fixtures) KeysAddRecoverHDPath(name, mnemonic string, account uint32, index uint32, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli keys add --home=%s --recover %s --account %d --index %d", f.GCLIHome, name, account, index)
executeWriteCheckErr(f.T, addFlags(cmd, flags), app.DefaultKeyPass, mnemonic)
}
// KeysShow is gaiacli keys show
func (f *Fixtures) KeysShow(name string, flags ...string) keys.KeyOutput {
cmd := fmt.Sprintf("../../../build/gaiacli keys show --home=%s %s", f.GCLIHome, name)
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ko keys.KeyOutput
err := clientkeys.UnmarshalJSON([]byte(out), &ko)
require.NoError(f.T, err)
return ko
}
// KeyAddress returns the SDK account address from the key
func (f *Fixtures) KeyAddress(name string) sdk.AccAddress {
ko := f.KeysShow(name)
accAddr, err := sdk.AccAddressFromBech32(ko.Address)
require.NoError(f.T, err)
return accAddr
}
//___________________________________________________________________________________
// gaiacli config
// CLIConfig is gaiacli config
func (f *Fixtures) CLIConfig(key, value string, flags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli config --home=%s %s %s", f.GCLIHome, key, value)
executeWriteCheckErr(f.T, addFlags(cmd, flags))
}
//___________________________________________________________________________________
// gaiacli tx send/sign/broadcast
// TxSend is gaiacli tx send
func (f *Fixtures) TxSend(from string, to sdk.AccAddress, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
func (f *Fixtures) txSendWithConfirm(
from string, to sdk.AccAddress, amount sdk.Coin, confirm string, flags ...string,
) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx send %s %s %v --from=%s", to, amount, f.Flags(), from)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), confirm, app.DefaultKeyPass)
}
// TxSign is gaiacli tx sign
func (f *Fixtures) TxSign(signer, fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx sign %v --from=%s %v", f.Flags(), signer, fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxBroadcast is gaiacli tx broadcast
func (f *Fixtures) TxBroadcast(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx broadcast %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxEncode is gaiacli tx encode
func (f *Fixtures) TxEncode(fileName string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx encode %v %v", f.Flags(), fileName)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxMultisign is gaiacli tx multisign
func (f *Fixtures) TxMultisign(fileName, name string, signaturesFiles []string,
flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx multisign %v %s %s %s", f.Flags(),
fileName, name, strings.Join(signaturesFiles, " "),
)
return executeWriteRetStdStreams(f.T, cmd)
}
//___________________________________________________________________________________
// gaiacli tx staking
// TxStakingCreateValidator is gaiacli tx staking create-validator
func (f *Fixtures) TxStakingCreateValidator(from, consPubKey string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx staking create-validator %v --from=%s --pubkey=%s", f.Flags(), from, consPubKey)
cmd += fmt.Sprintf(" --amount=%v --moniker=%v --commission-rate=%v", amount, from, "0.05")
cmd += fmt.Sprintf(" --commission-max-rate=%v --commission-max-change-rate=%v", "0.20", "0.10")
cmd += fmt.Sprintf(" --min-self-delegation=%v", "1")
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxStakingUnbond is gaiacli tx staking unbond
func (f *Fixtures) TxStakingUnbond(from, shares string, validator sdk.ValAddress, flags ...string) bool {
cmd := fmt.Sprintf("../../../build/gaiacli tx staking unbond %s %v --from=%s %v", validator, shares, from, f.Flags())
return executeWrite(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
//___________________________________________________________________________________
// gaiacli tx gov
// TxGovSubmitProposal is gaiacli tx gov submit-proposal
func (f *Fixtures) TxGovSubmitProposal(from, typ, title, description string, deposit sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov submit-proposal %v --from=%s --type=%s", f.Flags(), from, typ)
cmd += fmt.Sprintf(" --title=%s --description=%s --deposit=%s", title, description, deposit)
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxGovDeposit is gaiacli tx gov deposit
func (f *Fixtures) TxGovDeposit(proposalID int, from string, amount sdk.Coin, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov deposit %d %s --from=%s %v", proposalID, amount, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
// TxGovVote is gaiacli tx gov vote
func (f *Fixtures) TxGovVote(proposalID int, option gov.VoteOption, from string, flags ...string) (bool, string, string) {
cmd := fmt.Sprintf("../../../build/gaiacli tx gov vote %d %s --from=%s %v", proposalID, option, from, f.Flags())
return executeWriteRetStdStreams(f.T, addFlags(cmd, flags), app.DefaultKeyPass)
}
//___________________________________________________________________________________
// gaiacli query account
// QueryAccount is gaiacli query account
func (f *Fixtures) QueryAccount(address sdk.AccAddress, flags ...string) auth.BaseAccount {
cmd := fmt.Sprintf("../../../build/gaiacli query account %s %v", address, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var initRes map[string]json.RawMessage
err := json.Unmarshal([]byte(out), &initRes)
require.NoError(f.T, err, "out %v, err %v", out, err)
value := initRes["value"]
var acc auth.BaseAccount
cdc := codec.New()
codec.RegisterCrypto(cdc)
err = cdc.UnmarshalJSON(value, &acc)
require.NoError(f.T, err, "value %v, err %v", string(value), err)
return acc
}
//___________________________________________________________________________________
// gaiacli query txs
// QueryTxs is gaiacli query txs
func (f *Fixtures) QueryTxs(page, limit int, tags ...string) []sdk.TxResponse {
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var txs []sdk.TxResponse
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &txs)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return txs
}
// QueryTxsInvalid query txs with wrong parameters and compare expected error
func (f *Fixtures) QueryTxsInvalid(expectedErr error, page, limit int, tags ...string) {
cmd := fmt.Sprintf("../../../build/gaiacli query txs --page=%d --limit=%d --tags='%s' %v", page, limit, queryTags(tags), f.Flags())
_, err := tests.ExecuteT(f.T, cmd, "")
require.EqualError(f.T, expectedErr, err)
}
//___________________________________________________________________________________
// gaiacli query staking
// QueryStakingValidator is gaiacli query staking validator
func (f *Fixtures) QueryStakingValidator(valAddr sdk.ValAddress, flags ...string) staking.Validator {
cmd := fmt.Sprintf("../../../build/gaiacli query staking validator %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var validator staking.Validator
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &validator)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return validator
}
// QueryStakingUnbondingDelegationsFrom is gaiacli query staking unbonding-delegations-from
func (f *Fixtures) QueryStakingUnbondingDelegationsFrom(valAddr sdk.ValAddress, flags ...string) []staking.UnbondingDelegation {
cmd := fmt.Sprintf("../../../build/gaiacli query staking unbonding-delegations-from %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var ubds []staking.UnbondingDelegation
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &ubds)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return ubds
}
// QueryStakingDelegationsTo is gaiacli query staking delegations-to
func (f *Fixtures) QueryStakingDelegationsTo(valAddr sdk.ValAddress, flags ...string) []staking.Delegation {
cmd := fmt.Sprintf("../../../build/gaiacli query staking delegations-to %s %v", valAddr, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var delegations []staking.Delegation
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &delegations)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return delegations
}
// QueryStakingPool is gaiacli query staking pool
func (f *Fixtures) QueryStakingPool(flags ...string) staking.Pool {
cmd := fmt.Sprintf("../../../build/gaiacli query staking pool %v", f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var pool staking.Pool
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &pool)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return pool
}
// QueryStakingParameters is gaiacli query staking parameters
func (f *Fixtures) QueryStakingParameters(flags ...string) staking.Params {
cmd := fmt.Sprintf("../../../build/gaiacli query staking params %v", f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var params staking.Params
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &params)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return params
}
//___________________________________________________________________________________
// gaiacli query gov
// QueryGovParamDeposit is gaiacli query gov param deposit
func (f *Fixtures) QueryGovParamDeposit() gov.DepositParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param deposit %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var depositParam gov.DepositParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &depositParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return depositParam
}
// QueryGovParamVoting is gaiacli query gov param voting
func (f *Fixtures) QueryGovParamVoting() gov.VotingParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param voting %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var votingParam gov.VotingParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &votingParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return votingParam
}
// QueryGovParamTallying is gaiacli query gov param tallying
func (f *Fixtures) QueryGovParamTallying() gov.TallyParams {
cmd := fmt.Sprintf("../../../build/gaiacli query gov param tallying %s", f.Flags())
out, _ := tests.ExecuteT(f.T, cmd, "")
var tallyingParam gov.TallyParams
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &tallyingParam)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return tallyingParam
}
// QueryGovProposals is gaiacli query gov proposals
func (f *Fixtures) QueryGovProposals(flags ...string) gov.Proposals {
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposals %v", f.Flags())
stdout, stderr := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
if strings.Contains(stderr, "No matching proposals found") {
return gov.Proposals{}
}
require.Empty(f.T, stderr)
var out gov.Proposals
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(stdout), &out)
require.NoError(f.T, err)
return out
}
// QueryGovProposal is gaiacli query gov proposal
func (f *Fixtures) QueryGovProposal(proposalID int, flags ...string) gov.Proposal {
cmd := fmt.Sprintf("../../../build/gaiacli query gov proposal %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var proposal gov.Proposal
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &proposal)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return proposal
}
// QueryGovVote is gaiacli query gov vote
func (f *Fixtures) QueryGovVote(proposalID int, voter sdk.AccAddress, flags ...string) gov.Vote {
cmd := fmt.Sprintf("../../../build/gaiacli query gov vote %d %s %v", proposalID, voter, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var vote gov.Vote
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &vote)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return vote
}
// QueryGovVotes is gaiacli query gov votes
func (f *Fixtures) QueryGovVotes(proposalID int, flags ...string) []gov.Vote {
cmd := fmt.Sprintf("../../../build/gaiacli query gov votes %d %v", proposalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var votes []gov.Vote
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &votes)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return votes
}
// QueryGovDeposit is gaiacli query gov deposit
func (f *Fixtures) QueryGovDeposit(proposalID int, depositor sdk.AccAddress, flags ...string) gov.Deposit {
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposit %d %s %v", proposalID, depositor, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposit gov.Deposit
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &deposit)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return deposit
}
// QueryGovDeposits is gaiacli query gov deposits
func (f *Fixtures) QueryGovDeposits(propsalID int, flags ...string) []gov.Deposit {
cmd := fmt.Sprintf("../../../build/gaiacli query gov deposits %d %v", propsalID, f.Flags())
out, _ := tests.ExecuteT(f.T, addFlags(cmd, flags), "")
var deposits []gov.Deposit
cdc := app.MakeCodec()
err := cdc.UnmarshalJSON([]byte(out), &deposits)
require.NoError(f.T, err, "out %v\n, err %v", out, err)
return deposits
}
//___________________________________________________________________________________
// query slashing
// QuerySigningInfo returns the signing info for a validator
func (f *Fixtures) QuerySigningInfo(val string) slashing.ValidatorSigningInfo {
cmd := fmt.Sprintf("../../../build/gaiacli query slashing signing-info %s %s", val, f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
var sinfo slashing.ValidatorSigningInfo
err := cdc.UnmarshalJSON([]byte(res), &sinfo)
require.NoError(f.T, err)
return sinfo
}
// QuerySlashingParams is gaiacli query slashing params
func (f *Fixtures) QuerySlashingParams() slashing.Params {
cmd := fmt.Sprintf("../../../build/gaiacli query slashing params %s", f.Flags())
res, errStr := tests.ExecuteT(f.T, cmd, "")
require.Empty(f.T, errStr)
cdc := app.MakeCodec()
var params slashing.Params
err := cdc.UnmarshalJSON([]byte(res), &params)
require.NoError(f.T, err)
return params
}
//___________________________________________________________________________________
// executors
func executeWriteCheckErr(t *testing.T, cmdStr string, writes ...string) {
require.True(t, executeWrite(t, cmdStr, writes...))
}
func executeWrite(t *testing.T, cmdStr string, writes ...string) (exitSuccess bool) {
exitSuccess, _, _ = executeWriteRetStdStreams(t, cmdStr, writes...)
return
}
func executeWriteRetStdStreams(t *testing.T, cmdStr string, writes ...string) (bool, string, string) {
proc := tests.GoExecuteT(t, cmdStr)
// Enables use of interactive commands
for _, write := range writes {
_, err := proc.StdinPipe.Write([]byte(write + "\n"))
require.NoError(t, err)
}
// Read both stdout and stderr from the process
stdout, stderr, err := proc.ReadAll()
if err != nil {
fmt.Println("Err on proc.ReadAll()", err, cmdStr)
}
// Log output.
if len(stdout) > 0 {
t.Log("Stdout:", cmn.Green(string(stdout)))
}
if len(stderr) > 0 {
t.Log("Stderr:", cmn.Red(string(stderr)))
}
// Wait for process to exit
proc.Wait()
// Return succes, stdout, stderr
return proc.ExitState.Success(), string(stdout), string(stderr)
}
//___________________________________________________________________________________
// utils
func addFlags(cmd string, flags []string) string {
for _, f := range flags {
cmd += " " + f
}
return strings.TrimSpace(cmd)
}
func queryTags(tags []string) (out string) {
for _, tag := range tags {
out += tag + "&"
}
return strings.TrimSuffix(out, "&")
}
// Write the given string to a new temporary file
func WriteToNewTempFile(t *testing.T, s string) *os.File {
fp, err := ioutil.TempFile(os.TempDir(), "cosmos_cli_test_")
require.Nil(t, err)
_, err = fp.WriteString(s)
require.Nil(t, err)
return fp
}
func marshalStdTx(t *testing.T, stdTx auth.StdTx) []byte {
cdc := app.MakeCodec()
bz, err := cdc.MarshalBinaryBare(stdTx)
require.NoError(t, err)
return bz
}
func unmarshalStdTx(t *testing.T, s string) (stdTx auth.StdTx) {
cdc := app.MakeCodec()
require.Nil(t, cdc.UnmarshalJSON([]byte(s), &stdTx))
return
}

View File

@ -1,32 +1,52 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package main package main
import ( import (
"fmt" "fmt"
"net/http"
"os" "os"
"path" "path"
"github.com/cosmos/cosmos-sdk/x/mint"
"github.com/rakyll/statik/fs"
"github.com/spf13/cobra"
"github.com/spf13/viper"
amino "github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/cli"
"github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/lcd"
"github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
sdk "github.com/cosmos/cosmos-sdk/types" sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/version"
"github.com/cosmos/cosmos-sdk/x/auth"
at "github.com/cosmos/cosmos-sdk/x/auth"
auth "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
bank "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
dist "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
gv "github.com/cosmos/cosmos-sdk/x/gov"
gov "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
mintrest "github.com/cosmos/cosmos-sdk/x/mint/client/rest"
sl "github.com/cosmos/cosmos-sdk/x/slashing"
slashing "github.com/cosmos/cosmos-sdk/x/slashing/client/rest"
st "github.com/cosmos/cosmos-sdk/x/staking"
staking "github.com/cosmos/cosmos-sdk/x/staking/client/rest"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/bank"
bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli"
crisisclient "github.com/cosmos/cosmos-sdk/x/crisis/client"
distcmd "github.com/cosmos/cosmos-sdk/x/distribution"
distClient "github.com/cosmos/cosmos-sdk/x/distribution/client"
govClient "github.com/cosmos/cosmos-sdk/x/gov/client"
mintclient "github.com/cosmos/cosmos-sdk/x/mint/client"
slashingclient "github.com/cosmos/cosmos-sdk/x/slashing/client"
stakingclient "github.com/cosmos/cosmos-sdk/x/staking/client"
"github.com/spf13/cobra" _ "github.com/cosmos/cosmos-sdk/client/lcd/statik"
"github.com/spf13/viper"
"github.com/tendermint/go-amino"
"github.com/tendermint/tendermint/libs/cli"
"github.com/kava-labs/_/app"
) )
func main() { func main() {
@ -38,16 +58,29 @@ func main() {
// Read in the configuration file for the sdk // Read in the configuration file for the sdk
config := sdk.GetConfig() config := sdk.GetConfig()
app.SetAddressPrefixes(config) config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
config.Seal() config.Seal()
// TODO: setup keybase, viper object, etc. to be passed into // TODO: setup keybase, viper object, etc. to be passed into
// the below functions and eliminate global vars, like we do // the below functions and eliminate global vars, like we do
// with the cdc // with the cdc
// Module clients hold cli commnads (tx,query) and lcd routes
// TODO: Make the lcd command take a list of ModuleClient
mc := []sdk.ModuleClients{
govClient.NewModuleClient(gv.StoreKey, cdc),
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingclient.NewModuleClient(st.StoreKey, cdc),
mintclient.NewModuleClient(mint.StoreKey, cdc),
slashingclient.NewModuleClient(sl.StoreKey, cdc),
crisisclient.NewModuleClient(sl.StoreKey, cdc),
}
rootCmd := &cobra.Command{ rootCmd := &cobra.Command{
Use: "kvcli", Use: "gaiacli",
Short: "Command line interface for interacting with kvd", Short: "Command line interface for interacting with gaiad",
} }
// Add --chain-id to persistent flags and mark it required // Add --chain-id to persistent flags and mark it required
@ -60,14 +93,14 @@ func main() {
rootCmd.AddCommand( rootCmd.AddCommand(
rpc.StatusCommand(), rpc.StatusCommand(),
client.ConfigCmd(app.DefaultCLIHome), client.ConfigCmd(app.DefaultCLIHome),
queryCmd(cdc), queryCmd(cdc, mc),
txCmd(cdc), txCmd(cdc, mc),
client.LineBreak, client.LineBreak,
lcd.ServeCommand(cdc, registerRoutes), lcd.ServeCommand(cdc, registerRoutes),
client.LineBreak, client.LineBreak,
keys.Commands(), keys.Commands(),
client.LineBreak, client.LineBreak,
version.Cmd, version.VersionCmd,
client.NewCompletionCmd(rootCmd, true), client.NewCompletionCmd(rootCmd, true),
) )
@ -81,7 +114,7 @@ func main() {
} }
} }
func queryCmd(cdc *amino.Codec) *cobra.Command { func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
queryCmd := &cobra.Command{ queryCmd := &cobra.Command{
Use: "query", Use: "query",
Aliases: []string{"q"}, Aliases: []string{"q"},
@ -89,22 +122,25 @@ func queryCmd(cdc *amino.Codec) *cobra.Command {
} }
queryCmd.AddCommand( queryCmd.AddCommand(
authcmd.GetAccountCmd(cdc),
client.LineBreak,
rpc.ValidatorCommand(cdc), rpc.ValidatorCommand(cdc),
rpc.BlockCommand(), rpc.BlockCommand(),
tx.SearchTxCmd(cdc), tx.SearchTxCmd(cdc),
tx.QueryTxCmd(cdc), tx.QueryTxCmd(cdc),
client.LineBreak, client.LineBreak,
authcmd.GetAccountCmd(at.StoreKey, cdc),
) )
// add modules' query commands for _, m := range mc {
app.ModuleBasics.AddQueryCommands(queryCmd, cdc) mQueryCmd := m.GetQueryCmd()
if mQueryCmd != nil {
queryCmd.AddCommand(mQueryCmd)
}
}
return queryCmd return queryCmd
} }
func txCmd(cdc *amino.Codec) *cobra.Command { func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
txCmd := &cobra.Command{ txCmd := &cobra.Command{
Use: "tx", Use: "tx",
Short: "Transactions subcommands", Short: "Transactions subcommands",
@ -115,25 +151,14 @@ func txCmd(cdc *amino.Codec) *cobra.Command {
client.LineBreak, client.LineBreak,
authcmd.GetSignCommand(cdc), authcmd.GetSignCommand(cdc),
authcmd.GetMultiSignCommand(cdc), authcmd.GetMultiSignCommand(cdc),
client.LineBreak,
tx.GetBroadcastCommand(cdc), tx.GetBroadcastCommand(cdc),
tx.GetEncodeCommand(cdc), tx.GetEncodeCommand(cdc),
client.LineBreak, client.LineBreak,
) )
// add modules' tx commands for _, m := range mc {
app.ModuleBasics.AddTxCommands(txCmd, cdc) txCmd.AddCommand(m.GetTxCmd())
// remove auth and bank commands as they're mounted under the root tx command
var cmdsToRemove []*cobra.Command
for _, cmd := range txCmd.Commands() {
if cmd.Use == auth.ModuleName || cmd.Use == bank.ModuleName {
cmdsToRemove = append(cmdsToRemove, cmd)
} }
}
txCmd.RemoveCommand(cmdsToRemove...)
return txCmd return txCmd
} }
@ -142,8 +167,25 @@ func txCmd(cdc *amino.Codec) *cobra.Command {
// NOTE: details on the routes added for each module are in the module documentation // NOTE: details on the routes added for each module are in the module documentation
// NOTE: If making updates here you also need to update the test helper in client/lcd/test_helper.go // NOTE: If making updates here you also need to update the test helper in client/lcd/test_helper.go
func registerRoutes(rs *lcd.RestServer) { func registerRoutes(rs *lcd.RestServer) {
client.RegisterRoutes(rs.CliCtx, rs.Mux) registerSwaggerUI(rs)
app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
tx.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
auth.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, at.StoreKey)
bank.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
dist.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, distcmd.StoreKey)
staking.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
slashing.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc, rs.KeyBase)
gov.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
mintrest.RegisterRoutes(rs.CliCtx, rs.Mux, rs.Cdc)
}
func registerSwaggerUI(rs *lcd.RestServer) {
statikFS, err := fs.New()
if err != nil {
panic(err)
}
staticServer := http.FileServer(statikFS)
rs.Mux.PathPrefix("/swagger-ui/").Handler(http.StripPrefix("/swagger-ui/", staticServer))
} }
func initConfig(cmd *cobra.Command) error { func initConfig(cmd *cobra.Command) error {

View File

@ -1,6 +1,3 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package main package main
import ( import (
@ -10,22 +7,19 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
genaccscli "github.com/cosmos/cosmos-sdk/x/auth/genaccounts/client/cli"
genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli"
"github.com/cosmos/cosmos-sdk/x/staking"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/libs/cli" "github.com/tendermint/tendermint/libs/cli"
dbm "github.com/tendermint/tendermint/libs/db" dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/libs/log"
tmtypes "github.com/tendermint/tendermint/types" tmtypes "github.com/tendermint/tendermint/types"
"github.com/kava-labs/_/app" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
) )
// gaiad custom flags // gaiad custom flags
@ -37,45 +31,45 @@ func main() {
cdc := app.MakeCodec() cdc := app.MakeCodec()
config := sdk.GetConfig() config := sdk.GetConfig()
app.SetAddressPrefixes(config) config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
config.Seal() config.Seal()
ctx := server.NewDefaultContext() ctx := server.NewDefaultContext()
cobra.EnableCommandSorting = false cobra.EnableCommandSorting = false
rootCmd := &cobra.Command{ rootCmd := &cobra.Command{
Use: "kvd", Use: "gaiad",
Short: "Kava Daemon (server)", Short: "Gaia Daemon (server)",
PersistentPreRunE: server.PersistentPreRunEFn(ctx), PersistentPreRunE: server.PersistentPreRunEFn(ctx),
} }
rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome)) rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc))
rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, genaccounts.AppModuleBasic{}, app.DefaultNodeHome)) rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc))
rootCmd.AddCommand(genutilcli.GenTxCmd(ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{}, rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc))
genaccounts.AppModuleBasic{}, app.DefaultNodeHome, app.DefaultCLIHome)) rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics)) rootCmd.AddCommand(gaiaInit.AddGenesisAccountCmd(ctx, cdc))
rootCmd.AddCommand(genaccscli.AddGenesisAccountCmd(ctx, cdc, app.DefaultNodeHome, app.DefaultCLIHome)) rootCmd.AddCommand(gaiaInit.ValidateGenesisCmd(ctx, cdc))
rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true)) rootCmd.AddCommand(client.NewCompletionCmd(rootCmd, true))
rootCmd.AddCommand(testnetCmd(ctx, cdc, app.ModuleBasics, genaccounts.AppModuleBasic{}))
rootCmd.AddCommand(replayCmd())
server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators) server.AddCommands(ctx, cdc, rootCmd, newApp, exportAppStateAndTMValidators)
// prepare and add flags // prepare and add flags
executor := cli.PrepareBaseCmd(rootCmd, "KA", app.DefaultNodeHome) executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome)
rootCmd.PersistentFlags().UintVar(&invCheckPeriod, flagInvCheckPeriod, rootCmd.PersistentFlags().UintVar(&invCheckPeriod, flagInvCheckPeriod,
0, "Assert registered invariants every N blocks") 0, "Assert registered invariants every N blocks")
err := executor.Execute() err := executor.Execute()
if err != nil { if err != nil {
// handle with #870
panic(err) panic(err)
} }
} }
func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application { func newApp(logger log.Logger, db dbm.DB, traceStore io.Writer) abci.Application {
return app.NewApp( return app.NewGaiaApp(
logger, db, traceStore, true, invCheckPeriod, logger, db, traceStore, true, invCheckPeriod,
baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))), baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))),
baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)), baseapp.SetMinGasPrices(viper.GetString(server.FlagMinGasPrices)),
baseapp.SetHaltHeight(uint64(viper.GetInt(server.FlagHaltHeight))),
) )
} }
@ -84,13 +78,13 @@ func exportAppStateAndTMValidators(
) (json.RawMessage, []tmtypes.GenesisValidator, error) { ) (json.RawMessage, []tmtypes.GenesisValidator, error) {
if height != -1 { if height != -1 {
appStruct := app.NewApp(logger, db, traceStore, false, uint(1)) gApp := app.NewGaiaApp(logger, db, traceStore, false, uint(1))
err := appStruct.LoadHeight(height) err := gApp.LoadHeight(height)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
return appStruct.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
} }
appStruct := app.NewApp(logger, db, traceStore, true, uint(1)) gApp := app.NewGaiaApp(logger, db, traceStore, true, uint(1))
return appStruct.ExportAppStateAndValidators(forZeroHeight, jailWhiteList) return gApp.ExportAppStateAndValidators(forZeroHeight, jailWhiteList)
} }

View File

@ -0,0 +1,35 @@
# Gaiadebug
Simple tool for simple debugging.
We try to accept both hex and base64 formats and provide a useful response.
Note we often encode bytes as hex in the logs, but as base64 in the JSON.
## Pubkeys
The following give the same result:
```
gaiadebug pubkey TZTQnfqOsi89SeoXVnIw+tnFJnr4X8qVC0U8AsEmFk4=
gaiadebug pubkey 4D94D09DFA8EB22F3D49EA17567230FAD9C5267AF85FCA950B453C02C126164E
```
## Txs
Pass in a hex/base64 tx and get back the full JSON
```
gaiadebug tx <hex or base64 transaction>
```
## Hack
This is a command with boilerplate for using Go as a scripting language to hack
on an existing Gaia state.
Currently we have an example for the state of gaia-6001 after it
[crashed](https://github.com/cosmos/cosmos-sdk/blob/master/cmd/gaia/testnets/STATUS.md#june-13-2018-230-est---published-postmortem-of-gaia-6001-failure).
If you run `gaiadebug hack $HOME/.gaiad` on that
state, it will do a binary search on the state history to find when the state
invariant was violated.

268
gaia/cmd/gaiadebug/hack.go Normal file
View File

@ -0,0 +1,268 @@
package main
import (
"encoding/base64"
"encoding/hex"
"fmt"
"os"
"path"
"github.com/cosmos/cosmos-sdk/store"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/spf13/cobra"
"github.com/spf13/viper"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto/ed25519"
cmn "github.com/tendermint/tendermint/libs/common"
dbm "github.com/tendermint/tendermint/libs/db"
"github.com/tendermint/tendermint/libs/log"
bam "github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/bank"
"github.com/cosmos/cosmos-sdk/x/params"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/staking"
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
)
func runHackCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected 1 arg")
}
// ".gaiad"
dataDir := args[0]
dataDir = path.Join(dataDir, "data")
// load the app
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout))
db, err := sdk.NewLevelDB("gaia", dataDir)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
app := NewGaiaApp(logger, db, baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))))
// print some info
id := app.LastCommitID()
lastBlockHeight := app.LastBlockHeight()
fmt.Println("ID", id)
fmt.Println("LastBlockHeight", lastBlockHeight)
//----------------------------------------------------
// XXX: start hacking!
//----------------------------------------------------
// eg. gaia-6001 testnet bug
// We paniced when iterating through the "bypower" keys.
// The following powerKey was there, but the corresponding "trouble" validator did not exist.
// So here we do a binary search on the past states to find when the powerKey first showed up ...
// operator of the validator the bonds, gets jailed, later unbonds, and then later is still found in the bypower store
trouble := hexToBytes("D3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
// this is his "bypower" key
powerKey := hexToBytes("05303030303030303030303033FFFFFFFFFFFF4C0C0000FFFED3DC0FF59F7C3B548B7AFA365561B87FD0208AF8")
topHeight := lastBlockHeight
bottomHeight := int64(0)
checkHeight := topHeight
for {
// load the given version of the state
err = app.LoadVersion(checkHeight, app.keyMain)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
ctx := app.NewContext(true, abci.Header{})
// check for the powerkey and the validator from the store
store := ctx.KVStore(app.keyStaking)
res := store.Get(powerKey)
val, _ := app.stakingKeeper.GetValidator(ctx, trouble)
fmt.Println("checking height", checkHeight, res, val)
if res == nil {
bottomHeight = checkHeight
} else {
topHeight = checkHeight
}
checkHeight = (topHeight + bottomHeight) / 2
}
}
func base64ToPub(b64 string) ed25519.PubKeyEd25519 {
data, _ := base64.StdEncoding.DecodeString(b64)
var pubKey ed25519.PubKeyEd25519
copy(pubKey[:], data)
return pubKey
}
func hexToBytes(h string) []byte {
trouble, _ := hex.DecodeString(h)
return trouble
}
//--------------------------------------------------------------------------------
// NOTE: This is all copied from gaia/app/app.go
// so we can access internal fields!
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
cdc *codec.Codec
// keys to access the substores
keyMain *sdk.KVStoreKey
keyAccount *sdk.KVStoreKey
keyStaking *sdk.KVStoreKey
tkeyStaking *sdk.TransientStoreKey
keySlashing *sdk.KVStoreKey
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// Manage getting and setting accounts
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
stakingKeeper staking.Keeper
slashingKeeper slashing.Keeper
paramsKeeper params.Keeper
}
func NewGaiaApp(logger log.Logger, db dbm.DB, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
cdc := MakeCodec()
bApp := bam.NewBaseApp(appName, logger, db, auth.DefaultTxDecoder(cdc), baseAppOptions...)
bApp.SetCommitMultiStoreTracer(os.Stdout)
// create your application object
var app = &GaiaApp{
BaseApp: bApp,
cdc: cdc,
keyMain: sdk.NewKVStoreKey(bam.MainStoreKey),
keyAccount: sdk.NewKVStoreKey(auth.StoreKey),
keyStaking: sdk.NewKVStoreKey(staking.StoreKey),
tkeyStaking: sdk.NewTransientStoreKey(staking.TStoreKey),
keySlashing: sdk.NewKVStoreKey(slashing.StoreKey),
keyParams: sdk.NewKVStoreKey(params.StoreKey),
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
}
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams)
// define the accountKeeper
app.accountKeeper = auth.NewAccountKeeper(
app.cdc,
app.keyAccount, // target store
app.paramsKeeper.Subspace(auth.DefaultParamspace),
auth.ProtoBaseAccount, // prototype
)
// add handlers
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, app.paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace)
app.stakingKeeper = staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace)
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, app.stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace), slashing.DefaultCodespace)
// register message routes
app.Router().
AddRoute("bank", bank.NewHandler(app.bankKeeper)).
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper))
// initialize BaseApp
app.SetInitChainer(app.initChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetEndBlocker(app.EndBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper))
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keySlashing, app.keyParams)
app.MountStore(app.tkeyParams, sdk.StoreTypeTransient)
err := app.LoadLatestVersion(app.keyMain)
if err != nil {
cmn.Exit(err.Error())
}
app.Seal()
return app
}
// custom tx codec
func MakeCodec() *codec.Codec {
var cdc = codec.New()
bank.RegisterCodec(cdc)
staking.RegisterCodec(cdc)
slashing.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
cdc.Seal()
return cdc
}
// application updates every end block
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
return abci.ResponseBeginBlock{
Tags: tags.ToKVPairs(),
}
}
// application updates every end block
// nolint: unparam
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates, tags := staking.EndBlocker(ctx, app.stakingKeeper)
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
Tags: tags,
}
}
// custom logic for gaia initialization
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
stateJSON := req.AppStateBytes
// TODO is this now the whole genesis file?
var genesisState gaia.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, "")
}
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
app.accountKeeper.SetAccount(ctx, acc)
}
// load the initial staking information
validators, err := staking.InitGenesis(ctx, app.stakingKeeper, genesisState.StakingData)
if err != nil {
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "")
}
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
return abci.ResponseInitChain{
Validators: validators,
}
}

256
gaia/cmd/gaiadebug/main.go Normal file
View File

@ -0,0 +1,256 @@
package main
import (
"bytes"
"encoding/base64"
"encoding/hex"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/crypto/ed25519"
gaia "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
func init() {
config := sdk.GetConfig()
config.SetBech32PrefixForAccount(sdk.Bech32PrefixAccAddr, sdk.Bech32PrefixAccPub)
config.SetBech32PrefixForValidator(sdk.Bech32PrefixValAddr, sdk.Bech32PrefixValPub)
config.SetBech32PrefixForConsensusNode(sdk.Bech32PrefixConsAddr, sdk.Bech32PrefixConsPub)
config.Seal()
rootCmd.AddCommand(txCmd)
rootCmd.AddCommand(pubkeyCmd)
rootCmd.AddCommand(addrCmd)
rootCmd.AddCommand(hackCmd)
rootCmd.AddCommand(rawBytesCmd)
}
var rootCmd = &cobra.Command{
Use: "gaiadebug",
Short: "Gaia debug tool",
SilenceUsage: true,
}
var txCmd = &cobra.Command{
Use: "tx",
Short: "Decode a gaia tx from hex or base64",
RunE: runTxCmd,
}
var pubkeyCmd = &cobra.Command{
Use: "pubkey",
Short: "Decode a pubkey from hex, base64, or bech32",
RunE: runPubKeyCmd,
}
var addrCmd = &cobra.Command{
Use: "addr",
Short: "Convert an address between hex and bech32",
RunE: runAddrCmd,
}
var hackCmd = &cobra.Command{
Use: "hack",
Short: "Boilerplate to Hack on an existing state by scripting some Go...",
RunE: runHackCmd,
}
var rawBytesCmd = &cobra.Command{
Use: "raw-bytes",
Short: "Convert raw bytes output (eg. [10 21 13 255]) to hex",
RunE: runRawBytesCmd,
}
func runRawBytesCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
stringBytes := args[0]
stringBytes = strings.Trim(stringBytes, "[")
stringBytes = strings.Trim(stringBytes, "]")
spl := strings.Split(stringBytes, " ")
byteArray := []byte{}
for _, s := range spl {
b, err := strconv.Atoi(s)
if err != nil {
return err
}
byteArray = append(byteArray, byte(b))
}
fmt.Printf("%X\n", byteArray)
return nil
}
func runPubKeyCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
pubkeyString := args[0]
var pubKeyI crypto.PubKey
// try hex, then base64, then bech32
pubkeyBytes, err := hex.DecodeString(pubkeyString)
if err != nil {
var err2 error
pubkeyBytes, err2 = base64.StdEncoding.DecodeString(pubkeyString)
if err2 != nil {
var err3 error
pubKeyI, err3 = sdk.GetAccPubKeyBech32(pubkeyString)
if err3 != nil {
var err4 error
pubKeyI, err4 = sdk.GetValPubKeyBech32(pubkeyString)
if err4 != nil {
var err5 error
pubKeyI, err5 = sdk.GetConsPubKeyBech32(pubkeyString)
if err5 != nil {
return fmt.Errorf(`Expected hex, base64, or bech32. Got errors:
hex: %v,
base64: %v
bech32 Acc: %v
bech32 Val: %v
bech32 Cons: %v`,
err, err2, err3, err4, err5)
}
}
}
}
}
var pubKey ed25519.PubKeyEd25519
if pubKeyI == nil {
copy(pubKey[:], pubkeyBytes)
} else {
pubKey = pubKeyI.(ed25519.PubKeyEd25519)
pubkeyBytes = pubKey[:]
}
cdc := gaia.MakeCodec()
pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey)
if err != nil {
return err
}
accPub, err := sdk.Bech32ifyAccPub(pubKey)
if err != nil {
return err
}
valPub, err := sdk.Bech32ifyValPub(pubKey)
if err != nil {
return err
}
consenusPub, err := sdk.Bech32ifyConsPub(pubKey)
if err != nil {
return err
}
fmt.Println("Address:", pubKey.Address())
fmt.Printf("Hex: %X\n", pubkeyBytes)
fmt.Println("JSON (base64):", string(pubKeyJSONBytes))
fmt.Println("Bech32 Acc:", accPub)
fmt.Println("Bech32 Validator Operator:", valPub)
fmt.Println("Bech32 Validator Consensus:", consenusPub)
return nil
}
func runAddrCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
addrString := args[0]
var addr []byte
// try hex, then bech32
var err error
addr, err = hex.DecodeString(addrString)
if err != nil {
var err2 error
addr, err2 = sdk.AccAddressFromBech32(addrString)
if err2 != nil {
var err3 error
addr, err3 = sdk.ValAddressFromBech32(addrString)
if err3 != nil {
return fmt.Errorf(`Expected hex or bech32. Got errors:
hex: %v,
bech32 acc: %v
bech32 val: %v
`, err, err2, err3)
}
}
}
accAddr := sdk.AccAddress(addr)
valAddr := sdk.ValAddress(addr)
fmt.Println("Address:", addr)
fmt.Printf("Address (hex): %X\n", addr)
fmt.Printf("Bech32 Acc: %s\n", accAddr)
fmt.Printf("Bech32 Val: %s\n", valAddr)
return nil
}
func runTxCmd(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("Expected single arg")
}
txString := args[0]
// try hex, then base64
txBytes, err := hex.DecodeString(txString)
if err != nil {
var err2 error
txBytes, err2 = base64.StdEncoding.DecodeString(txString)
if err2 != nil {
return fmt.Errorf(`Expected hex or base64. Got errors:
hex: %v,
base64: %v
`, err, err2)
}
}
var tx = auth.StdTx{}
cdc := gaia.MakeCodec()
err = cdc.UnmarshalBinaryLengthPrefixed(txBytes, &tx)
if err != nil {
return err
}
bz, err := cdc.MarshalJSON(tx)
if err != nil {
return err
}
buf := bytes.NewBuffer([]byte{})
err = json.Indent(buf, bz, "", " ")
if err != nil {
return err
}
fmt.Println(buf.String())
return nil
}
func main() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
os.Exit(0)
}

View File

@ -0,0 +1,59 @@
package main
import (
"encoding/hex"
"fmt"
"os"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/tendermint/tendermint/libs/bech32"
)
var bech32Prefixes = []string{
sdk.Bech32PrefixAccAddr,
sdk.Bech32PrefixAccPub,
sdk.Bech32PrefixValAddr,
sdk.Bech32PrefixValPub,
sdk.Bech32PrefixConsAddr,
sdk.Bech32PrefixConsPub,
}
func main() {
if len(os.Args) < 2 {
fmt.Println("Must specify an input string")
}
arg := os.Args[1]
runFromBech32(arg)
runFromHex(arg)
}
// Print info from bech32.
func runFromBech32(bech32str string) {
hrp, bz, err := bech32.DecodeAndConvert(bech32str)
if err != nil {
fmt.Println("Not a valid bech32 string")
return
}
fmt.Println("Bech32 parse:")
fmt.Printf("Human readible part: %v\nBytes (hex): %X\n",
hrp,
bz,
)
}
func runFromHex(hexaddr string) {
bz, err := hex.DecodeString(hexaddr)
if err != nil {
fmt.Println("Not a valid hex string")
return
}
fmt.Println("Hex parse:")
fmt.Println("Bech32 formats:")
for _, prefix := range bech32Prefixes {
bech32Addr, err := bech32.ConvertAndEncode(prefix, bz)
if err != nil {
panic(err)
}
fmt.Println(" - " + bech32Addr)
}
}

View File

@ -1,6 +1,3 @@
// Copyright 2016 All in Bits, inc
// Modifications copyright 2019 Kava Labs
package main package main
import ( import (
@ -10,13 +7,11 @@ import (
"path/filepath" "path/filepath"
"time" "time"
"github.com/cosmos/cosmos-sdk/store"
cpm "github.com/otiai10/copy" cpm "github.com/otiai10/copy"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/store"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types" abci "github.com/tendermint/tendermint/abci/types"
bcm "github.com/tendermint/tendermint/blockchain" bcm "github.com/tendermint/tendermint/blockchain"
cmn "github.com/tendermint/tendermint/libs/common" cmn "github.com/tendermint/tendermint/libs/common"
@ -24,32 +19,49 @@ import (
tmsm "github.com/tendermint/tendermint/state" tmsm "github.com/tendermint/tendermint/state"
tm "github.com/tendermint/tendermint/types" tm "github.com/tendermint/tendermint/types"
"github.com/kava-labs/_/app" "github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
) )
func replayCmd() *cobra.Command { var (
return &cobra.Command{ rootDir string
Use: "replay <root-dir>", )
Short: "Replay transactions",
RunE: func(_ *cobra.Command, args []string) error { var rootCmd = &cobra.Command{
return replayTxs(args[0]) Use: "gaiareplay",
Short: "Replay gaia transactions",
Run: func(cmd *cobra.Command, args []string) {
run(rootDir)
}, },
Args: cobra.ExactArgs(1), }
func init() {
// cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&rootDir, "root", "r", "root dir")
}
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(1)
} }
} }
func replayTxs(rootDir string) error { func run(rootDir string) {
if false { if false {
// Copy the rootDir to a new directory, to preserve the old one. // Copy the rootDir to a new directory, to preserve the old one.
fmt.Fprintln(os.Stderr, "Copying rootdir over") fmt.Println("Copying rootdir over")
oldRootDir := rootDir oldRootDir := rootDir
rootDir = oldRootDir + "_replay" rootDir = oldRootDir + "_replay"
if cmn.FileExists(rootDir) { if cmn.FileExists(rootDir) {
cmn.Exit(fmt.Sprintf("temporary copy dir %v already exists", rootDir)) cmn.Exit(fmt.Sprintf("temporary copy dir %v already exists", rootDir))
} }
if err := cpm.Copy(oldRootDir, rootDir); err != nil { err := cpm.Copy(oldRootDir, rootDir)
return err if err != nil {
panic(err)
} }
} }
@ -59,25 +71,25 @@ func replayTxs(rootDir string) error {
// App DB // App DB
// appDB := dbm.NewMemDB() // appDB := dbm.NewMemDB()
fmt.Fprintln(os.Stderr, "Opening app database") fmt.Println("Opening app database")
appDB, err := sdk.NewLevelDB("application", dataDir) appDB, err := sdk.NewLevelDB("application", dataDir)
if err != nil { if err != nil {
return err panic(err)
} }
// TM DB // TM DB
// tmDB := dbm.NewMemDB() // tmDB := dbm.NewMemDB()
fmt.Fprintln(os.Stderr, "Opening tendermint state database") fmt.Println("Opening tendermint state database")
tmDB, err := sdk.NewLevelDB("state", dataDir) tmDB, err := sdk.NewLevelDB("state", dataDir)
if err != nil { if err != nil {
return err panic(err)
} }
// Blockchain DB // Blockchain DB
fmt.Fprintln(os.Stderr, "Opening blockstore database") fmt.Println("Opening blockstore database")
bcDB, err := sdk.NewLevelDB("blockstore", dataDir) bcDB, err := sdk.NewLevelDB("blockstore", dataDir)
if err != nil { if err != nil {
return err panic(err)
} }
// TraceStore // TraceStore
@ -89,12 +101,12 @@ func replayTxs(rootDir string) error {
0666, 0666,
) )
if err != nil { if err != nil {
return err panic(err)
} }
// Application // Application
fmt.Fprintln(os.Stderr, "Creating application") fmt.Println("Creating application")
myapp := app.NewApp( myapp := app.NewGaiaApp(
ctx.Logger, appDB, traceStoreWriter, true, uint(1), ctx.Logger, appDB, traceStoreWriter, true, uint(1),
baseapp.SetPruning(store.PruneEverything), // nothing baseapp.SetPruning(store.PruneEverything), // nothing
) )
@ -103,11 +115,11 @@ func replayTxs(rootDir string) error {
var genDocPath = filepath.Join(configDir, "genesis.json") var genDocPath = filepath.Join(configDir, "genesis.json")
genDoc, err := tm.GenesisDocFromFile(genDocPath) genDoc, err := tm.GenesisDocFromFile(genDocPath)
if err != nil { if err != nil {
return err panic(err)
} }
genState, err := tmsm.MakeGenesisState(genDoc) genState, err := tmsm.MakeGenesisState(genDoc)
if err != nil { if err != nil {
return err panic(err)
} }
// tmsm.SaveState(tmDB, genState) // tmsm.SaveState(tmDB, genState)
@ -115,7 +127,7 @@ func replayTxs(rootDir string) error {
proxyApp := proxy.NewAppConns(cc) proxyApp := proxy.NewAppConns(cc)
err = proxyApp.Start() err = proxyApp.Start()
if err != nil { if err != nil {
return err panic(err)
} }
defer func() { defer func() {
_ = proxyApp.Stop() _ = proxyApp.Stop()
@ -124,7 +136,7 @@ func replayTxs(rootDir string) error {
state := tmsm.LoadState(tmDB) state := tmsm.LoadState(tmDB)
if state.LastBlockHeight == 0 { if state.LastBlockHeight == 0 {
// Send InitChain msg // Send InitChain msg
fmt.Fprintln(os.Stderr, "Sending InitChain msg") fmt.Println("Sending InitChain msg")
validators := tm.TM2PB.ValidatorUpdates(genState.Validators) validators := tm.TM2PB.ValidatorUpdates(genState.Validators)
csParams := tm.TM2PB.ConsensusParams(genDoc.ConsensusParams) csParams := tm.TM2PB.ConsensusParams(genDoc.ConsensusParams)
req := abci.RequestInitChain{ req := abci.RequestInitChain{
@ -136,11 +148,11 @@ func replayTxs(rootDir string) error {
} }
res, err := proxyApp.Consensus().InitChainSync(req) res, err := proxyApp.Consensus().InitChainSync(req)
if err != nil { if err != nil {
return err panic(err)
} }
newValidatorz, err := tm.PB2TM.ValidatorUpdates(res.Validators) newValidatorz, err := tm.PB2TM.ValidatorUpdates(res.Validators)
if err != nil { if err != nil {
return err panic(err)
} }
newValidators := tm.NewValidatorSet(newValidatorz) newValidators := tm.NewValidatorSet(newValidatorz)
@ -151,17 +163,17 @@ func replayTxs(rootDir string) error {
} }
// Create executor // Create executor
fmt.Fprintln(os.Stderr, "Creating block executor") fmt.Println("Creating block executor")
blockExec := tmsm.NewBlockExecutor(tmDB, ctx.Logger, proxyApp.Consensus(), blockExec := tmsm.NewBlockExecutor(tmDB, ctx.Logger, proxyApp.Consensus(),
tmsm.MockMempool{}, tmsm.MockEvidencePool{}) tmsm.MockMempool{}, tmsm.MockEvidencePool{})
// Create block store // Create block store
fmt.Fprintln(os.Stderr, "Creating block store") fmt.Println("Creating block store")
blockStore := bcm.NewBlockStore(bcDB) blockStore := bcm.NewBlockStore(bcDB)
tz := []time.Duration{0, 0, 0} tz := []time.Duration{0, 0, 0}
for i := int(state.LastBlockHeight) + 1; ; i++ { for i := int(state.LastBlockHeight) + 1; ; i++ {
fmt.Fprintln(os.Stderr, "Running block ", i) fmt.Println("Running block ", i)
t1 := time.Now() t1 := time.Now()
// Apply block // Apply block
@ -169,25 +181,26 @@ func replayTxs(rootDir string) error {
blockmeta := blockStore.LoadBlockMeta(int64(i)) blockmeta := blockStore.LoadBlockMeta(int64(i))
if blockmeta == nil { if blockmeta == nil {
fmt.Printf("Couldn't find block meta %d... done?\n", i) fmt.Printf("Couldn't find block meta %d... done?\n", i)
return nil return
} }
block := blockStore.LoadBlock(int64(i)) block := blockStore.LoadBlock(int64(i))
if block == nil { if block == nil {
return fmt.Errorf("couldn't find block %d", i) panic(fmt.Sprintf("couldn't find block %d", i))
} }
t2 := time.Now() t2 := time.Now()
state, err = blockExec.ApplyBlock(state, blockmeta.BlockID, block) state, err = blockExec.ApplyBlock(state, blockmeta.BlockID, block)
if err != nil { if err != nil {
return err panic(err)
} }
t3 := time.Now() t3 := time.Now()
tz[0] += t2.Sub(t1) tz[0] += t2.Sub(t1)
tz[1] += t3.Sub(t2) tz[1] += t3.Sub(t2)
fmt.Fprintf(os.Stderr, "new app hash: %X\n", state.AppHash) fmt.Printf("new app hash: %X\n", state.AppHash)
fmt.Fprintln(os.Stderr, tz) fmt.Println(tz)
} }
} }

145
gaia/init/collect.go Normal file
View File

@ -0,0 +1,145 @@
package init
// DONTCOVER
import (
"encoding/json"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/x/auth"
)
const (
flagGenTxDir = "gentx-dir"
)
type initConfig struct {
ChainID string
GenTxsDir string
Name string
NodeID string
ValPubKey crypto.PubKey
}
// nolint
func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "collect-gentxs",
Short: "Collect genesis txs and output a genesis.json file",
RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
name := viper.GetString(client.FlagName)
nodeID, valPubKey, err := InitializeNodeValidatorFiles(config)
if err != nil {
return err
}
genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
if err != nil {
return err
}
genTxsDir := viper.GetString(flagGenTxDir)
if genTxsDir == "" {
genTxsDir = filepath.Join(config.RootDir, "config", "gentx")
}
toPrint := newPrintInfo(config.Moniker, genDoc.ChainID, nodeID, genTxsDir, json.RawMessage(""))
initCfg := newInitConfig(genDoc.ChainID, genTxsDir, name, nodeID, valPubKey)
appMessage, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
if err != nil {
return err
}
toPrint.AppMessage = appMessage
// print out some key information
return displayInfo(cdc, toPrint)
},
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagGenTxDir, "",
"override default \"gentx\" directory from which collect and execute "+
"genesis transactions; default [--home]/config/gentx/")
return cmd
}
func genAppStateFromConfig(
cdc *codec.Codec, config *cfg.Config, initCfg initConfig, genDoc types.GenesisDoc,
) (appState json.RawMessage, err error) {
genFile := config.GenesisFile()
var (
appGenTxs []auth.StdTx
persistentPeers string
genTxs []json.RawMessage
jsonRawTx json.RawMessage
)
// process genesis transactions, else create default genesis.json
appGenTxs, persistentPeers, err = app.CollectStdTxs(
cdc, config.Moniker, initCfg.GenTxsDir, genDoc,
)
if err != nil {
return
}
genTxs = make([]json.RawMessage, len(appGenTxs))
config.P2P.PersistentPeers = persistentPeers
for i, stdTx := range appGenTxs {
jsonRawTx, err = cdc.MarshalJSON(stdTx)
if err != nil {
return
}
genTxs[i] = jsonRawTx
}
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
appState, err = app.GaiaAppGenStateJSON(cdc, genDoc, genTxs)
if err != nil {
return
}
err = ExportGenesisFile(genFile, initCfg.ChainID, nil, appState)
return
}
func newInitConfig(chainID, genTxsDir, name, nodeID string,
valPubKey crypto.PubKey) initConfig {
return initConfig{
ChainID: chainID,
GenTxsDir: genTxsDir,
Name: name,
NodeID: nodeID,
ValPubKey: valPubKey,
}
}
func newPrintInfo(moniker, chainID, nodeID, genTxsDir string,
appMessage json.RawMessage) printInfo {
return printInfo{
Moniker: moniker,
ChainID: chainID,
NodeID: nodeID,
GenTxsDir: genTxsDir,
AppMessage: appMessage,
}
}

141
gaia/init/genesis_accts.go Normal file
View File

@ -0,0 +1,141 @@
package init
import (
"fmt"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "add-genesis-account [address_or_key_name] [coin][,[coin]]",
Short: "Add genesis account to genesis.json",
Args: cobra.ExactArgs(2),
RunE: func(_ *cobra.Command, args []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
addr, err := sdk.AccAddressFromBech32(args[0])
if err != nil {
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
if err != nil {
return err
}
info, err := kb.Get(args[0])
if err != nil {
return err
}
addr = info.GetAddress()
}
coins, err := sdk.ParseCoins(args[1])
if err != nil {
return err
}
vestingStart := viper.GetInt64(flagVestingStart)
vestingEnd := viper.GetInt64(flagVestingEnd)
vestingAmt, err := sdk.ParseCoins(viper.GetString(flagVestingAmt))
if err != nil {
return err
}
genFile := config.GenesisFile()
if !common.FileExists(genFile) {
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
}
genDoc, err := LoadGenesisDoc(cdc, genFile)
if err != nil {
return err
}
var appState app.GenesisState
if err = cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
return err
}
appState, err = addGenesisAccount(cdc, appState, addr, coins, vestingAmt, vestingStart, vestingEnd)
if err != nil {
return err
}
appStateJSON, err := cdc.MarshalJSON(appState)
if err != nil {
return err
}
return ExportGenesisFile(genFile, genDoc.ChainID, nil, appStateJSON)
},
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
cmd.Flags().Uint64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
cmd.Flags().Uint64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
return cmd
}
func addGenesisAccount(
cdc *codec.Codec, appState app.GenesisState, addr sdk.AccAddress,
coins, vestingAmt sdk.Coins, vestingStart, vestingEnd int64,
) (app.GenesisState, error) {
for _, stateAcc := range appState.Accounts {
if stateAcc.Address.Equals(addr) {
return appState, fmt.Errorf("the application state already contains account %v", addr)
}
}
acc := auth.NewBaseAccountWithAddress(addr)
acc.Coins = coins
if !vestingAmt.IsZero() {
var vacc auth.VestingAccount
bvacc := &auth.BaseVestingAccount{
BaseAccount: &acc,
OriginalVesting: vestingAmt,
EndTime: vestingEnd,
}
if bvacc.OriginalVesting.IsAllGT(acc.Coins) {
return appState, fmt.Errorf("vesting amount cannot be greater than total amount")
}
if vestingStart >= vestingEnd {
return appState, fmt.Errorf("vesting start time must before end time")
}
if vestingStart != 0 {
vacc = &auth.ContinuousVestingAccount{
BaseVestingAccount: bvacc,
StartTime: vestingStart,
}
} else {
vacc = &auth.DelayedVestingAccount{
BaseVestingAccount: bvacc,
}
}
appState.Accounts = append(appState.Accounts, app.NewGenesisAccountI(vacc))
} else {
appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc))
}
return appState, nil
}

View File

@ -0,0 +1,88 @@
package init
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/secp256k1"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
func TestAddGenesisAccount(t *testing.T) {
cdc := codec.New()
addr1 := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
type args struct {
appState app.GenesisState
addr sdk.AccAddress
coins sdk.Coins
vestingAmt sdk.Coins
vestingStart int64
vestingEnd int64
}
tests := []struct {
name string
args args
wantErr bool
}{
{
"valid account",
args{
app.GenesisState{},
addr1,
sdk.NewCoins(),
sdk.NewCoins(),
0,
0,
},
false,
},
{
"dup account",
args{
app.GenesisState{Accounts: []app.GenesisAccount{{Address: addr1}}},
addr1,
sdk.NewCoins(),
sdk.NewCoins(),
0,
0,
},
true,
},
{
"invalid vesting amount",
args{
app.GenesisState{},
addr1,
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)),
0,
0,
},
true,
},
{
"invalid vesting times",
args{
app.GenesisState{},
addr1,
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
1654668078,
1554668078,
},
true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := addGenesisAccount(
cdc, tt.args.appState, tt.args.addr, tt.args.coins,
tt.args.vestingAmt, tt.args.vestingStart, tt.args.vestingEnd,
)
require.Equal(t, tt.wantErr, (err != nil))
})
}
}

312
gaia/init/gentx.go Normal file
View File

@ -0,0 +1,312 @@
package init
// DONTCOVER
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
tmcli "github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
kbkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
)
var (
defaultTokens = sdk.TokensFromTendermintPower(100)
defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom
defaultCommissionRate = "0.1"
defaultCommissionMaxRate = "0.2"
defaultCommissionMaxChangeRate = "0.01"
defaultMinSelfDelegation = "1"
)
// GenTxCmd builds the gaiad gentx command.
// nolint: errcheck
func GenTxCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
cmd := &cobra.Command{
Use: "gentx",
Short: "Generate a genesis tx carrying a self delegation",
Args: cobra.NoArgs,
Long: fmt.Sprintf(`This command is an alias of the 'gaiad tx create-validator' command'.
It creates a genesis piece carrying a self delegation with the
following delegation and commission default parameters:
delegation amount: %s
commission rate: %s
commission max rate: %s
commission max change rate: %s
minimum self delegation: %s
`, defaultAmount, defaultCommissionRate, defaultCommissionMaxRate, defaultCommissionMaxChangeRate, defaultMinSelfDelegation),
RunE: func(cmd *cobra.Command, args []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(tmcli.HomeFlag))
nodeID, valPubKey, err := InitializeNodeValidatorFiles(ctx.Config)
if err != nil {
return err
}
// Read --nodeID, if empty take it from priv_validator.json
if nodeIDString := viper.GetString(cli.FlagNodeID); nodeIDString != "" {
nodeID = nodeIDString
}
ip := viper.GetString(cli.FlagIP)
if ip == "" {
fmt.Fprintf(os.Stderr, "couldn't retrieve an external IP; "+
"the tx's memo field will be unset")
}
genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
if err != nil {
return err
}
genesisState := app.GenesisState{}
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
return err
}
if err = app.GaiaValidateGenesisState(genesisState); err != nil {
return err
}
kb, err := keys.NewKeyBaseFromDir(viper.GetString(flagClientHome))
if err != nil {
return err
}
name := viper.GetString(client.FlagName)
key, err := kb.Get(name)
if err != nil {
return err
}
// Read --pubkey, if empty take it from priv_validator.json
if valPubKeyString := viper.GetString(cli.FlagPubKey); valPubKeyString != "" {
valPubKey, err = sdk.GetConsPubKeyBech32(valPubKeyString)
if err != nil {
return err
}
}
website := viper.GetString(cli.FlagWebsite)
details := viper.GetString(cli.FlagDetails)
identity := viper.GetString(cli.FlagIdentity)
// Set flags for creating gentx
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey, website, details, identity)
// Fetch the amount of coins staked
amount := viper.GetString(cli.FlagAmount)
coins, err := sdk.ParseCoins(amount)
if err != nil {
return err
}
err = accountInGenesis(genesisState, key.GetAddress(), coins)
if err != nil {
return err
}
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
cliCtx := context.NewCLIContext().WithCodec(cdc)
// XXX: Set the generate-only flag here after the CLI context has
// been created. This allows the from name/key to be correctly populated.
//
// TODO: Consider removing the manual setting of generate-only in
// favor of a 'gentx' flag in the create-validator command.
viper.Set(client.FlagGenerateOnly, true)
// create a 'create-validator' message
txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr)
if err != nil {
return err
}
info, err := txBldr.Keybase().Get(name)
if err != nil {
return err
}
if info.GetType() == kbkeys.TypeOffline || info.GetType() == kbkeys.TypeMulti {
fmt.Println("Offline key passed in. Use `gaiacli tx sign` command to sign:")
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true)
}
// write the unsigned transaction to the buffer
w := bytes.NewBuffer([]byte{})
cliCtx = cliCtx.WithOutput(w)
if err = utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true); err != nil {
return err
}
// read the transaction
stdTx, err := readUnsignedGenTxFile(cdc, w)
if err != nil {
return err
}
// sign the transaction and write it to the output file
signedTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, false, true)
if err != nil {
return err
}
// Fetch output file name
outputDocument := viper.GetString(client.FlagOutputDocument)
if outputDocument == "" {
outputDocument, err = makeOutputFilepath(config.RootDir, nodeID)
if err != nil {
return err
}
}
if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil {
return err
}
fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument)
return nil
},
}
ip, _ := server.ExternalIP()
cmd.Flags().String(tmcli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, app.DefaultCLIHome, "client's home directory")
cmd.Flags().String(client.FlagName, "", "name of private key with which to sign the gentx")
cmd.Flags().String(client.FlagOutputDocument, "",
"write the genesis transaction JSON document to the given file instead of the default location")
cmd.Flags().String(cli.FlagIP, ip, "The node's public IP")
cmd.Flags().String(cli.FlagNodeID, "", "The node's NodeID")
cmd.Flags().String(cli.FlagWebsite, "", "The validator's (optional) website")
cmd.Flags().String(cli.FlagDetails, "", "The validator's (optional) details")
cmd.Flags().String(cli.FlagIdentity, "", "The (optional) identity signature (ex. UPort or Keybase)")
cmd.Flags().AddFlagSet(cli.FsCommissionCreate)
cmd.Flags().AddFlagSet(cli.FsMinSelfDelegation)
cmd.Flags().AddFlagSet(cli.FsAmount)
cmd.Flags().AddFlagSet(cli.FsPk)
cmd.MarkFlagRequired(client.FlagName)
return cmd
}
func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins sdk.Coins) error {
accountIsInGenesis := false
bondDenom := genesisState.StakingData.Params.BondDenom
// Check if the account is in genesis
for _, acc := range genesisState.Accounts {
// Ensure that account is in genesis
if acc.Address.Equals(key) {
// Ensure account contains enough funds of default bond denom
if coins.AmountOf(bondDenom).GT(acc.Coins.AmountOf(bondDenom)) {
return fmt.Errorf(
"account %v is in genesis, but it only has %v%v available to stake, not %v%v",
key.String(), acc.Coins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom,
)
}
accountIsInGenesis = true
break
}
}
if accountIsInGenesis {
return nil
}
return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key)
}
func prepareFlagsForTxCreateValidator(
config *cfg.Config, nodeID, ip, chainID string, valPubKey crypto.PubKey, website, details, identity string,
) {
viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome))
viper.Set(client.FlagChainID, chainID)
viper.Set(client.FlagFrom, viper.GetString(client.FlagName))
viper.Set(cli.FlagNodeID, nodeID)
viper.Set(cli.FlagIP, ip)
viper.Set(cli.FlagPubKey, sdk.MustBech32ifyConsPub(valPubKey))
viper.Set(cli.FlagMoniker, config.Moniker)
viper.Set(cli.FlagWebsite, website)
viper.Set(cli.FlagDetails, details)
viper.Set(cli.FlagIdentity, identity)
if config.Moniker == "" {
viper.Set(cli.FlagMoniker, viper.GetString(client.FlagName))
}
if viper.GetString(cli.FlagAmount) == "" {
viper.Set(cli.FlagAmount, defaultAmount)
}
if viper.GetString(cli.FlagCommissionRate) == "" {
viper.Set(cli.FlagCommissionRate, defaultCommissionRate)
}
if viper.GetString(cli.FlagCommissionMaxRate) == "" {
viper.Set(cli.FlagCommissionMaxRate, defaultCommissionMaxRate)
}
if viper.GetString(cli.FlagCommissionMaxChangeRate) == "" {
viper.Set(cli.FlagCommissionMaxChangeRate, defaultCommissionMaxChangeRate)
}
if viper.GetString(cli.FlagMinSelfDelegation) == "" {
viper.Set(cli.FlagMinSelfDelegation, defaultMinSelfDelegation)
}
}
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
writePath := filepath.Join(rootDir, "config", "gentx")
if err := common.EnsureDir(writePath, 0700); err != nil {
return "", err
}
return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
}
func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (auth.StdTx, error) {
var stdTx auth.StdTx
bytes, err := ioutil.ReadAll(r)
if err != nil {
return stdTx, err
}
err = cdc.UnmarshalJSON(bytes, &stdTx)
return stdTx, err
}
// nolint: errcheck
func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx auth.StdTx) error {
outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
if err != nil {
return err
}
defer outputFile.Close()
json, err := cdc.MarshalJSON(tx)
if err != nil {
return err
}
_, err = fmt.Fprintf(outputFile, "%s\n", json)
return err
}

85
gaia/init/gentx_test.go Normal file
View File

@ -0,0 +1,85 @@
package init
import (
"testing"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/log"
)
func Test_prepareFlagsForTxCreateValidator(t *testing.T) {
defer server.SetupViper(t)()
defer setupClientHome(t)()
config, err := tcmd.ParseConfig()
require.Nil(t, err)
logger := log.NewNopLogger()
ctx := server.NewContext(config, logger)
valPubKey, _ := sdk.GetConsPubKeyBech32("cosmosvalconspub1zcjduepq7jsrkl9fgqk0wj3ahmfr8pgxj6vakj2wzn656s8pehh0zhv2w5as5gd80a")
type args struct {
config *cfg.Config
nodeID string
ip string
chainID string
valPubKey crypto.PubKey
website string
details string
identity string
}
type extraParams struct {
amount string
commissionRate string
commissionMaxRate string
commissionMaxChangeRate string
minSelfDelegation string
}
type testcase struct {
name string
args args
}
runTest := func(t *testing.T, tt testcase, params extraParams) {
prepareFlagsForTxCreateValidator(tt.args.config, tt.args.nodeID, tt.args.ip, tt.args.chainID, tt.args.valPubKey, tt.args.website, tt.args.details, tt.args.identity)
require.Equal(t, tt.args.website, viper.GetString(cli.FlagWebsite))
require.Equal(t, tt.args.details, viper.GetString(cli.FlagDetails))
require.Equal(t, tt.args.identity, viper.GetString(cli.FlagIdentity))
require.Equal(t, params.amount, viper.GetString(cli.FlagAmount))
require.Equal(t, params.commissionRate, viper.GetString(cli.FlagCommissionRate))
require.Equal(t, params.commissionMaxRate, viper.GetString(cli.FlagCommissionMaxRate))
require.Equal(t, params.commissionMaxChangeRate, viper.GetString(cli.FlagCommissionMaxChangeRate))
require.Equal(t, params.minSelfDelegation, viper.GetString(cli.FlagMinSelfDelegation))
}
tests := []testcase{
{"No parameters", args{ctx.Config, "X", "0.0.0.0", "chainId", valPubKey, "", "", ""}},
{"Optional parameters fed", args{ctx.Config, "X", "0.0.0.0", "chainId", valPubKey, "cosmos.network", "details", "identity"}},
}
defaultParams := extraParams{defaultAmount, defaultCommissionRate, defaultCommissionMaxRate, defaultCommissionMaxChangeRate, defaultMinSelfDelegation}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Run(tt.name, func(t *testing.T) { runTest(t, tt, defaultParams) })
})
}
// Override default params
params := extraParams{"5stake", "1.0", "1.0", "1.0", "1.0"}
viper.Set(cli.FlagAmount, params.amount)
viper.Set(cli.FlagCommissionRate, params.commissionRate)
viper.Set(cli.FlagCommissionMaxRate, params.commissionMaxRate)
viper.Set(cli.FlagCommissionMaxChangeRate, params.commissionMaxChangeRate)
viper.Set(cli.FlagMinSelfDelegation, params.minSelfDelegation)
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { runTest(t, tt, params) })
}
}

95
gaia/init/init.go Normal file
View File

@ -0,0 +1,95 @@
package init
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
)
const (
flagOverwrite = "overwrite"
flagClientHome = "home-client"
flagVestingStart = "vesting-start-time"
flagVestingEnd = "vesting-end-time"
flagVestingAmt = "vesting-amount"
)
type printInfo struct {
Moniker string `json:"moniker"`
ChainID string `json:"chain_id"`
NodeID string `json:"node_id"`
GenTxsDir string `json:"gentxs_dir"`
AppMessage json.RawMessage `json:"app_message"`
}
func displayInfo(cdc *codec.Codec, info printInfo) error {
out, err := codec.MarshalJSONIndent(cdc, info)
if err != nil {
return err
}
fmt.Fprintf(os.Stderr, "%s\n", string(out)) // nolint: errcheck
return nil
}
// InitCmd returns a command that initializes all files needed for Tendermint
// and the respective application.
func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { // nolint: golint
cmd := &cobra.Command{
Use: "init [moniker]",
Short: "Initialize private validator, p2p, genesis, and application configuration files",
Long: `Initialize validators's and node's configuration files.`,
Args: cobra.ExactArgs(1),
RunE: func(_ *cobra.Command, args []string) error {
config := ctx.Config
config.SetRoot(viper.GetString(cli.HomeFlag))
chainID := viper.GetString(client.FlagChainID)
if chainID == "" {
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
}
nodeID, _, err := InitializeNodeValidatorFiles(config)
if err != nil {
return err
}
config.Moniker = args[0]
var appState json.RawMessage
genFile := config.GenesisFile()
if appState, err = initializeEmptyGenesis(cdc, genFile, chainID,
viper.GetBool(flagOverwrite)); err != nil {
return err
}
if err = ExportGenesisFile(genFile, chainID, nil, appState); err != nil {
return err
}
toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
return displayInfo(cdc, toPrint)
},
}
cmd.Flags().String(cli.HomeFlag, app.DefaultNodeHome, "node's home directory")
cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file")
cmd.Flags().String(client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
return cmd
}

136
gaia/init/init_test.go Normal file
View File

@ -0,0 +1,136 @@
package init
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
"time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/mock"
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
abciServer "github.com/tendermint/tendermint/abci/server"
tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/log"
)
func TestInitCmd(t *testing.T) {
defer server.SetupViper(t)()
defer setupClientHome(t)()
logger := log.NewNopLogger()
cfg, err := tcmd.ParseConfig()
require.Nil(t, err)
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
cmd := InitCmd(ctx, cdc)
require.NoError(t, cmd.RunE(nil, []string{"gaianode-test"}))
}
func setupClientHome(t *testing.T) func() {
clientDir, err := ioutil.TempDir("", "mock-sdk-cmd")
require.Nil(t, err)
viper.Set(flagClientHome, clientDir)
return func() {
if err := os.RemoveAll(clientDir); err != nil {
// TODO: Handle with #870
panic(err)
}
}
}
func TestEmptyState(t *testing.T) {
defer server.SetupViper(t)()
defer setupClientHome(t)()
logger := log.NewNopLogger()
cfg, err := tcmd.ParseConfig()
require.Nil(t, err)
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
cmd := InitCmd(ctx, cdc)
require.NoError(t, cmd.RunE(nil, []string{"gaianode-test"}))
old := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w
cmd = server.ExportCmd(ctx, cdc, nil)
err = cmd.RunE(nil, nil)
require.NoError(t, err)
outC := make(chan string)
go func() {
var buf bytes.Buffer
io.Copy(&buf, r)
outC <- buf.String()
}()
w.Close()
os.Stdout = old
out := <-outC
require.Contains(t, out, "genesis_time")
require.Contains(t, out, "chain_id")
require.Contains(t, out, "consensus_params")
require.Contains(t, out, "validators")
require.Contains(t, out, "app_hash")
}
func TestStartStandAlone(t *testing.T) {
home, err := ioutil.TempDir("", "mock-sdk-cmd")
require.Nil(t, err)
defer func() {
os.RemoveAll(home)
}()
viper.Set(cli.HomeFlag, home)
defer setupClientHome(t)()
logger := log.NewNopLogger()
cfg, err := tcmd.ParseConfig()
require.Nil(t, err)
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
initCmd := InitCmd(ctx, cdc)
require.NoError(t, initCmd.RunE(nil, []string{"gaianode-test"}))
app, err := mock.NewApp(home, logger)
require.Nil(t, err)
svrAddr, _, err := server.FreeTCPAddr()
require.Nil(t, err)
svr, err := abciServer.NewServer(svrAddr, "socket", app)
require.Nil(t, err, "error creating listener")
svr.SetLogger(logger.With("module", "abci-server"))
svr.Start()
timer := time.NewTimer(time.Duration(2) * time.Second)
select {
case <-timer.C:
svr.Stop()
}
}
func TestInitNodeValidatorFiles(t *testing.T) {
home, err := ioutil.TempDir("", "mock-sdk-cmd")
require.Nil(t, err)
defer func() {
os.RemoveAll(home)
}()
viper.Set(cli.HomeFlag, home)
viper.Set(client.FlagName, "moniker")
cfg, err := tcmd.ParseConfig()
require.Nil(t, err)
nodeID, valPubKey, err := InitializeNodeValidatorFiles(cfg)
require.Nil(t, err)
require.NotEqual(t, "", nodeID)
require.NotEqual(t, 0, len(valPubKey.Bytes()))
}

View File

@ -1,7 +1,4 @@
// Copyright 2016 All in Bits, inc package init
// Modifications copyright 2019 Kava Labs
package main
// DONTCOVER // DONTCOVER
@ -12,6 +9,17 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/spf13/viper" "github.com/spf13/viper"
tmconfig "github.com/tendermint/tendermint/config" tmconfig "github.com/tendermint/tendermint/config"
@ -20,17 +28,7 @@ import (
"github.com/tendermint/tendermint/types" "github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time" tmtime "github.com/tendermint/tendermint/types/time"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server"
srvconfig "github.com/cosmos/cosmos-sdk/server/config"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/staking"
) )
var ( var (
@ -38,70 +36,68 @@ var (
flagNumValidators = "v" flagNumValidators = "v"
flagOutputDir = "output-dir" flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home" flagNodeDaemonHome = "node-daemon-home"
flagNodeCLIHome = "node-cli-home" flagNodeCliHome = "node-cli-home"
flagStartingIPAddress = "starting-ip-address" flagStartingIPAddress = "starting-ip-address"
) )
const nodeDirPerm = 0755
// get cmd to initialize all files for tendermint testnet and application // get cmd to initialize all files for tendermint testnet and application
func testnetCmd(ctx *server.Context, cdc *codec.Codec, func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
mbm module.BasicManager, genAccIterator genutil.GenesisAccountsIterator) *cobra.Command {
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: "testnet", Use: "testnet",
Short: "Initialize files for a kvd testnet", Short: "Initialize files for a Gaiad testnet",
Long: `testnet will create "v" number of directories and populate each with Long: `testnet will create "v" number of directories and populate each with
necessary files (private validator, genesis, config, etc.). necessary files (private validator, genesis, config, etc.).
Note, strict routability for addresses is turned off in the config file. Note, strict routability for addresses is turned off in the config file.
Example: Example:
kvd testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2 gaiad testnet --v 4 --output-dir ./output --starting-ip-address 192.168.10.2
`, `,
RunE: func(_ *cobra.Command, _ []string) error { RunE: func(_ *cobra.Command, _ []string) error {
config := ctx.Config config := ctx.Config
return initTestnet(config, cdc)
outputDir := viper.GetString(flagOutputDir)
chainID := viper.GetString(client.FlagChainID)
minGasPrices := viper.GetString(server.FlagMinGasPrices)
nodeDirPrefix := viper.GetString(flagNodeDirPrefix)
nodeDaemonHome := viper.GetString(flagNodeDaemonHome)
nodeCLIHome := viper.GetString(flagNodeCLIHome)
startingIPAddress := viper.GetString(flagStartingIPAddress)
numValidators := viper.GetInt(flagNumValidators)
return InitTestnet(config, cdc, mbm, genAccIterator, outputDir, chainID, minGasPrices,
nodeDirPrefix, nodeDaemonHome, nodeCLIHome, startingIPAddress, numValidators)
}, },
} }
cmd.Flags().Int(flagNumValidators, 4, cmd.Flags().Int(flagNumValidators, 4,
"Number of validators to initialize the testnet with") "Number of validators to initialize the testnet with",
)
cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet", cmd.Flags().StringP(flagOutputDir, "o", "./mytestnet",
"Directory to store initialization data for the testnet") "Directory to store initialization data for the testnet",
)
cmd.Flags().String(flagNodeDirPrefix, "node", cmd.Flags().String(flagNodeDirPrefix, "node",
"Prefix the directory name for each node with (node results in node0, node1, ...)") "Prefix the directory name for each node with (node results in node0, node1, ...)",
cmd.Flags().String(flagNodeDaemonHome, "kvd", )
"Home directory of the node's daemon configuration") cmd.Flags().String(flagNodeDaemonHome, "gaiad",
cmd.Flags().String(flagNodeCLIHome, "kvcli", "Home directory of the node's daemon configuration",
"Home directory of the node's cli configuration") )
cmd.Flags().String(flagNodeCliHome, "gaiacli",
"Home directory of the node's cli configuration",
)
cmd.Flags().String(flagStartingIPAddress, "192.168.0.1", cmd.Flags().String(flagStartingIPAddress, "192.168.0.1",
"Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)") "Starting IP address (192.168.0.1 results in persistent peers list ID0@192.168.0.1:46656, ID1@192.168.0.2:46656, ...)")
cmd.Flags().String( cmd.Flags().String(
client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") client.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created",
)
cmd.Flags().String( cmd.Flags().String(
server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom), server.FlagMinGasPrices, fmt.Sprintf("0.000006%s", sdk.DefaultBondDenom),
"Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)") "Minimum gas prices to accept for transactions; All fees in a tx must meet this minimum (e.g. 0.01photino,0.001stake)",
)
return cmd return cmd
} }
const nodeDirPerm = 0755 func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
var chainID string
// Initialize the testnet outDir := viper.GetString(flagOutputDir)
func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicManager, numValidators := viper.GetInt(flagNumValidators)
genAccIterator genutil.GenesisAccountsIterator,
outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome,
nodeCLIHome, startingIPAddress string, numValidators int) error {
chainID = viper.GetString(client.FlagChainID)
if chainID == "" { if chainID == "" {
chainID = "chain-" + cmn.RandStr(6) chainID = "chain-" + cmn.RandStr(6)
} }
@ -110,47 +106,49 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
nodeIDs := make([]string, numValidators) nodeIDs := make([]string, numValidators)
valPubKeys := make([]crypto.PubKey, numValidators) valPubKeys := make([]crypto.PubKey, numValidators)
appConfig := srvconfig.DefaultConfig() gaiaConfig := srvconfig.DefaultConfig()
appConfig.MinGasPrices = minGasPrices gaiaConfig.MinGasPrices = viper.GetString(server.FlagMinGasPrices)
var ( var (
accs []genaccounts.GenesisAccount accs []app.GenesisAccount
genFiles []string genFiles []string
) )
// generate private keys, node IDs, and initial transactions // generate private keys, node IDs, and initial transactions
for i := 0; i < numValidators; i++ { for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) nodeDirName := fmt.Sprintf("%s%d", viper.GetString(flagNodeDirPrefix), i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome) nodeDaemonHomeName := viper.GetString(flagNodeDaemonHome)
clientDir := filepath.Join(outputDir, nodeDirName, nodeCLIHome) nodeCliHomeName := viper.GetString(flagNodeCliHome)
gentxsDir := filepath.Join(outputDir, "gentxs") nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
clientDir := filepath.Join(outDir, nodeDirName, nodeCliHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
config.SetRoot(nodeDir) config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm) err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
err = os.MkdirAll(clientDir, nodeDirPerm) err = os.MkdirAll(clientDir, nodeDirPerm)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
monikers = append(monikers, nodeDirName) monikers = append(monikers, nodeDirName)
config.Moniker = nodeDirName config.Moniker = nodeDirName
ip, err := getIP(i, startingIPAddress) ip, err := getIP(i, viper.GetString(flagStartingIPAddress))
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(config) nodeIDs[i], valPubKeys[i], err = InitializeNodeValidatorFiles(config)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
@ -159,7 +157,7 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
buf := client.BufferStdin() buf := client.BufferStdin()
prompt := fmt.Sprintf( prompt := fmt.Sprintf(
"Password for account '%s' (default %s):", nodeDirName, client.DefaultKeyPass, "Password for account '%s' (default %s):", nodeDirName, app.DefaultKeyPass,
) )
keyPass, err := client.GetPassword(prompt, buf) keyPass, err := client.GetPassword(prompt, buf)
@ -171,12 +169,12 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
} }
if keyPass == "" { if keyPass == "" {
keyPass = client.DefaultKeyPass keyPass = app.DefaultKeyPass
} }
addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true) addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
@ -195,7 +193,7 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
accTokens := sdk.TokensFromTendermintPower(1000) accTokens := sdk.TokensFromTendermintPower(1000)
accStakingTokens := sdk.TokensFromTendermintPower(500) accStakingTokens := sdk.TokensFromTendermintPower(500)
accs = append(accs, genaccounts.GenesisAccount{ accs = append(accs, app.GenesisAccount{
Address: addr, Address: addr,
Coins: sdk.Coins{ Coins: sdk.Coins{
sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens), sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens),
@ -209,7 +207,7 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
valPubKeys[i], valPubKeys[i],
sdk.NewCoin(sdk.DefaultBondDenom, valTokens), sdk.NewCoin(sdk.DefaultBondDenom, valTokens),
staking.NewDescription(nodeDirName, "", "", ""), staking.NewDescription(nodeDirName, "", "", ""),
staking.NewCommissionRates(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()), staking.NewCommissionMsg(sdk.ZeroDec(), sdk.ZeroDec(), sdk.ZeroDec()),
sdk.OneInt(), sdk.OneInt(),
) )
kb, err := keys.NewKeyBaseFromDir(clientDir) kb, err := keys.NewKeyBaseFromDir(clientDir)
@ -217,40 +215,38 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
return err return err
} }
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo) tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{}, memo)
txBldr := auth.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo).WithKeybase(kb) txBldr := authtx.NewTxBuilderFromCLI().WithChainID(chainID).WithMemo(memo).WithKeybase(kb)
signedTx, err := txBldr.SignStdTx(nodeDirName, client.DefaultKeyPass, tx, false) signedTx, err := txBldr.SignStdTx(nodeDirName, app.DefaultKeyPass, tx, false)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
txBytes, err := cdc.MarshalJSON(signedTx) txBytes, err := cdc.MarshalJSON(signedTx)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
// gather gentxs folder // gather gentxs folder
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes) err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
if err != nil { if err != nil {
_ = os.RemoveAll(outputDir) _ = os.RemoveAll(outDir)
return err return err
} }
// TODO: Rename config file to server.toml as it's not particular to Gaia gaiaConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml")
// (REF: https://github.com/cosmos/cosmos-sdk/issues/4125). srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig)
appConfigFilePath := filepath.Join(nodeDir, "config/gaiad.toml")
srvconfig.WriteConfigFile(appConfigFilePath, appConfig)
} }
if err := initGenFiles(cdc, mbm, chainID, accs, genFiles, numValidators); err != nil { if err := initGenFiles(cdc, chainID, accs, genFiles, numValidators); err != nil {
return err return err
} }
err := collectGenFiles( err := collectGenFiles(
cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators, cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators,
outputDir, nodeDirPrefix, nodeDaemonHome, genAccIterator, outDir, viper.GetString(flagNodeDirPrefix), viper.GetString(flagNodeDaemonHome),
) )
if err != nil { if err != nil {
return err return err
@ -260,13 +256,13 @@ func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm module.BasicMana
return nil return nil
} }
func initGenFiles(cdc *codec.Codec, mbm module.BasicManager, chainID string, func initGenFiles(
accs []genaccounts.GenesisAccount, genFiles []string, numValidators int) error { cdc *codec.Codec, chainID string, accs []app.GenesisAccount,
genFiles []string, numValidators int,
) error {
appGenState := mbm.DefaultGenesis() appGenState := app.NewDefaultGenesisState()
appGenState.Accounts = accs
// set the accounts in the genesis state
appGenState = genaccounts.SetGenesisStateInAppState(cdc, appGenState, accs)
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState) appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
if err != nil { if err != nil {
@ -285,36 +281,37 @@ func initGenFiles(cdc *codec.Codec, mbm module.BasicManager, chainID string,
return err return err
} }
} }
return nil return nil
} }
func collectGenFiles( func collectGenFiles(
cdc *codec.Codec, config *tmconfig.Config, chainID string, cdc *codec.Codec, config *tmconfig.Config, chainID string,
monikers, nodeIDs []string, valPubKeys []crypto.PubKey, monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string, numValidators int, outDir, nodeDirPrefix, nodeDaemonHomeName string,
genAccIterator genutil.GenesisAccountsIterator) error { ) error {
var appState json.RawMessage var appState json.RawMessage
genTime := tmtime.Now() genTime := tmtime.Now()
for i := 0; i < numValidators; i++ { for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome) nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
gentxsDir := filepath.Join(outputDir, "gentxs") gentxsDir := filepath.Join(outDir, "gentxs")
moniker := monikers[i] moniker := monikers[i]
config.Moniker = nodeDirName config.Moniker = nodeDirName
config.SetRoot(nodeDir) config.SetRoot(nodeDir)
nodeID, valPubKey := nodeIDs[i], valPubKeys[i] nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
initCfg := genutil.NewInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey) initCfg := newInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey)
genDoc, err := types.GenesisDocFromFile(config.GenesisFile()) genDoc, err := LoadGenesisDoc(cdc, config.GenesisFile())
if err != nil { if err != nil {
return err return err
} }
nodeAppState, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator) nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, genDoc)
if err != nil { if err != nil {
return err return err
} }
@ -327,7 +324,7 @@ func collectGenFiles(
genFile := config.GenesisFile() genFile := config.GenesisFile()
// overwrite each validator's genesis file to have a canonical genesis time // overwrite each validator's genesis file to have a canonical genesis time
err = genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime) err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
if err != nil { if err != nil {
return err return err
} }
@ -336,28 +333,25 @@ func collectGenFiles(
return nil return nil
} }
func getIP(i int, startingIPAddr string) (ip string, err error) { func getIP(i int, startingIPAddr string) (string, error) {
var (
ip string
err error
)
if len(startingIPAddr) == 0 { if len(startingIPAddr) == 0 {
ip, err = server.ExternalIP() ip, err = server.ExternalIP()
if err != nil { if err != nil {
return "", err return "", err
} }
} else {
ip, err = calculateIP(startingIPAddr, i)
if err != nil {
return "", err
}
}
return ip, nil return ip, nil
}
return calculateIP(startingIPAddr, i)
}
func calculateIP(ip string, i int) (string, error) {
ipv4 := net.ParseIP(ip).To4()
if ipv4 == nil {
return "", fmt.Errorf("%v: non ipv4 address", ip)
}
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
} }
func writeFile(name string, dir string, contents []byte) error { func writeFile(name string, dir string, contents []byte) error {
@ -376,3 +370,16 @@ func writeFile(name string, dir string, contents []byte) error {
return nil return nil
} }
func calculateIP(ip string, i int) (string, error) {
ipv4 := net.ParseIP(ip).To4()
if ipv4 == nil {
return "", fmt.Errorf("%v: non ipv4 address", ip)
}
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
}

114
gaia/init/utils.go Normal file
View File

@ -0,0 +1,114 @@
package init
import (
"encoding/json"
"fmt"
"io/ioutil"
"path/filepath"
"time"
amino "github.com/tendermint/go-amino"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
)
// ExportGenesisFile creates and writes the genesis configuration to disk. An
// error is returned if building or writing the configuration to file fails.
func ExportGenesisFile(
genFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage,
) error {
genDoc := types.GenesisDoc{
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
return genDoc.SaveAs(genFile)
}
// ExportGenesisFileWithTime creates and writes the genesis configuration to disk.
// An error is returned if building or writing the configuration to file fails.
func ExportGenesisFileWithTime(
genFile, chainID string, validators []types.GenesisValidator,
appState json.RawMessage, genTime time.Time,
) error {
genDoc := types.GenesisDoc{
GenesisTime: genTime,
ChainID: chainID,
Validators: validators,
AppState: appState,
}
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
return genDoc.SaveAs(genFile)
}
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
func InitializeNodeValidatorFiles(
config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error,
) {
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
return nodeID, valPubKey, err
}
nodeID = string(nodeKey.ID())
server.UpgradeOldPrivValFile(config)
pvKeyFile := config.PrivValidatorKeyFile()
if err := common.EnsureDir(filepath.Dir(pvKeyFile), 0777); err != nil {
return nodeID, valPubKey, nil
}
pvStateFile := config.PrivValidatorStateFile()
if err := common.EnsureDir(filepath.Dir(pvStateFile), 0777); err != nil {
return nodeID, valPubKey, nil
}
valPubKey = privval.LoadOrGenFilePV(pvKeyFile, pvStateFile).GetPubKey()
return nodeID, valPubKey, nil
}
// LoadGenesisDoc reads and unmarshals GenesisDoc from the given file.
func LoadGenesisDoc(cdc *amino.Codec, genFile string) (genDoc types.GenesisDoc, err error) {
genContents, err := ioutil.ReadFile(genFile)
if err != nil {
return genDoc, err
}
if err := cdc.UnmarshalJSON(genContents, &genDoc); err != nil {
return genDoc, err
}
return genDoc, err
}
func initializeEmptyGenesis(
cdc *codec.Codec, genFile, chainID string, overwrite bool,
) (appState json.RawMessage, err error) {
if !overwrite && common.FileExists(genFile) {
return nil, fmt.Errorf("genesis.json file already exists: %v", genFile)
}
return codec.MarshalJSONIndent(cdc, app.NewDefaultGenesisState())
}

49
gaia/init/utils_test.go Normal file
View File

@ -0,0 +1,49 @@
package init
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"testing"
"time"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/tests"
"github.com/stretchr/testify/require"
)
func TestExportGenesisFileWithTime(t *testing.T) {
t.Parallel()
dir, cleanup := tests.NewTestCaseDir(t)
defer cleanup()
fname := filepath.Join(dir, "genesis.json")
require.NoError(t, ExportGenesisFileWithTime(fname, "test", nil, json.RawMessage(""), time.Now()))
}
func TestLoadGenesisDoc(t *testing.T) {
t.Parallel()
dir, cleanup := tests.NewTestCaseDir(t)
defer cleanup()
fname := filepath.Join(dir, "genesis.json")
require.NoError(t, ExportGenesisFileWithTime(fname, "test", nil, json.RawMessage(""), time.Now()))
_, err := LoadGenesisDoc(codec.Cdc, fname)
require.NoError(t, err)
// Non-existing file
_, err = LoadGenesisDoc(codec.Cdc, "non-existing-file")
require.Error(t, err)
malformedFilename := filepath.Join(dir, "malformed")
malformedFile, err := os.Create(malformedFilename)
require.NoError(t, err)
fmt.Fprint(malformedFile, "invalidjson")
malformedFile.Close()
// Non-existing file
_, err = LoadGenesisDoc(codec.Cdc, malformedFilename)
require.Error(t, err)
}

View File

@ -0,0 +1,51 @@
package init
import (
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
)
// Validate genesis command takes
func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "validate-genesis [file]",
Args: cobra.RangeArgs(0, 1),
Short: "validates the genesis file at the default location or at the location passed as an arg",
RunE: func(cmd *cobra.Command, args []string) (err error) {
// Load default if passed no args, otherwise load passed file
var genesis string
if len(args) == 0 {
genesis = ctx.Config.GenesisFile()
} else {
genesis = args[0]
}
//nolint
fmt.Fprintf(os.Stderr, "validating genesis file at %s\n", genesis)
var genDoc types.GenesisDoc
if genDoc, err = LoadGenesisDoc(cdc, genesis); err != nil {
return fmt.Errorf("Error loading genesis doc from %s: %s", genesis, err.Error())
}
var genstate app.GenesisState
if err = cdc.UnmarshalJSON(genDoc.AppState, &genstate); err != nil {
return fmt.Errorf("Error unmarshaling genesis doc %s: %s", genesis, err.Error())
}
if err = app.GaiaValidateGenesisState(genstate); err != nil {
return fmt.Errorf("Error validating genesis file %s: %s", genesis, err.Error())
}
fmt.Printf("File at %s is a valid genesis file for gaiad\n", genesis)
return nil
},
}
}

7
gaia/testnets/README.md Normal file
View File

@ -0,0 +1,7 @@
# DEPRECATED
The content of this file was moved to the `/docs` folder and is hosted on the
[website](https://cosmos.network/docs/getting-started/full-node.html#run-a-full-node).
The rest of this folder was moved to the [testnets
repo](https://github.com/cosmos/testnets).

132
gaia/testnets/STATUS.md Normal file
View File

@ -0,0 +1,132 @@
# DEPRECATED
See [testnets repo](https://github.com/cosmos/testnets).
## *July 22, 2018, 5:30 EST* - Gaia-7001 Consensus Failure
- [Consensus Failure at Block 24570](https://github.com/cosmos/cosmos-sdk/issues/1787)
## *July 17, 2018, 4:00 EST* - New Testnet Gaia-7001
- New testnet with fixes for the genesis file
- Increased max validators to 128
## *July 17, 2018, 3:00 EST* - Gaia-7000 consensus failure
- Misconfiguration in the genesis file led to a consensus failure
- New genesis file for gaia-7001 will be up soon
## *July 17, 2018, 2:40 EST* - Gaia-7000 is making blocks!
- Gaia-7000 is live and making blocks!
## *July 16, 2018, 17:00 EST* - New Testnet Gaia-7000
- Gaia-7000 is up!
- 108 validators in the genesis.json file.
## *July 2, 2018, 1:00 EST* - Gaia-6002 slashing failure
- Gaia-6002 has been halted due to a slashing issue.
- The team is taking its time to look into this Gaia-7000 will be introduced this week.
## *June 13, 2018, 17:00 EST* - Gaia-6002 is making blocks!
- Gaia-6002 is live and making blocks
- Absent validators have been slashed and jailed
- Currently live with 17 validators
## *June 13, 2018, 4:30 EST* - New Testnet Gaia-6002
- After fixing bugs from gaia-6001, especially [issue
#1197](https://github.com/cosmos/cosmos-sdk/issues/1197), we are announcing a
new testnet, Gaia-6002
- Gaia-6002 has the same genesis file as Gaia-6001, just with the chain-id
updated
- Update from previous testnet [here](https://github.com/cosmos/cosmos-sdk/tree/master/cmd/gaia/testnets#upgrading-from-previous-testnet)
## *June 13, 2018, 4:30 EST* - New Release
- Released gaia
[v0.19.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.19.0)
- Includes various bug-fixes for staking found on Gaia-6001
## *June 13, 2018, 2:30 EST* - Published Postmortem of Gaia-6001 failure
- A bug in the design of the staking data model caused a sanity check to fail
- Full writeup
[here](https://github.com/cosmos/cosmos-sdk/issues/1197#issuecomment-396823021)
## *June 10, 2018, 8:30 EST* - Gaia-6001 consensus failure
- Validator unbonding and revocation activity caused a consensus failure
- There is a bug in the staking module that must be fixed
- The team is taking its time to look into this and release a fix following a
proper protocol for hotfix upgrades to the testnet
- Please stay tuned!
## *June 9, 2018, 14:00 EST* - New Release
- Released gaia
[v0.18.0](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.18.0) with
update for Tendermint
[v0.20.0](https://github.com/tendermint/tendermint/releases/tag/v0.20.0)
- Includes bug fix for declaring candidacy from the command line
## *June 8, 2018, 23:30 EST* - Gaia-6001 is making blocks
- +2/3 of the voting power is finally online for Gaia-6001 and it is making
blocks!
- This is a momentous achievement - a successful asynchronous decentralized
testnet launch
- Congrats everyone!
## *June 8, 2018, 12:00 EST* - New Testnet Gaia-6001
- After some confusion around testnet deployment and a contention testnet
hardfork, a new genesis file and network was released for `gaia-6001`
## *June 7, 2018, 9:00 EST* - New Testnet Gaia-6000
- Released a new `genesis.json` file for `gaia-6000`
- Initial validators include those that were most active in
the gaia-5001 testnet
- Join the network via gaia `v0.18.0-rc0`
## *June 5, 2018, 21:00 EST* - New Release
- Released gaia
[v0.17.5](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.5)
with update for Tendermint
[v0.19.9](https://github.com/tendermint/tendermint/releases/tag/v0.19.9)
- Fixes many bugs!
- evidence gossipping
- mempool deadlock
- WAL panic
- memory leak
- Please update to this to put a stop to the rampant invalid evidence gossiping
:)
## *May 31, 2018, 14:00 EST* - New Release
- Released gaia
[v0.17.4](https://github.com/cosmos/cosmos-sdk/releases/tag/v0.17.4) with update for Tendermint v0.19.7
- Fixes a WAL bug and some more
- Please update to this if you have trouble restarting a node
## *May 31, 2018, 2:00 EST* - Testnet Halt
- A validator equivocated last week and Evidence is being rampantly gossipped
- Peers that can't process the evidence (either too far behind or too far ahead) are disconnecting from the peers that
sent it, causing high peer turn-over
- The high peer turn-over may be causing a memory-leak, resulting in some nodes
crashing and the testnet halting
- We need to fix some issues in the EvidenceReactor to address this and also
investigate the possible memory-leak
## *May 29, 2018* - New Release
- Released v0.17.3 with update for Tendermint v0.19.6
- Fixes fast-sync bug
- Please update to this to sync with the testnet

34
go.mod
View File

@ -1,35 +1,15 @@
module github.com/kava-labs/_ module github.com/Kava-Labs/kava
go 1.12 go 1.12
require ( require (
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c // indirect github.com/cosmos/cosmos-sdk v0.34.7
github.com/cosmos/cosmos-sdk v0.28.2-0.20190606154315-3180e68c7b57 github.com/rakyll/statik v0.1.4
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d // indirect github.com/spf13/cobra v0.0.3
github.com/google/gofuzz v1.0.0 // indirect github.com/spf13/viper v1.0.3
github.com/gorilla/mux v1.7.2 // indirect github.com/stretchr/testify v1.3.0
github.com/magiconair/properties v1.8.1 // indirect github.com/tendermint/go-amino v0.14.1
github.com/mattn/go-isatty v0.0.8 // indirect
github.com/onsi/ginkgo v1.8.0 // indirect
github.com/onsi/gomega v1.5.0 // indirect
github.com/otiai10/copy v1.0.1
github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776 // indirect
github.com/pelletier/go-toml v1.4.0 // indirect
github.com/prometheus/common v0.4.1 // indirect
github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389 // indirect
github.com/rakyll/statik v0.1.6 // indirect
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a // indirect
github.com/spf13/afero v1.2.2 // indirect
github.com/spf13/cobra v0.0.4
github.com/spf13/viper v1.4.0
github.com/syndtr/goleveldb v1.0.0 // indirect
github.com/tendermint/go-amino v0.15.0
github.com/tendermint/tendermint v0.31.5 github.com/tendermint/tendermint v0.31.5
golang.org/x/crypto v0.0.0-20190513172903-22d7a77e9e5f // indirect
golang.org/x/sys v0.0.0-20190527104216-9cd6430ef91e // indirect
golang.org/x/text v0.3.2 // indirect
google.golang.org/appengine v1.4.0 // indirect
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69 // indirect
) )
replace golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 replace golang.org/x/crypto => github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5

63
go.sum
View File

@ -9,17 +9,17 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d h1:1aAija9gr0Hyv4KfQcRcwlmFIrhkDmIj2dz5bkg/s/8=
github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk= github.com/bartekn/go-bip39 v0.0.0-20171116152956-a05967ea095d/go.mod h1:icNx/6QdFblhsEjZehARqbNumymUT/ydwlLojFdv7Sk=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973 h1:xJ4a3vCFaGF/jqvzLMYoU8P317H5OQ+Via4RmuPwCS0=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY= github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d h1:xG8Pj6Y6J760xwETNmMzmlt38QSwz0BLp1cZ09g27uw=
github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0= github.com/btcsuite/btcd v0.0.0-20190115013929-ed77733ec07d/go.mod h1:d3C0AkH6BRcvO8T0UEPu53cnw4IbV63x1bEjildYhO0=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c h1:aEbSeNALREWXk0G7UdNhR3ayBV7tZ4M2PNmnrCAph6Q=
github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI= github.com/btcsuite/btcd v0.0.0-20190523000118-16327141da8c/go.mod h1:3J08xEfcugPacsc34/LKRU2yO7YmuT8yt28J8k2+rrI=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA= github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a h1:RQMUrEILyYJEoAT34XS/kLu40vC0+po/UfxrBBA4qZE=
github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20180706230648-ab6388e0c60a/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d h1:yJzD/yFppdVCf6ApMkVy8cUxV0XrxdP9rVf6D87/Mng=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg= github.com/btcsuite/go-socks v0.0.0-20170105172521-4720035b7bfd/go.mod h1:HHNXQzUsZCxOoE+CPiyCTO6x34Zs86zZUiwtpXoGdtg=
github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY= github.com/btcsuite/goleveldb v0.0.0-20160330041536-7834afc9e8cd/go.mod h1:F+uVaaLLH7j4eDXPRvw78tMflu7Ie2bzYOH4Y8rRKBY=
@ -34,10 +34,12 @@ github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8Nz
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA= github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190606154315-3180e68c7b57 h1:bLViLq/BPtEMhxsYhE5NxxTM664Bt1Z+vM6SJflQXTU=
github.com/cosmos/cosmos-sdk v0.28.2-0.20190606154315-3180e68c7b57/go.mod h1:MvaJDmjgAK7X1rTnpk8+c6tUFfIZ++iuNCp2sUWzprM= github.com/cosmos/cosmos-sdk v0.28.2-0.20190606154315-3180e68c7b57/go.mod h1:MvaJDmjgAK7X1rTnpk8+c6tUFfIZ++iuNCp2sUWzprM=
github.com/cosmos/cosmos-sdk v0.34.7 h1:S6yMldhrAMB/SDMsR2Hvz05tpUpQQGCHf0INXAZ7VW0=
github.com/cosmos/cosmos-sdk v0.34.7/go.mod h1:ruF+G4D7hRf34uzZQvf/SIja9fsIThU5D7GirwTMQ9I=
github.com/cosmos/cosmos-sdk v0.35.0 h1:EPeie1aKHwnXtTzKggvabG7aAPN+DDmju2xquvjFwao=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8 h1:Iwin12wRQtyZhH6FV3ykFcdGNlYEzoeR0jN8Vn+JWsI=
github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v0.0.0-20180618194314-52158e4697b8/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d h1:49RLWk1j44Xu4fjHb6JFYmeUnDORVwHNkDxaQ0ctCVU=
github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y= github.com/cosmos/go-bip39 v0.0.0-20180819234021-555e2067c45d/go.mod h1:tSxLoYXyBmiFeKpvmq4dzayMdCjCnu8uqmCysIGBT2Y=
github.com/cosmos/ledger-cosmos-go v0.10.3/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY= github.com/cosmos/ledger-cosmos-go v0.10.3/go.mod h1:J8//BsAGTo3OC/vDLjMRFLW6q0WAaXvHnVc7ZmE8iUY=
github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI= github.com/cosmos/ledger-go v0.9.2/go.mod h1:oZJ2hHAZROdlHiwTg4t7kP+GKIIkBT+o6c9QWFanOyI=
@ -58,15 +60,15 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA= github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gogo/protobuf v1.1.1 h1:72R+M5VuhED/KujmZVcIquuo8mBgX4oVda//DQb3PXo=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4= github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0= github.com/golang/protobuf v1.3.0/go.mod h1:Qd/q+1AKNOZr9uGQzbzCmRO6sUih6GTPZv6a1/R87v0=
github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4= github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
@ -75,8 +77,8 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI= github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/gorilla/mux v1.7.0 h1:tOSd0UKHQd6urX6ApfOn4XdBMY6Sh1MfxV3kmaazO+U=
github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.0/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.2 h1:zoNxOV7WjqXptQOVngLmcSQgXmgk4NMz1HibBchjl/I=
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q= github.com/gorilla/websocket v1.4.0 h1:WDFjx/TMzVgy9VdMMQi2K2Emtwi2QcUQsztZ/zLaH/Q=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
@ -100,11 +102,11 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
github.com/mattn/go-isatty v0.0.6 h1:SrwhHcpV4nWrMGdNcC2kXpMfcBVYGDuTArqyhocJgvA=
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU= github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
@ -118,14 +120,14 @@ github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/otiai10/copy v1.0.1 h1:gtBjD8aq4nychvRZ2CyJvFWAw0aja+VHazDdruZKGZA= github.com/otiai10/copy v0.0.0-20180813032824-7e9a647135a1/go.mod h1:pXzZSDlN+HPzSdyIBnKNN9ptD9Hx7iZMWIJPTwo4FPE=
github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc= github.com/otiai10/copy v1.0.1/go.mod h1:8bMCJrAqOtN/d9oyh5HR7HhLQMvcGMpGdwRDYsfOCHc=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4= github.com/otiai10/curr v0.0.0-20190513014714-f5a3d24e5776/go.mod h1:3HNVkVOU7vZeFXocWuvtcS0XSFLcf2XUSDHkq9t1jU4=
github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw= github.com/otiai10/mint v1.2.3/go.mod h1:YnfyPNhBvnY8bW4SGQHCs/aAFhkgySlMZbrF5U0bOVw=
github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M= github.com/otiai10/mint v1.2.4/go.mod h1:d+b7n/0R3tdyUYYylALXpWQ/kTN+QobSq/4SRGBkR3M=
github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
github.com/pelletier/go-toml v1.4.0 h1:u3Z1r+oOXJIkxqw34zVhyPgjBsm6X2wn21NWs/HfSeg=
github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo= github.com/pelletier/go-toml v1.4.0/go.mod h1:PN7xzY2wHTK0K9p34ErDQMlFxa51Fk0OUruD3k1mMwo=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
@ -133,30 +135,30 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
github.com/prometheus/client_golang v0.9.2 h1:awm861/B8OKDd2I/6o1dy3ra4BamzKhYOiGItCeZ740=
github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM= github.com/prometheus/client_golang v0.9.2/go.mod h1:OsXs2jCmiKlQ1lTBmv21f2mNfw4xf/QclQDMrYNZzcM=
github.com/prometheus/client_golang v0.9.3 h1:9iH4JKXLzFbOAdtqv/a+j8aewx2Y8lAjAydhbaScPF8=
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso= github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90 h1:S/YWwWx/RA8rT8tKFRuGUZhuA90OyIBpPCXkcbwU8DE=
github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= github.com/prometheus/common v0.0.0-20181126121408-4724e9255275/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
github.com/prometheus/common v0.2.0 h1:kUZDBDTdBVBYBj5Tmh2NZLlF60mfjA27rM34b+cVwNU=
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/common v0.4.1 h1:K0MGApIoQvMw27RTdJkPbr3JZ7DNbtxQNyi5STVM6Kw=
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20181204211112-1dc9a6cbc91a/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137 h1:3l8oligPtjd4JuM+OZ+U8sjtwFGJs98cdWsqs6QZRWs=
github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190227231451-bbced9601137/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389 h1:F/k2nob1S9M6v5Xkq7KjSTQirOYaYQord0jR4TwyVmY=
github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.0-20190523193104-a7aeb8df3389/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
github.com/rakyll/statik v0.1.4 h1:zCS/YQCxfo/fQjCtGVGIyWGFnRbQ18Y55mhS3XPE+Oo=
github.com/rakyll/statik v0.1.4/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.4/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
github.com/rakyll/statik v0.1.6 h1:uICcfUXpgqtw2VopbIncslhAmE5hwc4g20TEyEENBNs=
github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs= github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6GX8Zs=
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165 h1:nkcn14uNmFEuGCb2mBZbBb24RdNRL08b/wb+xBOYpuk=
github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20180503174638-e2704e165165/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a h1:9ZKAASQSHhDYGoxY8uLVpewe1GDZ2vu2Tr/vTdVAkFQ=
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4=
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI= github.com/rs/cors v1.6.0 h1:G9tHG9lebljV9mfp9SNPDL36nCDxmo3zTlAf1YgvzmI=
@ -166,38 +168,40 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.1 h1:qgMbHoJbPbw579P+1zVY+6n4nIFuIchaIjzZ/I/Yq8M=
github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.1/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk= github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
github.com/spf13/cobra v0.0.3 h1:ZlrZ4XsMRm04Fr5pSFxBgfND2EBVa1nLpiy1stUsX/8=
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
github.com/spf13/cobra v0.0.4 h1:S0tLZ3VOKl2Te0hpq8+ke0eSJPfCnNTPiDlsfwi1/NE=
github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= github.com/spf13/cobra v0.0.4/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg= github.com/spf13/pflag v1.0.3 h1:zPAT6CGy6wXeQ7NtTnaTerfKOsV6V6F8agHXFiazDkg=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/viper v1.0.3 h1:z5LPUc2iz8VLT5Cw1UyrESG6FUUnOGecYGY08BLKSuc=
github.com/spf13/viper v1.0.3/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM= github.com/spf13/viper v1.0.3/go.mod h1:A8kyI5cUJhb8N+3pkfONlcEcZbueH6nhAm0Fq7SrnBM=
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
github.com/spf13/viper v1.4.0 h1:yXHLWeravcrgGyFSyCgdYpXQ9dR9c/WED3pg1RhxqEU=
github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE= github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/yZzE=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3 h1:sAlSBRDl4psFR3ysKXRSE8ss6Mt90+ma1zRTroTNBJA=
github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0= github.com/syndtr/goleveldb v0.0.0-20180708030551-c4c61651e9e3/go.mod h1:Z4AUp2Km+PwemOoO/VB5AOx9XSsIItzFjoJlOSiYmn0=
github.com/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ= github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s= github.com/tendermint/btcd v0.1.1 h1:0VcxPfflS2zZ3RiOAHkBiFUcPvbtRj5O7zHmcJWHV7s=
github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U= github.com/tendermint/btcd v0.1.1/go.mod h1:DC6/m53jtQzr/NFmMNEu0rxf18/ktVoVtMrnDD5pN+U=
github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 h1:u8i49c+BxloX3XQ55cvzFNXplizZP/q00i+IlttUjAU= github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5 h1:u8i49c+BxloX3XQ55cvzFNXplizZP/q00i+IlttUjAU=
github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk= github.com/tendermint/crypto v0.0.0-20180820045704-3764759f34a5/go.mod h1:z4YtwM70uOnk8h0pjJYlj3zdYwi9l03By6iAIF5j/Pk=
github.com/tendermint/go-amino v0.15.0 h1:TC4e66P59W7ML9+bxio17CPKnxW3nKIRAYskntMAoRk= github.com/tendermint/go-amino v0.14.1 h1:o2WudxNfdLNBwMyl2dqOJxiro5rfrEaU0Ugs6offJMk=
github.com/tendermint/go-amino v0.14.1/go.mod h1:i/UKE5Uocn+argJJBb12qTZsCDBcAYMbR92AaJVmKso=
github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME= github.com/tendermint/go-amino v0.15.0/go.mod h1:TQU0M1i/ImAo+tYpZi73AU3V/dKeCoMC9Sphe2ZwGME=
github.com/tendermint/iavl v0.12.2 h1:Ls5p5VINCM1HRT9g5Vvs2zmDOCU/CCIvIHzd/pZ8P0E= github.com/tendermint/iavl v0.12.1 h1:JDfyhM/Hhrumu1CL1Nxrypm8sNTPYqmeHo1IZLiJoXM=
github.com/tendermint/iavl v0.12.1/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM=
github.com/tendermint/iavl v0.12.2/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM= github.com/tendermint/iavl v0.12.2/go.mod h1:EoKMMv++tDOL5qKKVnoIqtVPshRrEPeJ0WsgDOLAauM=
github.com/tendermint/tendermint v0.31.5 h1:vTet8tCq3B9/J9Yo11dNZ8pOB7NtSy++bVSfkP4KzR4= github.com/tendermint/tendermint v0.31.5 h1:vTet8tCq3B9/J9Yo11dNZ8pOB7NtSy++bVSfkP4KzR4=
github.com/tendermint/tendermint v0.31.5/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc= github.com/tendermint/tendermint v0.31.5/go.mod h1:ymcPyWblXCplCPQjbOYbrF1fWnpslATMVqiGgWbZrlc=
@ -211,6 +215,9 @@ go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20170930174604-9419663f5a44/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793 h1:u+LnwYTOOW7Ukr/fppxEb1Nwz0AtPflrblfvUudpo+I=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
@ -219,11 +226,11 @@ golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73r
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc h1:a3CU5tJYVj92DY2LaA1kUkrsqD5/3mLDhx2NcNqyW+0=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092 h1:4QSRKanuywn15aTZvI/mIDEgPQpswuFndXpOj3rKEco=
golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= golang.org/x/net v0.0.0-20190522155817-f3200d17e092/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -237,11 +244,11 @@ golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190527104216-9cd6430ef91e h1:Pzdi8HRppinixnWWzN6KSa0QkBM+GKsTJaWwwfJskNw=
golang.org/x/sys v0.0.0-20190527104216-9cd6430ef91e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190527104216-9cd6430ef91e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@ -251,12 +258,12 @@ golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69 h1:4rNOqY4ULrKzS6twXa619uQgI7h9PaVd4ZhjFQ7C5zs=
google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s= google.golang.org/genproto v0.0.0-20190522204451-c2c4e71fbf69/go.mod h1:z3L6/3dTEVtUr6QSP8miRzeRqwQOioJ9I66odjN4I7s=
google.golang.org/grpc v1.19.0 h1:cfg4PD8YEdSFnm7qLV4++93WcmhH2nIUhMjhdCvl3j8=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.21.0 h1:G+97AoqBnmZIT91cLG/EkCoK9NSelj64P8bOHHNmGn0=
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=