Merge PR #4159: Module/Genesis Generalization

* first commit

* gaia cleanup

* ...

* staking multihooks

* missing module function return args

* bank module name constant

* working, module interface for x/

* got this thing compiling

* make test compiles and passes

* remove expanded simulation invariants

* genesis issue

* continued

* continued

* register crisis routes thought mm

* begin blocker to mm

* end blocker to mm

* empty routes not initialized

* move gaia initChainer sanity check to baseapp

* remove codecs from module manager

* reorging genesis stuff

* module manager passed by reference/bugfixes from working last commit

int

int

* move invariant checks from gaia to crisis

* typo

* basic refactors cmd/gaia/init

* working

* MultiStakingHooks from types to x/staking/types

int

* default module manager order of operations from input modules

* working

* typo

* add AppModuleBasic

* moduleBasicManager / non-test code compiles

* working attempting to get tests passing

* make test passes

* sim random genesis fix

* export bug

* ...

* genutil module

* genutil working

* refactored - happy with non-testing code in cmd/

* ...

* lint fixes

* comment improvement

* cli test fix

* compile housing

* working through compile errors

* working gettin' compilin'

* non-test code compiles

* move testnet to its own module

* reworking tests

int

* bez staging PR 1 comments

* concise module function-of names

* moved all tests from genesis_test.go to other genutil tests

* genaccounts package, add genutil and genaccounts to app.go

* docs for genutil genaccounts

* genaccounts iterate fn

* non-test code with genaccounts/ now compiles

* working test compiling

* debugging tests

* resolved all make test compile errors

* test debuggin

* resolved all unit tests, introduced param module

* cli-test compile fixes

* staking initialization bug

* code comment improvements, changelog entries

* BasicGaiaApp -> ModuleBasics

* highlevel explanation in types/module.go

* @alexanderbez comment revisions

* @fedekunze PR comments

* @alexanderbez PR comments (x2)

* @cwgoes comments (minor updates)

* @fedekunze suggestions

* panic on init with multiple validator updates from different modules

* initchain panic makes validate genesis fail

int

* AppModuleGenesis seperation

int

* test

* remove init panic logic in validate genesis replaced with TODO

* set maxprocs to match system's GOMAXPROCS

* Update circleci

* Cap maxprocs in CI to 4

* @alexanderbez recent comments addressed

* less blocks in twouble sims

int

* runsim error output flag

* -e on import_export as well

* error out

int

* Try to fix failures

* runsim
This commit is contained in:
frog power 4000 2019-05-16 11:25:32 -04:00 committed by GitHub
parent f8fd50a0d8
commit 3fe5869148
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
137 changed files with 3662 additions and 2308 deletions

View File

@ -0,0 +1 @@
#4159 use module pattern and module manager for initialization

View File

@ -0,0 +1 @@
#4159 create the default module patterns and module manager

View File

@ -170,11 +170,11 @@ test_sim_gaia_fast:
test_sim_gaia_import_export: runsim
@echo "Running Gaia import/export simulation. This may take several minutes..."
$(BINDIR)/runsim 50 5 TestGaiaImportExport
$(BINDIR)/runsim -e 25 5 TestGaiaImportExport
test_sim_gaia_simulation_after_import: runsim
@echo "Running Gaia simulation-after-import. This may take several minutes..."
$(BINDIR)/runsim 50 5 TestGaiaSimulationAfterImport
$(BINDIR)/runsim -e 25 5 TestGaiaSimulationAfterImport
test_sim_gaia_custom_genesis_multi_seed: runsim
@echo "Running multi-seed custom genesis simulation..."

View File

@ -6,6 +6,7 @@ import (
"os"
"reflect"
"runtime/debug"
"sort"
"strings"
"errors"
@ -47,8 +48,8 @@ type BaseApp struct {
name string // application name from abci.Info
db dbm.DB // common DB backend
cms sdk.CommitMultiStore // Main (uncached) state
router Router // handle any kind of message
queryRouter QueryRouter // router for redirecting query calls
router sdk.Router // handle any kind of message
queryRouter sdk.QueryRouter // router for redirecting query calls
txDecoder sdk.TxDecoder // unmarshal []byte into sdk.Tx
// set upon LoadVersion or LoadLatestVersion.
@ -246,7 +247,7 @@ func (app *BaseApp) setHaltHeight(height uint64) {
}
// Router returns the router of the BaseApp.
func (app *BaseApp) Router() Router {
func (app *BaseApp) Router() sdk.Router {
if app.sealed {
// We cannot return a router when the app is sealed because we can't have
// any routes modified which would cause unexpected routing behavior.
@ -256,7 +257,7 @@ func (app *BaseApp) Router() Router {
}
// QueryRouter returns the QueryRouter of a BaseApp.
func (app *BaseApp) QueryRouter() QueryRouter { return app.queryRouter }
func (app *BaseApp) QueryRouter() sdk.QueryRouter { return app.queryRouter }
// Seal seals a BaseApp. It prohibits any further modifications to a BaseApp.
func (app *BaseApp) Seal() { app.sealed = true }
@ -368,6 +369,22 @@ func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitC
res = app.initChainer(app.deliverState.ctx, req)
// sanity check
if len(req.Validators) > 0 {
if len(req.Validators) != len(res.Validators) {
panic(fmt.Errorf(
"len(RequestInitChain.Validators) != len(validators) (%d != %d)",
len(req.Validators), len(res.Validators)))
}
sort.Sort(abci.ValidatorUpdates(req.Validators))
sort.Sort(abci.ValidatorUpdates(res.Validators))
for i, val := range res.Validators {
if !val.Equal(req.Validators[i]) {
panic(fmt.Errorf("validators[%d] != req.Validators[%d] ", i, i))
}
}
}
// NOTE: We don't commit, but BeginBlock for block 1 starts from this
// deliverState.
return

View File

@ -6,16 +6,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// QueryRouter provides queryables for each query path.
type QueryRouter interface {
AddRoute(r string, h sdk.Querier) (rtr QueryRouter)
Route(path string) (h sdk.Querier)
}
type queryRouter struct {
routes map[string]sdk.Querier
}
var _ sdk.QueryRouter = NewQueryRouter()
// NewQueryRouter returns a reference to a new queryRouter.
//
// TODO: Either make the function private or make return type (queryRouter) public.
@ -27,7 +23,7 @@ func NewQueryRouter() *queryRouter { // nolint: golint
// AddRoute adds a query path to the router with a given Querier. It will panic
// if a duplicate route is given. The route must be alphanumeric.
func (qrt *queryRouter) AddRoute(path string, q sdk.Querier) QueryRouter {
func (qrt *queryRouter) AddRoute(path string, q sdk.Querier) sdk.QueryRouter {
if !isAlphaNumeric(path) {
panic("route expressions can only contain alphanumeric characters")
}

View File

@ -6,16 +6,12 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Router provides handlers for each transaction type.
type Router interface {
AddRoute(r string, h sdk.Handler) (rtr Router)
Route(path string) (h sdk.Handler)
}
type router struct {
routes map[string]sdk.Handler
}
var _ sdk.Router = NewRouter()
// NewRouter returns a reference to a new router.
//
// TODO: Either make the function private or make return type (router) public.
@ -27,7 +23,7 @@ func NewRouter() *router { // nolint: golint
// AddRoute adds a route path to the router with a given handler. The route must
// be alphanumeric.
func (rtr *router) AddRoute(path string, h sdk.Handler) Router {
func (rtr *router) AddRoute(path string, h sdk.Handler) sdk.Router {
if !isAlphaNumeric(path) {
panic("route expressions can only contain alphanumeric characters")
}

View File

@ -1,19 +1,19 @@
package app
import (
"fmt"
"io"
"os"
"sort"
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/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"
"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"
@ -26,15 +26,45 @@ import (
"github.com/tendermint/tendermint/libs/log"
)
const (
appName = "GaiaApp"
const appName = "GaiaApp"
var (
// default home directories for gaiacli
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
// default home directories for gaiad
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
// The ModuleBasicManager is in charge of setting up basic,
// non-dependant module elements, such as codec registration
// and genesis verification.
ModuleBasics sdk.ModuleBasicManager
)
// default home directories for expected binaries
var (
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
)
func init() {
ModuleBasics = sdk.NewModuleBasicManager(
genaccounts.AppModuleBasic{},
genutil.AppModuleBasic{},
auth.AppModuleBasic{},
bank.AppModuleBasic{},
staking.AppModuleBasic{},
mint.AppModuleBasic{},
distr.AppModuleBasic{},
gov.AppModuleBasic{},
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
}
// Extended ABCI application
type GaiaApp struct {
@ -57,7 +87,7 @@ type GaiaApp struct {
keyParams *sdk.KVStoreKey
tkeyParams *sdk.TransientStoreKey
// Manage getting and setting accounts
// keepers
accountKeeper auth.AccountKeeper
feeCollectionKeeper auth.FeeCollectionKeeper
bankKeeper bank.Keeper
@ -68,12 +98,14 @@ type GaiaApp struct {
govKeeper gov.Keeper
crisisKeeper crisis.Keeper
paramsKeeper params.Keeper
// the module manager
mm *sdk.ModuleManager
}
// 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 {
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
cdc := MakeCodec()
@ -99,103 +131,79 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
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)
// 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,
)
// 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))
app.govKeeper = gov.NewKeeper(
app.cdc,
app.keyGov,
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
gov.DefaultCodespace,
govRouter,
)
app.crisisKeeper = crisis.NewKeeper(
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
app.distrKeeper,
app.bankKeeper,
app.feeCollectionKeeper,
)
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper, govSubspace,
app.bankKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
// register the staking hooks
// NOTE: The stakingKeeper above is passed by reference, so that it can be
// modified like below:
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
app.stakingKeeper = *stakingKeeper.SetHooks(
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
app.mm = sdk.NewModuleManager(
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),
)
// 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)
// 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)
// 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.mm.SetOrderEndBlockers(gov.ModuleName, staking.ModuleName)
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))
// 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.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.SetInitChainer(app.InitChainer)
app.SetBeginBlocker(app.BeginBlocker)
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper, auth.DefaultSigVerificationGasConsumer))
app.SetEndBlocker(app.EndBlocker)
@ -206,210 +214,27 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
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)
params.RegisterCodec(cdc)
gov.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
crisis.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
return cdc
}
// application updates every end block
// application updates every begin 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(),
}
return app.mm.BeginBlock(ctx, req)
}
// 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,
}
return app.mm.EndBlock(ctx, req)
}
// 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?
// application update at chain initialization
func (app *GaiaApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
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,
}
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
return app.mm.InitGenesis(ctx, genesisState)
}
// 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)
}

View File

@ -4,55 +4,15 @@ 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)
@ -63,3 +23,22 @@ func TestGaiadExport(t *testing.T) {
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
}
func setGenesis(gapp *GaiaApp) error {
genesisState := NewDefaultGenesisState()
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
if err != nil {
return err
}
// Initialize the chain
gapp.InitChain(
abci.RequestInitChain{
Validators: []abci.ValidatorUpdate{},
AppStateBytes: stateBytes,
},
)
gapp.Commit()
return nil
}

View File

@ -9,19 +9,13 @@ import (
"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"
)
// export the state of gaia for a genesis file
func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string) (
appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteList []string,
) (appState json.RawMessage, validators []tmtypes.GenesisValidator, err error) {
// as if they could withdraw from the start of the next block
ctx := app.NewContext(true, abci.Header{Height: app.LastBlockHeight()})
@ -30,26 +24,7 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis
app.prepForZeroHeightGenesis(ctx, jailWhiteList)
}
// 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),
)
genState := app.mm.ExportGenesis(ctx)
appState, err = codec.MarshalJSONIndent(app.cdc, genState)
if err != nil {
return nil, nil, err
@ -59,6 +34,8 @@ func (app *GaiaApp) ExportAppStateAndValidators(forZeroHeight bool, jailWhiteLis
}
// prepare for fresh start at zero height
// NOTE zero height genesis is a temporary feature which will be deprecated
// in favour of export at a block height
func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) {
applyWhiteList := false
@ -78,7 +55,7 @@ func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st
}
/* Just to be safe, assert the invariants on current state. */
app.assertRuntimeInvariantsOnContext(ctx)
app.crisisKeeper.AssertInvariants(ctx, app.Logger())
/* Handle fee distribution state. */

View File

@ -2,416 +2,18 @@ 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
}
// 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 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)
return ModuleBasics.DefaultGenesis()
}

View File

@ -1,188 +0,0 @@
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")
}

View File

@ -1,31 +0,0 @@
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())
}

View File

@ -22,6 +22,7 @@ import (
"github.com/cosmos/cosmos-sdk/baseapp"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
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"
@ -71,7 +72,9 @@ func getSimulateFromSeedInput(tb testing.TB, w io.Writer, app *GaiaApp) (
testAndRunTxs(app), invariants(app), numBlocks, blockSize, commit, lean
}
func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
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)
@ -81,8 +84,10 @@ func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisT
cdc.MustUnmarshalJSON(bytes, &genesis)
var appState GenesisState
cdc.MustUnmarshalJSON(genesis.AppState, &appState)
accounts := genaccounts.GetGenesisStateFromAppState(cdc, appState).Accounts
var newAccs []simulation.Account
for _, acc := range appState.Accounts {
for _, acc := range 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.
@ -94,9 +99,13 @@ func appStateFromGenesisFileFn(r *rand.Rand, accs []simulation.Account, genesisT
return genesis.AppState, newAccs, genesis.ChainID
}
func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
// TODO refactor out random initialization code to the modules
func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time,
) (json.RawMessage, []simulation.Account, string) {
var genesisAccounts []GenesisAccount
var genesisAccounts []genaccounts.GenesisAccount
genesisState := NewDefaultGenesisState()
cdc := MakeCodec()
amount := int64(r.Intn(1e12))
numInitiallyBonded := int64(r.Intn(250))
@ -114,7 +123,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
bacc := auth.NewBaseAccountWithAddress(acc.Address)
bacc.SetCoins(coins)
var gacc GenesisAccount
var gacc genaccounts.GenesisAccount
// Only consider making a vesting account once the initial bonded validator
// set is exhausted due to needing to track DelegatedVesting.
@ -135,7 +144,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
}
if startTime == endTime {
endTime += 1
endTime++
}
if r.Intn(100) < 50 {
@ -144,70 +153,79 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
vacc = auth.NewDelayedVestingAccount(&bacc, endTime)
}
gacc = NewGenesisAccountI(vacc)
var err error
gacc, err = genaccounts.NewGenesisAccountI(vacc)
if err != nil {
panic(err)
}
} else {
gacc = NewGenesisAccount(&bacc)
gacc = genaccounts.NewGenesisAccount(&bacc)
}
genesisAccounts = append(genesisAccounts, gacc)
}
genaccsGenesis := genaccounts.NewGenesisState(genesisAccounts)
genesisState[genaccounts.ModuleName] = cdc.MustMarshalJSON(genaccsGenesis)
authGenesis := auth.NewGenesisState(
nil,
auth.Params{
MaxMemoCharacters: simulation.ModuleParamSimulator["MaxMemoCharacters"](r).(uint64),
TxSigLimit: simulation.ModuleParamSimulator["TxSigLimit"](r).(uint64),
TxSizeCostPerByte: simulation.ModuleParamSimulator["TxSizeCostPerByte"](r).(uint64),
SigVerifyCostED25519: simulation.ModuleParamSimulator["SigVerifyCostED25519"](r).(uint64),
SigVerifyCostSecp256k1: simulation.ModuleParamSimulator["SigVerifyCostSecp256k1"](r).(uint64),
},
auth.NewParams(
simulation.ModuleParamSimulator["MaxMemoCharacters"](r).(uint64),
simulation.ModuleParamSimulator["TxSigLimit"](r).(uint64),
simulation.ModuleParamSimulator["TxSizeCostPerByte"](r).(uint64),
simulation.ModuleParamSimulator["SigVerifyCostED25519"](r).(uint64),
simulation.ModuleParamSimulator["SigVerifyCostSecp256k1"](r).(uint64),
),
)
fmt.Printf("Selected randomly generated auth parameters:\n\t%+v\n", authGenesis)
genesisState[auth.ModuleName] = cdc.MustMarshalJSON(authGenesis)
bankGenesis := bank.NewGenesisState(r.Int63n(2) == 0)
genesisState[bank.ModuleName] = cdc.MustMarshalJSON(bankGenesis)
fmt.Printf("Selected randomly generated bank parameters:\n\t%+v\n", bankGenesis)
// Random genesis states
vp := simulation.ModuleParamSimulator["VotingParams/VotingPeriod"](r).(time.Duration)
govGenesis := gov.NewGenesisState(
uint64(r.Intn(100)),
gov.DepositParams{
MinDeposit: simulation.ModuleParamSimulator["DepositParams/MinDeposit"](r).(sdk.Coins),
MaxDepositPeriod: vp,
},
gov.VotingParams{
VotingPeriod: vp,
},
gov.TallyParams{
Quorum: simulation.ModuleParamSimulator["TallyParams/Quorum"](r).(sdk.Dec),
Threshold: simulation.ModuleParamSimulator["TallyParams/Threshold"](r).(sdk.Dec),
Veto: simulation.ModuleParamSimulator["TallyParams/Veto"](r).(sdk.Dec),
},
gov.NewDepositParams(
simulation.ModuleParamSimulator["DepositParams/MinDeposit"](r).(sdk.Coins),
vp,
),
gov.NewVotingParams(vp),
gov.NewTallyParams(
simulation.ModuleParamSimulator["TallyParams/Quorum"](r).(sdk.Dec),
simulation.ModuleParamSimulator["TallyParams/Threshold"](r).(sdk.Dec),
simulation.ModuleParamSimulator["TallyParams/Veto"](r).(sdk.Dec),
),
)
genesisState[gov.ModuleName] = cdc.MustMarshalJSON(govGenesis)
fmt.Printf("Selected randomly generated governance parameters:\n\t%+v\n", govGenesis)
stakingGenesis := staking.NewGenesisState(
staking.InitialPool(),
staking.Params{
UnbondingTime: simulation.ModuleParamSimulator["UnbondingTime"](r).(time.Duration),
MaxValidators: simulation.ModuleParamSimulator["MaxValidators"](r).(uint16),
BondDenom: sdk.DefaultBondDenom,
},
staking.NewParams(
simulation.ModuleParamSimulator["UnbondingTime"](r).(time.Duration),
simulation.ModuleParamSimulator["MaxValidators"](r).(uint16),
7,
sdk.DefaultBondDenom,
),
nil,
nil,
)
fmt.Printf("Selected randomly generated staking parameters:\n\t%+v\n", stakingGenesis)
slashingGenesis := slashing.GenesisState{
Params: slashing.Params{
MaxEvidenceAge: stakingGenesis.Params.UnbondingTime,
SignedBlocksWindow: simulation.ModuleParamSimulator["SignedBlocksWindow"](r).(int64),
MinSignedPerWindow: simulation.ModuleParamSimulator["MinSignedPerWindow"](r).(sdk.Dec),
DowntimeJailDuration: simulation.ModuleParamSimulator["DowntimeJailDuration"](r).(time.Duration),
SlashFractionDoubleSign: simulation.ModuleParamSimulator["SlashFractionDoubleSign"](r).(sdk.Dec),
SlashFractionDowntime: simulation.ModuleParamSimulator["SlashFractionDowntime"](r).(sdk.Dec),
},
}
slashingParams := slashing.NewParams(
stakingGenesis.Params.UnbondingTime,
simulation.ModuleParamSimulator["SignedBlocksWindow"](r).(int64),
simulation.ModuleParamSimulator["MinSignedPerWindow"](r).(sdk.Dec),
simulation.ModuleParamSimulator["DowntimeJailDuration"](r).(time.Duration),
simulation.ModuleParamSimulator["SlashFractionDoubleSign"](r).(sdk.Dec),
simulation.ModuleParamSimulator["SlashFractionDowntime"](r).(sdk.Dec),
)
slashingGenesis := slashing.NewGenesisState(slashingParams, nil, nil)
genesisState[slashing.ModuleName] = cdc.MustMarshalJSON(slashingGenesis)
fmt.Printf("Selected randomly generated slashing parameters:\n\t%+v\n", slashingGenesis)
mintGenesis := mint.NewGenesisState(
@ -222,6 +240,7 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
uint64(60*60*8766/5),
),
)
genesisState[mint.ModuleName] = cdc.MustMarshalJSON(mintGenesis)
fmt.Printf("Selected randomly generated minting parameters:\n\t%+v\n", mintGenesis)
var validators []staking.Validator
@ -243,28 +262,20 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
stakingGenesis.Pool.NotBondedTokens = sdk.NewInt((amount * numAccs) + (numInitiallyBonded * amount))
stakingGenesis.Validators = validators
stakingGenesis.Delegations = delegations
genesisState[staking.ModuleName] = cdc.MustMarshalJSON(stakingGenesis)
// TODO make use NewGenesisState
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)),
}
genesisState[distr.ModuleName] = cdc.MustMarshalJSON(distrGenesis)
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)
appState, err := MakeCodec().MarshalJSON(genesisState)
if err != nil {
panic(err)
}
@ -272,7 +283,9 @@ func appStateRandomizedFn(r *rand.Rand, accs []simulation.Account, genesisTimest
return appState, accs, "simulation"
}
func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time) (json.RawMessage, []simulation.Account, string) {
func appStateFn(r *rand.Rand, accs []simulation.Account, genesisTimestamp time.Time,
) (json.RawMessage, []simulation.Account, string) {
if genesisFile != "" {
return appStateFromGenesisFileFn(r, accs, genesisTimestamp)
}
@ -425,7 +438,7 @@ func TestGaiaImportExport(t *testing.T) {
panic(err)
}
ctxB := newApp.NewContext(true, abci.Header{})
newApp.initFromGenesisState(ctxB, genesisState)
newApp.mm.InitGenesis(ctxB, genesisState)
fmt.Printf("Comparing stores...\n")
ctxA := app.NewContext(true, abci.Header{})

22
cmd/gaia/app/test_util.go Normal file
View File

@ -0,0 +1,22 @@
package app
import (
"io"
"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/x/staking"
dbm "github.com/tendermint/tendermint/libs/db"
)
// used for debugging by gaia/cmd/gaiadebug
// NOTE to not use this function with non-test code
func NewGaiaAppUNSAFE(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp),
) (gapp *GaiaApp, keyMain, keyStaking *sdk.KVStoreKey, stakingKeeper staking.Keeper) {
gapp = NewGaiaApp(logger, db, traceStore, loadLatest, invCheckPeriod, baseAppOptions...)
return gapp, gapp.keyMain, gapp.keyStaking, gapp.stakingKeeper
}

View File

@ -3,7 +3,7 @@
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/...
$ go test -mod=readonly -p 4 `go list ./cmd/gaia/cli_test/...` -tags=cli_test
# OR!
$ make test_cli
```

View File

@ -24,7 +24,9 @@ import (
"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/auth/genaccounts"
"github.com/cosmos/cosmos-sdk/x/gov"
"github.com/cosmos/cosmos-sdk/x/mint"
)
func TestGaiaCLIKeysAddMultisig(t *testing.T) {
@ -446,16 +448,22 @@ func TestGaiaCLICreateValidator(t *testing.T) {
func TestGaiaCLIQueryRewards(t *testing.T) {
t.Parallel()
f := InitFixtures(t)
cdc := app.MakeCodec()
genesisState := f.GenesisState()
inflationMin := sdk.MustNewDecFromStr("10000.0")
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMin = inflationMin
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
var mintData mint.GenesisState
cdc.UnmarshalJSON(genesisState[mint.ModuleName], &mintData)
mintData.Minter.Inflation = inflationMin
mintData.Params.InflationMin = inflationMin
mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
mintDataBz, err := cdc.MarshalJSON(mintData)
require.NoError(t, err)
genesisState[mint.ModuleName] = mintDataBz
genFile := filepath.Join(f.GaiadHome, "config", "genesis.json")
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
require.NoError(t, err)
cdc := app.MakeCodec()
genDoc.AppState, err = cdc.MarshalJSON(genesisState)
require.NoError(t, genDoc.SaveAs(genFile))
@ -1193,10 +1201,14 @@ func TestGaiadAddGenesisAccount(t *testing.T) {
f.AddGenesisAccount(f.KeyAddress(keyFoo), startCoins)
f.AddGenesisAccount(f.KeyAddress(keyBar), bazCoins)
genesisState := f.GenesisState()
require.Equal(t, genesisState.Accounts[0].Address, f.KeyAddress(keyFoo))
require.Equal(t, genesisState.Accounts[1].Address, f.KeyAddress(keyBar))
require.True(t, genesisState.Accounts[0].Coins.IsEqual(startCoins))
require.True(t, genesisState.Accounts[1].Coins.IsEqual(bazCoins))
cdc := app.MakeCodec()
accounts := genaccounts.GetGenesisStateFromAppState(cdc, genesisState).Accounts
require.Equal(t, accounts[0].Address, f.KeyAddress(keyFoo))
require.Equal(t, accounts[1].Address, f.KeyAddress(keyBar))
require.True(t, accounts[0].Coins.IsEqual(startCoins))
require.True(t, accounts[1].Coins.IsEqual(bazCoins))
// Cleanup testing directories
f.Cleanup()

View File

@ -68,7 +68,7 @@ func main() {
// Module clients hold cli commnads (tx,query) and lcd routes
// TODO: Make the lcd command take a list of ModuleClient
mc := []sdk.ModuleClients{
mc := []sdk.ModuleClient{
govClient.NewModuleClient(gv.StoreKey, cdc, paramcli.GetCmdSubmitProposal(cdc)),
distClient.NewModuleClient(distcmd.StoreKey, cdc),
stakingclient.NewModuleClient(st.StoreKey, cdc),
@ -113,7 +113,7 @@ func main() {
}
}
func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClient) *cobra.Command {
queryCmd := &cobra.Command{
Use: "query",
Aliases: []string{"q"},
@ -139,7 +139,7 @@ func queryCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
return queryCmd
}
func txCmd(cdc *amino.Codec, mc []sdk.ModuleClients) *cobra.Command {
func txCmd(cdc *amino.Codec, mc []sdk.ModuleClient) *cobra.Command {
txCmd := &cobra.Command{
Use: "tx",
Short: "Transactions subcommands",

View File

@ -16,10 +16,12 @@ import (
"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"
"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"
)
// gaiad custom flags
@ -44,13 +46,13 @@ func main() {
PersistentPreRunE: server.PersistentPreRunEFn(ctx),
}
rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.CollectGenTxsCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.GenTxCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.AddGenesisAccountCmd(ctx, cdc))
rootCmd.AddCommand(gaiaInit.ValidateGenesisCmd(ctx, cdc))
rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics))
rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, genaccounts.AppModuleBasic{}))
rootCmd.AddCommand(genutilcli.GenTxCmd(ctx, cdc, app.ModuleBasics, genaccounts.AppModuleBasic{}, app.DefaultNodeHome, app.DefaultCLIHome))
rootCmd.AddCommand(genutilcli.ValidateGenesisCmd(ctx, cdc, app.ModuleBasics))
rootCmd.AddCommand(genaccscli.AddGenesisAccountCmd(ctx, cdc))
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)
@ -61,7 +63,6 @@ func main() {
0, "Assert registered invariants every N blocks")
err := executor.Execute()
if err != nil {
// handle with #870
panic(err)
}
}

View File

@ -1,4 +1,4 @@
package init
package main
// DONTCOVER
@ -9,17 +9,17 @@ import (
"os"
"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/client/keys"
"github.com/cosmos/cosmos-sdk/codec"
"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/x/auth"
authtx "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/spf13/cobra"
"github.com/spf13/viper"
tmconfig "github.com/tendermint/tendermint/config"
@ -27,8 +27,6 @@ import (
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/types"
tmtime "github.com/tendermint/tendermint/types/time"
"github.com/cosmos/cosmos-sdk/server"
)
var (
@ -36,14 +34,13 @@ var (
flagNumValidators = "v"
flagOutputDir = "output-dir"
flagNodeDaemonHome = "node-daemon-home"
flagNodeCliHome = "node-cli-home"
flagNodeCLIHome = "node-cli-home"
flagStartingIPAddress = "starting-ip-address"
)
const nodeDirPerm = 0755
// get cmd to initialize all files for tendermint testnet and application
func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
func testnetCmd(ctx *server.Context, cdc *codec.Codec,
mbm sdk.ModuleBasicManager, genAccIterator genutil.GenesisAccountsIterator) *cobra.Command {
cmd := &cobra.Command{
Use: "testnet",
@ -58,46 +55,49 @@ Example:
`,
RunE: func(_ *cobra.Command, _ []string) error {
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,
"Number of validators to initialize the testnet with",
)
"Number of validators to initialize the testnet with")
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",
"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, "gaiad",
"Home directory of the node's daemon configuration",
)
cmd.Flags().String(flagNodeCliHome, "gaiacli",
"Home directory of the node's cli configuration",
)
"Home directory of the node's daemon configuration")
cmd.Flags().String(flagNodeCLIHome, "gaiacli",
"Home directory of the node's cli configuration")
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, ...)")
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(
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
}
func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
var chainID string
const nodeDirPerm = 0755
outDir := viper.GetString(flagOutputDir)
numValidators := viper.GetInt(flagNumValidators)
// Initialize the testnet
func InitTestnet(config *tmconfig.Config, cdc *codec.Codec, mbm sdk.ModuleBasicManager,
genAccIterator genutil.GenesisAccountsIterator,
outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome,
nodeCLIHome, startingIPAddress string, numValidators int) error {
chainID = viper.GetString(client.FlagChainID)
if chainID == "" {
chainID = "chain-" + cmn.RandStr(6)
}
@ -107,48 +107,46 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
valPubKeys := make([]crypto.PubKey, numValidators)
gaiaConfig := srvconfig.DefaultConfig()
gaiaConfig.MinGasPrices = viper.GetString(server.FlagMinGasPrices)
gaiaConfig.MinGasPrices = minGasPrices
var (
accs []app.GenesisAccount
accs []genaccounts.GenesisAccount
genFiles []string
)
// generate private keys, node IDs, and initial transactions
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", viper.GetString(flagNodeDirPrefix), i)
nodeDaemonHomeName := viper.GetString(flagNodeDaemonHome)
nodeCliHomeName := viper.GetString(flagNodeCliHome)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
clientDir := filepath.Join(outDir, nodeDirName, nodeCliHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
clientDir := filepath.Join(outputDir, nodeDirName, nodeCLIHome)
gentxsDir := filepath.Join(outputDir, "gentxs")
config.SetRoot(nodeDir)
err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
err = os.MkdirAll(clientDir, nodeDirPerm)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
monikers = append(monikers, nodeDirName)
config.Moniker = nodeDirName
ip, err := getIP(i, viper.GetString(flagStartingIPAddress))
ip, err := getIP(i, startingIPAddress)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
nodeIDs[i], valPubKeys[i], err = InitializeNodeValidatorFiles(config)
nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(config)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
@ -174,7 +172,7 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
addr, secret, err := server.GenerateSaveCoinKey(clientDir, nodeDirName, keyPass, true)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
@ -193,7 +191,7 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
accTokens := sdk.TokensFromTendermintPower(1000)
accStakingTokens := sdk.TokensFromTendermintPower(500)
accs = append(accs, app.GenesisAccount{
accs = append(accs, genaccounts.GenesisAccount{
Address: addr,
Coins: sdk.Coins{
sdk.NewCoin(fmt.Sprintf("%stoken", nodeDirName), accTokens),
@ -219,20 +217,20 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
signedTx, err := txBldr.SignStdTx(nodeDirName, client.DefaultKeyPass, tx, false)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
txBytes, err := cdc.MarshalJSON(signedTx)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
// gather gentxs folder
err = writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBytes)
if err != nil {
_ = os.RemoveAll(outDir)
_ = os.RemoveAll(outputDir)
return err
}
@ -242,13 +240,13 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
srvconfig.WriteConfigFile(gaiaConfigFilePath, gaiaConfig)
}
if err := initGenFiles(cdc, chainID, accs, genFiles, numValidators); err != nil {
if err := initGenFiles(cdc, mbm, chainID, accs, genFiles, numValidators); err != nil {
return err
}
err := collectGenFiles(
cdc, config, chainID, monikers, nodeIDs, valPubKeys, numValidators,
outDir, viper.GetString(flagNodeDirPrefix), viper.GetString(flagNodeDaemonHome),
outputDir, nodeDirPrefix, nodeDaemonHome, genAccIterator,
)
if err != nil {
return err
@ -258,13 +256,14 @@ func initTestnet(config *tmconfig.Config, cdc *codec.Codec) error {
return nil
}
func initGenFiles(
cdc *codec.Codec, chainID string, accs []app.GenesisAccount,
genFiles []string, numValidators int,
) error {
func initGenFiles(cdc *codec.Codec, mbm sdk.ModuleBasicManager, chainID string,
accs []genaccounts.GenesisAccount, genFiles []string, numValidators int) error {
appGenState := app.NewDefaultGenesisState()
appGenState.Accounts = accs
appGenState := mbm.DefaultGenesis()
// set the accounts in the genesis state
appGenState = genaccounts.SetGenesisStateInAppState(cdc, appGenState,
genaccounts.NewGenesisState(accs))
appGenStateJSON, err := codec.MarshalJSONIndent(cdc, appGenState)
if err != nil {
@ -283,37 +282,36 @@ func initGenFiles(
return err
}
}
return nil
}
func collectGenFiles(
cdc *codec.Codec, config *tmconfig.Config, chainID string,
monikers, nodeIDs []string, valPubKeys []crypto.PubKey,
numValidators int, outDir, nodeDirPrefix, nodeDaemonHomeName string,
) error {
numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string,
genAccIterator genutil.GenesisAccountsIterator) error {
var appState json.RawMessage
genTime := tmtime.Now()
for i := 0; i < numValidators; i++ {
nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i)
nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName)
gentxsDir := filepath.Join(outDir, "gentxs")
nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome)
gentxsDir := filepath.Join(outputDir, "gentxs")
moniker := monikers[i]
config.Moniker = nodeDirName
config.SetRoot(nodeDir)
nodeID, valPubKey := nodeIDs[i], valPubKeys[i]
initCfg := newInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey)
initCfg := genutil.NewInitConfig(chainID, gentxsDir, moniker, nodeID, valPubKey)
genDoc, err := types.GenesisDocFromFile(config.GenesisFile())
if err != nil {
return err
}
nodeAppState, err := genAppStateFromConfig(cdc, config, initCfg, *genDoc)
nodeAppState, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator)
if err != nil {
return err
}
@ -326,7 +324,7 @@ func collectGenFiles(
genFile := config.GenesisFile()
// overwrite each validator's genesis file to have a canonical genesis time
err = ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
err = genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime)
if err != nil {
return err
}
@ -335,25 +333,28 @@ func collectGenFiles(
return nil
}
func getIP(i int, startingIPAddr string) (string, error) {
var (
ip string
err error
)
func getIP(i int, startingIPAddr string) (ip string, err error) {
if len(startingIPAddr) == 0 {
ip, err = server.ExternalIP()
if err != nil {
return "", err
}
} else {
ip, err = calculateIP(startingIPAddr, i)
if err != nil {
return "", err
}
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)
}
return ip, nil
for j := 0; j < i; j++ {
ipv4[3]++
}
return ipv4.String(), nil
}
func writeFile(name string, dir string, contents []byte) error {
@ -372,16 +373,3 @@ func writeFile(name string, dir string, contents []byte) error {
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
}

View File

@ -16,20 +16,10 @@ import (
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"
)
@ -50,7 +40,8 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
fmt.Println(err)
os.Exit(1)
}
app := NewGaiaApp(logger, db, baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))))
app, keyMain, keyStaking, stakingKeeper := gaia.NewGaiaAppUNSAFE(
logger, db, nil, false, 0, baseapp.SetPruning(store.NewPruningOptionsFromString(viper.GetString("pruning"))))
// print some info
id := app.LastCommitID()
@ -76,7 +67,7 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
checkHeight := topHeight
for {
// load the given version of the state
err = app.LoadVersion(checkHeight, app.keyMain)
err = app.LoadVersion(checkHeight, keyMain)
if err != nil {
fmt.Println(err)
os.Exit(1)
@ -84,9 +75,9 @@ func runHackCmd(cmd *cobra.Command, args []string) error {
ctx := app.NewContext(true, abci.Header{})
// check for the powerkey and the validator from the store
store := ctx.KVStore(app.keyStaking)
store := ctx.KVStore(keyStaking)
res := store.Get(powerKey)
val, _ := app.stakingKeeper.GetValidator(ctx, trouble)
val, _ := stakingKeeper.GetValidator(ctx, trouble)
fmt.Println("checking height", checkHeight, res, val)
if res == nil {
bottomHeight = checkHeight
@ -110,159 +101,3 @@ func hexToBytes(h string) []byte {
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, params.DefaultCodespace)
// 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, auth.DefaultSigVerificationGasConsumer))
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,
}
}

View File

@ -1,8 +1,10 @@
package main
import (
"bufio"
"flag"
"fmt"
"io"
"io/ioutil"
"log"
"os"
@ -34,11 +36,12 @@ var (
results chan bool
// command line arguments and options
jobs int = runtime.GOMAXPROCS(0)
blocks string
period string
testname string
genesis string
jobs int = runtime.GOMAXPROCS(0)
blocks string
period string
testname string
genesis string
exitOnFail bool
// logs temporary directory
tempdir string
@ -53,10 +56,11 @@ func init() {
flag.IntVar(&jobs, "j", jobs, "Number of parallel processes")
flag.StringVar(&genesis, "g", "", "Genesis file")
flag.BoolVar(&exitOnFail, "e", false, "Exit on fail during multi-sim, print error")
flag.Usage = func() {
fmt.Fprintf(flag.CommandLine.Output(),
`Usage: %s [-j maxprocs] [-g genesis.json] [blocks] [period] [testname]
`Usage: %s [-j maxprocs] [-g genesis.json] [-e] [blocks] [period] [testname]
Run simulations in parallel
`, filepath.Base(os.Args[0]))
@ -115,13 +119,13 @@ func main() {
// set up worker pool
log.Printf("Allocating %d workers...", jobs)
wg := sync.WaitGroup{}
for workerId := 0; workerId < jobs; workerId++ {
for workerID := 0; workerID < jobs; workerID++ {
wg.Add(1)
go func(workerId int) {
go func(workerID int) {
defer wg.Done()
worker(workerId, queue)
}(workerId)
worker(workerID, queue)
}(workerID)
}
// idiomatic hack required to use wg.Wait() with select
@ -175,6 +179,10 @@ func worker(id int, seeds <-chan int) {
results <- false
log.Printf("[W%d] Seed %d: FAILED", id, seed)
log.Printf("To reproduce run: %s", buildCommand(testname, blocks, period, genesis, seed))
if exitOnFail {
log.Printf("\bERROR OUTPUT \n\n%s", err)
panic("halting simulations")
}
} else {
log.Printf("[W%d] Seed %d: OK", id, seed)
}
@ -182,23 +190,45 @@ func worker(id int, seeds <-chan int) {
log.Printf("[W%d] no seeds left, shutting down", id)
}
func spawnProc(workerId int, seed int) error {
func spawnProc(workerID int, seed int) error {
stderrFile, _ := os.Create(filepath.Join(tempdir, makeFilename(seed)+".stderr"))
stdoutFile, _ := os.Create(filepath.Join(tempdir, makeFilename(seed)+".stdout"))
s := buildCommand(testname, blocks, period, genesis, seed)
cmd := makeCmd(s)
cmd.Stdout = stdoutFile
cmd.Stderr = stderrFile
err := cmd.Start()
var err error
var stderr io.ReadCloser
if !exitOnFail {
cmd.Stderr = stderrFile
} else {
stderr, err = cmd.StderrPipe()
if err != nil {
return err
}
}
sc := bufio.NewScanner(stderr)
err = cmd.Start()
if err != nil {
log.Printf("couldn't start %q", s)
return err
}
log.Printf("[W%d] Spawned simulation with pid %d [seed=%d stdout=%s stderr=%s]",
workerId, cmd.Process.Pid, seed, stdoutFile.Name(), stderrFile.Name())
workerID, cmd.Process.Pid, seed, stdoutFile.Name(), stderrFile.Name())
pushProcess(cmd.Process)
defer popProcess(cmd.Process)
return cmd.Wait()
err = cmd.Wait()
if err != nil {
fmt.Printf("%s\n", err)
}
if exitOnFail {
for sc.Scan() {
fmt.Printf("stderr: %s\n", sc.Text())
}
}
return err
}
func pushProcess(proc *os.Process) {

View File

@ -1,145 +0,0 @@
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 := types.GenesisDocFromFile(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) {
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
}
genDoc.AppState = appState
err = ExportGenesisFile(&genDoc, config.GenesisFile())
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,
}
}

View File

@ -1,101 +0,0 @@
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,
},
{
"invalid vesting amount with multi coins",
args{
app.GenesisState{},
addr1,
sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)),
sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)),
0,
1,
},
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)
})
}
}

View File

@ -2,7 +2,6 @@ package lcd_test
import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
@ -16,19 +15,17 @@ import (
"github.com/spf13/viper"
"github.com/stretchr/testify/require"
amino "github.com/tendermint/go-amino"
"github.com/cosmos/cosmos-sdk/client"
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/lcd"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
"github.com/cosmos/cosmos-sdk/client/tx"
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
"github.com/cosmos/cosmos-sdk/client/utils"
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/crypto/keys"
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/tests"
@ -37,12 +34,16 @@ import (
"github.com/cosmos/cosmos-sdk/x/auth"
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
bankrest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
"github.com/cosmos/cosmos-sdk/x/crisis"
distr "github.com/cosmos/cosmos-sdk/x/distribution"
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
"github.com/cosmos/cosmos-sdk/x/genutil"
"github.com/cosmos/cosmos-sdk/x/gov"
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
"github.com/cosmos/cosmos-sdk/x/mint"
mintrest "github.com/cosmos/cosmos-sdk/x/mint/client/rest"
paramsrest "github.com/cosmos/cosmos-sdk/x/params/client/rest"
paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils"
@ -68,10 +69,10 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
)
var cdc = amino.NewCodec()
var cdc = codec.New()
func init() {
ctypes.RegisterAmino(cdc)
codec.RegisterCrypto(cdc)
}
// makePathname creates a unique pathname for each test. It will panic if it
@ -238,10 +239,10 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
require.Nil(t, err)
genDoc.Validators = nil
require.NoError(t, genDoc.SaveAs(genesisFile))
genTxs := []json.RawMessage{}
// append any additional (non-proposing) validators
var accs []gapp.GenesisAccount
var genTxs []auth.StdTx
var accs []genaccounts.GenesisAccount
for i := 0; i < nValidators; i++ {
operPrivKey := secp256k1.GenPrivKey()
operAddr := operPrivKey.PubKey().Address()
@ -268,61 +269,80 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
}
sig, err := operPrivKey.Sign(stdSignMsg.Bytes())
require.Nil(t, err)
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
txBytes, err := cdc.MarshalJSON(tx)
require.Nil(t, err)
genTxs = append(genTxs, txBytes)
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
genTxs = append(genTxs, tx)
valConsPubKeys = append(valConsPubKeys, pubKey)
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
accTokens := sdk.TokensFromTendermintPower(150)
accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)}
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
accs = append(accs, genaccounts.NewGenesisAccount(&accAuth))
}
appGenState := gapp.NewDefaultGenesisState()
appGenState.Accounts = accs
genDoc.AppState, err = cdc.MarshalJSON(appGenState)
genesisState := gapp.NewDefaultGenesisState()
genDoc.AppState, err = cdc.MarshalJSON(genesisState)
require.NoError(t, err)
genesisState, err := gapp.GaiaAppGenState(cdc, *genDoc, genTxs)
genesisState, err = genutil.SetGenTxsInAppGenesisState(cdc, genesisState, genTxs)
require.NoError(t, err)
// add some tokens to init accounts
stakingDataBz := genesisState[staking.ModuleName]
var stakingData staking.GenesisState
cdc.MustUnmarshalJSON(stakingDataBz, &stakingData)
for _, addr := range initAddrs {
accAuth := auth.NewBaseAccountWithAddress(addr)
accTokens := sdk.TokensFromTendermintPower(100)
accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)}
acc := gapp.NewGenesisAccount(&accAuth)
genesisState.Accounts = append(genesisState.Accounts, acc)
genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(accTokens)
acc := genaccounts.NewGenesisAccount(&accAuth)
accs = append(accs, acc)
}
// now add the account tokens to the non-bonded pool
for _, acc := range accs {
accTokens := acc.Coins.AmountOf(sdk.DefaultBondDenom)
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(accTokens)
}
stakingDataBz = cdc.MustMarshalJSON(stakingData)
genesisState[staking.ModuleName] = stakingDataBz
genaccountsData := genaccounts.NewGenesisState(accs)
genaccountsDataBz := cdc.MustMarshalJSON(genaccountsData)
genesisState[genaccounts.ModuleName] = genaccountsDataBz
// mint genesis (none set within genesisState)
mintData := mint.DefaultGenesisState()
inflationMin := sdk.ZeroDec()
if minting {
inflationMin = sdk.MustNewDecFromStr("10000.0")
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
} else {
genesisState.MintData.Params.InflationMax = inflationMin
mintData.Params.InflationMax = inflationMin
}
genesisState.MintData.Minter.Inflation = inflationMin
genesisState.MintData.Params.InflationMin = inflationMin
mintData.Minter.Inflation = inflationMin
mintData.Params.InflationMin = inflationMin
mintDataBz := cdc.MustMarshalJSON(mintData)
genesisState[mint.ModuleName] = mintDataBz
// initialize crisis data
genesisState.CrisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
crisisDataBz := genesisState[crisis.ModuleName]
var crisisData crisis.GenesisState
cdc.MustUnmarshalJSON(crisisDataBz, &crisisData)
crisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
crisisDataBz = cdc.MustMarshalJSON(crisisData)
genesisState[crisis.ModuleName] = crisisDataBz
// double check inflation is set according to the minting boolean flag
if minting {
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
genesisState.MintData.Params.InflationMax)
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), genesisState.MintData.Minter.Inflation)
require.Equal(t, sdk.MustNewDecFromStr("10000.0"),
genesisState.MintData.Params.InflationMin)
require.Equal(t, sdk.MustNewDecFromStr("15000.0"), mintData.Params.InflationMax)
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Minter.Inflation)
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Params.InflationMin)
} else {
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Params.InflationMax)
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Minter.Inflation)
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Params.InflationMin)
require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMax)
require.Equal(t, sdk.ZeroDec(), mintData.Minter.Inflation)
require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMin)
}
appState, err := codec.MarshalJSONIndent(cdc, genesisState)
@ -332,13 +352,13 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
listenAddr, port, err := server.FreeTCPAddr()
require.NoError(t, err)
// XXX: Need to set this so LCD knows the tendermint node address!
// NOTE: Need to set this so LCD knows the tendermint node address!
viper.Set(client.FlagNode, config.RPC.ListenAddress)
viper.Set(client.FlagChainID, genDoc.ChainID)
// TODO Set to false once the upstream Tendermint proof verification issue is fixed.
viper.Set(client.FlagTrustNode, true)
node, err := startTM(config, logger, genDoc, privVal, app)
node := startTM(t, config, logger, genDoc, privVal, app)
require.NoError(t, err)
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
@ -365,16 +385,15 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
//
// TODO: Clean up the WAL dir or enable it to be not persistent!
func startTM(
tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc,
t *testing.T, tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc,
privVal tmtypes.PrivValidator, app abci.Application,
) (*nm.Node, error) {
) *nm.Node {
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
if err != nil {
return nil, err
}
require.NoError(t, err)
node, err := nm.NewNode(
tmcfg,
privVal,
@ -385,19 +404,15 @@ func startTM(
nm.DefaultMetricsProvider(tmcfg.Instrumentation),
logger.With("module", "node"),
)
if err != nil {
return nil, err
}
require.NoError(t, err)
err = node.Start()
if err != nil {
return nil, err
}
require.NoError(t, err)
tests.WaitForRPC(tmcfg.RPC.ListenAddress)
logger.Info("Tendermint running!")
return node, err
return node
}
// startLCD starts the LCD.
@ -412,6 +427,7 @@ func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing
return listener, nil
}
// TODO generalize this with the module basic manager
// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go
func registerRoutes(rs *lcd.RestServer) {
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)

View File

@ -229,7 +229,7 @@ func TestCoinMultiSendGenerateOnly(t *testing.T) {
var stdTx auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &stdTx))
require.Equal(t, len(stdTx.Msgs), 1)
require.Equal(t, stdTx.GetMsgs()[0].Route(), "bank")
require.Equal(t, stdTx.GetMsgs()[0].Route(), bank.RouterKey)
require.Equal(t, stdTx.GetMsgs()[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(stdTx.Signatures))
require.Equal(t, memo, stdTx.Memo)
@ -265,7 +265,7 @@ func TestCoinSendGenerateSignAndBroadcast(t *testing.T) {
var tx auth.StdTx
require.Nil(t, cdc.UnmarshalJSON([]byte(body), &tx))
require.Equal(t, len(tx.Msgs), 1)
require.Equal(t, tx.Msgs[0].Route(), "bank")
require.Equal(t, tx.Msgs[0].Route(), bank.RouterKey)
require.Equal(t, tx.Msgs[0].GetSigners(), []sdk.AccAddress{addr})
require.Equal(t, 0, len(tx.Signatures))
require.Equal(t, memo, tx.Memo)
@ -384,8 +384,8 @@ func TestPoolParamsQuery(t *testing.T) {
tokens := sdk.TokensFromTendermintPower(100)
freeTokens := sdk.TokensFromTendermintPower(50)
initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(tokens)
initialPool.BondedTokens = initialPool.BondedTokens.Add(tokens) // Delegate tx on GaiaAppGenState
initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(freeTokens) // freeTokensPerAcc = 50 on GaiaAppGenState
initialPool.BondedTokens = initialPool.BondedTokens.Add(tokens) // Delegate tx on GaiaAppGenState
initialPool.NotBondedTokens = initialPool.NotBondedTokens.Add(freeTokens)
require.Equal(t, initialPool.BondedTokens, pool.BondedTokens)
@ -815,7 +815,7 @@ func TestUnjail(t *testing.T) {
cleanup, valPubKeys, _, port := InitializeTestLCD(t, 1, []sdk.AccAddress{addr}, true)
defer cleanup()
// XXX: any less than this and it fails
// NOTE: any less than this and it fails
tests.WaitForHeight(3, port)
pkString, _ := sdk.Bech32ifyConsPub(valPubKeys[0])
signingInfo := getSigningInfo(t, port, pkString)

View File

@ -23,11 +23,11 @@ sim-gaia-fast:
sim-gaia-import-export: runsim
@echo "Running Gaia import/export simulation. This may take several minutes..."
$(GOPATH)/bin/runsim 50 5 TestGaiaImportExport
$(GOPATH)/bin/runsim 25 5 TestGaiaImportExport
sim-gaia-simulation-after-import: runsim
@echo "Running Gaia simulation-after-import. This may take several minutes..."
$(GOPATH)/bin/runsim 50 5 TestGaiaSimulationAfterImport
$(GOPATH)/bin/runsim 25 5 TestGaiaSimulationAfterImport
sim-gaia-custom-genesis-multi-seed: runsim
@echo "Running multi-seed custom genesis simulation..."

View File

@ -1,7 +0,0 @@
# 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).

View File

@ -1,132 +0,0 @@
# 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

View File

@ -93,10 +93,9 @@ func VerifyAddressFormat(bz []byte) error {
verifier := GetConfig().GetAddressVerifier()
if verifier != nil {
return verifier(bz)
} else {
if len(bz) != AddrLen {
return errors.New("Incorrect address length")
}
}
if len(bz) != AddrLen {
return errors.New("Incorrect address length")
}
return nil
}

View File

@ -8,3 +8,8 @@ type Invariant func(ctx Context) error
// Invariants defines a group of invariants
type Invariants []Invariant
// expected interface for routing invariants
type InvariantRouter interface {
RegisterRoute(moduleName, route string, invar Invariant)
}

281
types/module.go Normal file
View File

@ -0,0 +1,281 @@
/*
Package types contains application module patterns and associated "manager" functionality.
The module pattern has been broken down by:
- independent module functionality (AppModuleBasic)
- inter-dependent module functionality (AppModule)
inter-dependent module functionality is module functionality which somehow
depends on other modules, typically through the module keeper. Many of the
module keepers are dependent on each other, thus in order to access the full
set of module functionality we need to define all the keepers/params-store/keys
etc. This full set of advanced functionality is defined by the AppModule interface.
Independent module functions are separated to allow for the construction of the
basic application structures required early on in the application definition
and used to enable the definition of full module functionality later in the
process. This separation is necessary, however we still want to allow for a
high level pattern for modules to follow - for instance, such that we don't
have to manually register all of the codecs for all the modules. This basic
procedure as well as other basic patterns are handled through the use of
ModuleBasicManager.
*/
package types
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/spf13/cobra"
abci "github.com/tendermint/tendermint/abci/types"
)
// ModuleClient helps modules provide a standard interface for exporting client functionality
type ModuleClient interface {
GetQueryCmd() *cobra.Command
GetTxCmd() *cobra.Command
}
//__________________________________________________________________________________________
// AppModuleBasic is the standard form for basic non-dependant elements of an application module.
type AppModuleBasic interface {
Name() string
RegisterCodec(*codec.Codec)
DefaultGenesis() json.RawMessage
ValidateGenesis(json.RawMessage) error
}
// collections of AppModuleBasic
type ModuleBasicManager []AppModuleBasic
func NewModuleBasicManager(modules ...AppModuleBasic) ModuleBasicManager {
return modules
}
// RegisterCodecs registers all module codecs
func (mbm ModuleBasicManager) RegisterCodec(cdc *codec.Codec) {
for _, mb := range mbm {
mb.RegisterCodec(cdc)
}
}
// Provided default genesis information for all modules
func (mbm ModuleBasicManager) DefaultGenesis() map[string]json.RawMessage {
genesis := make(map[string]json.RawMessage)
for _, mb := range mbm {
genesis[mb.Name()] = mb.DefaultGenesis()
}
return genesis
}
// Provided default genesis information for all modules
func (mbm ModuleBasicManager) ValidateGenesis(genesis map[string]json.RawMessage) error {
for _, mb := range mbm {
if err := mb.ValidateGenesis(genesis[mb.Name()]); err != nil {
return err
}
}
return nil
}
//_________________________________________________________
// AppModuleGenesis is the standard form for an application module genesis functions
type AppModuleGenesis interface {
AppModuleBasic
InitGenesis(Context, json.RawMessage) []abci.ValidatorUpdate
ExportGenesis(Context) json.RawMessage
}
// AppModule is the standard form for an application module
type AppModule interface {
AppModuleGenesis
// registers
RegisterInvariants(InvariantRouter)
// routes
Route() string
NewHandler() Handler
QuerierRoute() string
NewQuerierHandler() Querier
BeginBlock(Context, abci.RequestBeginBlock) Tags
EndBlock(Context, abci.RequestEndBlock) ([]abci.ValidatorUpdate, Tags)
}
//___________________________
// app module
type GenesisOnlyAppModule struct {
AppModuleGenesis
}
// NewGenesisOnlyAppModule creates a new GenesisOnlyAppModule object
func NewGenesisOnlyAppModule(amg AppModuleGenesis) AppModule {
return GenesisOnlyAppModule{
AppModuleGenesis: amg,
}
}
// register invariants
func (GenesisOnlyAppModule) RegisterInvariants(_ InvariantRouter) {}
// module message route ngame
func (GenesisOnlyAppModule) Route() string { return "" }
// module handler
func (GenesisOnlyAppModule) NewHandler() Handler { return nil }
// module querier route ngame
func (GenesisOnlyAppModule) QuerierRoute() string { return "" }
// module querier
func (gam GenesisOnlyAppModule) NewQuerierHandler() Querier { return nil }
// module begin-block
func (gam GenesisOnlyAppModule) BeginBlock(ctx Context, req abci.RequestBeginBlock) Tags {
return EmptyTags()
}
// module end-block
func (GenesisOnlyAppModule) EndBlock(_ Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, Tags) {
return []abci.ValidatorUpdate{}, EmptyTags()
}
//____________________________________________________________________________
// module manager provides the high level utility for managing and executing
// operations for a group of modules
type ModuleManager struct {
Modules map[string]AppModule
OrderInitGenesis []string
OrderExportGenesis []string
OrderBeginBlockers []string
OrderEndBlockers []string
}
// NewModuleManager creates a new ModuleManager object
func NewModuleManager(modules ...AppModule) *ModuleManager {
moduleMap := make(map[string]AppModule)
var modulesStr []string
for _, module := range modules {
moduleMap[module.Name()] = module
modulesStr = append(modulesStr, module.Name())
}
return &ModuleManager{
Modules: moduleMap,
OrderInitGenesis: modulesStr,
OrderExportGenesis: modulesStr,
OrderBeginBlockers: modulesStr,
OrderEndBlockers: modulesStr,
}
}
// set the order of init genesis calls
func (mm *ModuleManager) SetOrderInitGenesis(moduleNames ...string) {
mm.OrderInitGenesis = moduleNames
}
// set the order of export genesis calls
func (mm *ModuleManager) SetOrderExportGenesis(moduleNames ...string) {
mm.OrderExportGenesis = moduleNames
}
// set the order of set begin-blocker calls
func (mm *ModuleManager) SetOrderBeginBlockers(moduleNames ...string) {
mm.OrderBeginBlockers = moduleNames
}
// set the order of set end-blocker calls
func (mm *ModuleManager) SetOrderEndBlockers(moduleNames ...string) {
mm.OrderEndBlockers = moduleNames
}
// register all module routes and module querier routes
func (mm *ModuleManager) RegisterInvariants(invarRouter InvariantRouter) {
for _, module := range mm.Modules {
module.RegisterInvariants(invarRouter)
}
}
// register all module routes and module querier routes
func (mm *ModuleManager) RegisterRoutes(router Router, queryRouter QueryRouter) {
for _, module := range mm.Modules {
if module.Route() != "" {
router.AddRoute(module.Route(), module.NewHandler())
}
if module.QuerierRoute() != "" {
queryRouter.AddRoute(module.QuerierRoute(), module.NewQuerierHandler())
}
}
}
// perform init genesis functionality for modules
func (mm *ModuleManager) InitGenesis(ctx Context, genesisData map[string]json.RawMessage) abci.ResponseInitChain {
var validatorUpdates []abci.ValidatorUpdate
for _, moduleName := range mm.OrderInitGenesis {
if genesisData[moduleName] == nil {
continue
}
moduleValUpdates := mm.Modules[moduleName].InitGenesis(ctx, genesisData[moduleName])
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
panic("validator InitGenesis updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
return abci.ResponseInitChain{
Validators: validatorUpdates,
}
}
// perform export genesis functionality for modules
func (mm *ModuleManager) ExportGenesis(ctx Context) map[string]json.RawMessage {
genesisData := make(map[string]json.RawMessage)
for _, moduleName := range mm.OrderExportGenesis {
genesisData[moduleName] = mm.Modules[moduleName].ExportGenesis(ctx)
}
return genesisData
}
// perform begin block functionality for modules
func (mm *ModuleManager) BeginBlock(ctx Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
tags := EmptyTags()
for _, moduleName := range mm.OrderBeginBlockers {
moduleTags := mm.Modules[moduleName].BeginBlock(ctx, req)
tags = tags.AppendTags(moduleTags)
}
return abci.ResponseBeginBlock{
Tags: tags.ToKVPairs(),
}
}
// perform end block functionality for modules
func (mm *ModuleManager) EndBlock(ctx Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
validatorUpdates := []abci.ValidatorUpdate{}
tags := EmptyTags()
for _, moduleName := range mm.OrderEndBlockers {
moduleValUpdates, moduleTags := mm.Modules[moduleName].EndBlock(ctx, req)
tags = tags.AppendTags(moduleTags)
// use these validator updates if provided, the module manager assumes
// only one module will update the validator set
if len(moduleValUpdates) > 0 {
if len(validatorUpdates) > 0 {
panic("validator EndBlock updates already set by a previous module")
}
validatorUpdates = moduleValUpdates
}
}
return abci.ResponseEndBlock{
ValidatorUpdates: validatorUpdates,
Tags: tags,
}
}
// DONTCOVER

View File

@ -1,11 +0,0 @@
package types
import (
"github.com/spf13/cobra"
)
// ModuleClients helps modules provide a standard interface for exporting client functionality
type ModuleClients interface {
GetQueryCmd() *cobra.Command
GetTxCmd() *cobra.Command
}

16
types/module_test.go Normal file
View File

@ -0,0 +1,16 @@
package types
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestSetOrderBeginBlockers(t *testing.T) {
mm := NewModuleManager()
mm.SetOrderBeginBlockers("a", "b", "c")
obb := mm.OrderBeginBlockers
require.Equal(t, 3, len(obb))
assert.Equal(t, []string{"a", "b", "c"}, obb)
}

13
types/router.go Normal file
View File

@ -0,0 +1,13 @@
package types
// Router provides handlers for each transaction type.
type Router interface {
AddRoute(r string, h Handler) Router
Route(path string) Handler
}
// QueryRouter provides queryables for each query path.
type QueryRouter interface {
AddRoute(r string, h Querier) QueryRouter
Route(path string) Querier
}

View File

@ -81,6 +81,19 @@ type BaseAccount struct {
Sequence uint64 `json:"sequence"`
}
// NewBaseAccount creates a new BaseAccount object
func NewBaseAccount(address sdk.AccAddress, coins sdk.Coins,
pubKey crypto.PubKey, accountNumber uint64, sequence uint64) *BaseAccount {
return &BaseAccount{
Address: address,
Coins: coins,
PubKey: pubKey,
AccountNumber: accountNumber,
Sequence: sequence,
}
}
// String implements fmt.Stringer
func (acc BaseAccount) String() string {
var pubkey string
@ -190,6 +203,19 @@ type BaseVestingAccount struct {
EndTime int64 `json:"end_time"` // when the coins become unlocked
}
// NewBaseVestingAccount creates a new BaseVestingAccount object
func NewBaseVestingAccount(baseAccount *BaseAccount, originalVesting sdk.Coins,
delegatedFree sdk.Coins, delegatedVesting sdk.Coins, endTime int64) *BaseVestingAccount {
return &BaseVestingAccount{
BaseAccount: baseAccount,
OriginalVesting: originalVesting,
DelegatedFree: delegatedFree,
DelegatedVesting: delegatedVesting,
EndTime: endTime,
}
}
// String implements fmt.Stringer
func (bva BaseVestingAccount) String() string {
var pubkey string
@ -352,6 +378,16 @@ type ContinuousVestingAccount struct {
StartTime int64 `json:"start_time"` // when the coins start to vest
}
// NewContinuousVestingAccountRaw creates a new ContinuousVestingAccount object from BaseVestingAccount
func NewContinuousVestingAccountRaw(bva *BaseVestingAccount,
startTime int64) *ContinuousVestingAccount {
return &ContinuousVestingAccount{
BaseVestingAccount: bva,
StartTime: startTime,
}
}
// NewContinuousVestingAccount returns a new ContinuousVestingAccount
func NewContinuousVestingAccount(
baseAcc *BaseAccount, StartTime, EndTime int64,
@ -462,6 +498,13 @@ type DelayedVestingAccount struct {
*BaseVestingAccount
}
// NewDelayedVestingAccountRaw creates a new DelayedVestingAccount object from BaseVestingAccount
func NewDelayedVestingAccountRaw(bva *BaseVestingAccount) *DelayedVestingAccount {
return &DelayedVestingAccount{
BaseVestingAccount: bva,
}
}
// NewDelayedVestingAccount returns a DelayedVestingAccount
func NewDelayedVestingAccount(baseAcc *BaseAccount, EndTime int64) *DelayedVestingAccount {
baseVestingAcc := &BaseVestingAccount{

View File

@ -215,7 +215,7 @@ func consumeSimSigGas(gasmeter sdk.GasMeter, pubkey crypto.PubKey, sig StdSignat
simSig.Signature = simSecp256k1Sig[:]
}
sigBz := msgCdc.MustMarshalBinaryLengthPrefixed(simSig)
sigBz := moduleCdc.MustMarshalBinaryLengthPrefixed(simSig)
cost := sdk.Gas(len(sigBz) + 6)
// If the pubkey is a multi-signature pubkey, then we estimate for the maximum

View File

@ -26,9 +26,9 @@ func RegisterBaseAccount(cdc *codec.Codec) {
codec.RegisterCrypto(cdc)
}
var msgCdc = codec.New()
var moduleCdc = codec.New()
func init() {
RegisterCodec(msgCdc)
codec.RegisterCrypto(msgCdc)
RegisterCodec(moduleCdc)
codec.RegisterCrypto(moduleCdc)
}

View File

@ -1,4 +1,4 @@
package init
package cli
import (
"fmt"
@ -6,15 +6,21 @@ import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
"github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
"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"
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
"github.com/cosmos/cosmos-sdk/x/genutil"
)
const (
flagClientHome = "home-client"
flagVestingStart = "vesting-start-time"
flagVestingEnd = "vesting-end-time"
flagVestingAmt = "vesting-amount"
)
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
@ -54,33 +60,38 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
return err
}
genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd)
if err := genAcc.Validate(); err != nil {
return err
}
// retrieve the app state
genFile := config.GenesisFile()
if !common.FileExists(genFile) {
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
}
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
appState, genDoc, err := genutil.GenesisStateFromGenFile(cdc, genFile)
if err != nil {
return err
}
var appState app.GenesisState
if err = cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
return err
// add genesis account to the app state
var genesisState genaccounts.GenesisState
cdc.MustUnmarshalJSON(appState[genaccounts.ModuleName], &genesisState)
if genesisState.Accounts.Contains(addr) {
return fmt.Errorf("cannot add account at existing address %v", addr)
}
genesisState.Accounts = append(genesisState.Accounts, genAcc)
appState, err = addGenesisAccount(cdc, appState, addr, coins, vestingAmt, vestingStart, vestingEnd)
if err != nil {
return err
}
genesisStateBz := cdc.MustMarshalJSON(genesisState)
appState[genaccounts.ModuleName] = genesisStateBz
appStateJSON, err := cdc.MarshalJSON(appState)
if err != nil {
return err
}
// export app state
genDoc.AppState = appStateJSON
return ExportGenesisFile(genDoc, genFile)
return genutil.ExportGenesisFile(genDoc, genFile)
},
}
@ -89,55 +100,5 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
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.IsAnyGT(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,14 @@
package genaccounts
import (
"github.com/cosmos/cosmos-sdk/codec"
)
// generic sealed codec to be used throughout this module
var moduleCdc *codec.Codec
func init() {
cdc := codec.New()
codec.RegisterCrypto(cdc)
moduleCdc = cdc.Seal()
}

View File

@ -0,0 +1,9 @@
/*
Package genaccounts contains specialized functionality for initializing
accounts from genesis including:
- genesis account validation,
- initchain processing of genesis accounts,
- export processing (to genesis) of accounts,
- server command for adding accounts to the genesis file.
*/
package genaccounts

View File

@ -0,0 +1,13 @@
package genaccounts
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// expected account keeper
type AccountKeeper interface {
NewAccount(sdk.Context, auth.Account) auth.Account
SetAccount(sdk.Context, auth.Account)
IterateAccounts(ctx sdk.Context, process func(auth.Account) (stop bool))
}

View File

@ -0,0 +1,25 @@
package genaccounts
import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// export genesis for all accounts
func ExportGenesis(ctx sdk.Context, accountKeeper AccountKeeper) GenesisState {
// iterate to get the accounts
accounts := []GenesisAccount{}
accountKeeper.IterateAccounts(ctx,
func(acc auth.Account) (stop bool) {
account, err := NewGenesisAccountI(acc)
if err != nil {
panic(err)
}
accounts = append(accounts, account)
return false
},
)
return NewGenesisState(accounts)
}

View File

@ -0,0 +1,125 @@
package genaccounts
import (
"errors"
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// GenesisAccount is a struct for account initialization used exclusively during 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)
}
// validate the the VestingAccount parameters are possible
func (ga GenesisAccount) Validate() error {
if !ga.OriginalVesting.IsZero() {
if ga.OriginalVesting.IsAnyGT(ga.Coins) {
return errors.New("vesting amount cannot be greater than total amount")
}
if ga.StartTime >= ga.EndTime {
return errors.New("vesting start-time cannot be before end-time")
}
}
return nil
}
// NewGenesisAccount creates a new GenesisAccount object
func NewGenesisAccountRaw(address sdk.AccAddress, coins,
vestingAmount sdk.Coins, vestingStartTime, vestingEndTime int64) GenesisAccount {
return GenesisAccount{
Address: address,
Coins: coins,
Sequence: 0,
AccountNumber: 0, // ignored set by the account keeper during InitGenesis
OriginalVesting: vestingAmount,
DelegatedFree: sdk.Coins{}, // ignored
DelegatedVesting: sdk.Coins{}, // ignored
StartTime: vestingStartTime,
EndTime: vestingEndTime,
}
}
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, error) {
gacc := GenesisAccount{
Address: acc.GetAddress(),
Coins: acc.GetCoins(),
AccountNumber: acc.GetAccountNumber(),
Sequence: acc.GetSequence(),
}
if err := gacc.Validate(); err != nil {
return gacc, err
}
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, nil
}
// convert GenesisAccount to auth.Account
func (ga *GenesisAccount) ToAccount() auth.Account {
bacc := auth.NewBaseAccount(ga.Address, ga.Coins.Sort(),
nil, ga.AccountNumber, ga.Sequence)
if !ga.OriginalVesting.IsZero() {
baseVestingAcc := auth.NewBaseVestingAccount(
bacc, ga.OriginalVesting, ga.DelegatedFree,
ga.DelegatedVesting, ga.EndTime)
switch {
case ga.StartTime != 0 && ga.EndTime != 0:
return auth.NewContinuousVestingAccountRaw(baseVestingAcc, ga.StartTime)
case ga.EndTime != 0:
return auth.NewDelayedVestingAccountRaw(baseVestingAcc)
default:
panic(fmt.Sprintf("invalid genesis vesting account: %+v", ga))
}
}
return bacc
}
//___________________________________
type GenesisAccounts []GenesisAccount
// genesis accounts contain an address
func (gaccs GenesisAccounts) Contains(acc sdk.AccAddress) bool {
for _, gacc := range gaccs {
if gacc.Address.Equals(acc) {
return true
}
}
return false
}

View File

@ -0,0 +1,75 @@
package genaccounts
import (
"errors"
"testing"
"time"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
"github.com/tendermint/tendermint/crypto/secp256k1"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
func TestGenesisAccountValidate(t *testing.T) {
addr := sdk.AccAddress(secp256k1.GenPrivKey().PubKey().Address())
tests := []struct {
name string
acc GenesisAccount
expErr error
}{
{
"valid account",
NewGenesisAccountRaw(addr, sdk.NewCoins(), sdk.NewCoins(), 0, 0),
nil,
},
{
"invalid vesting amount",
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 100)), 0, 0),
errors.New("vesting amount cannot be greater than total amount"),
},
{
"invalid vesting amount with multi coins",
NewGenesisAccountRaw(addr,
sdk.NewCoins(sdk.NewInt64Coin("uatom", 50), sdk.NewInt64Coin("eth", 50)),
sdk.NewCoins(sdk.NewInt64Coin("uatom", 100), sdk.NewInt64Coin("eth", 20)),
0, 0),
errors.New("vesting amount cannot be greater than total amount"),
},
{
"invalid vesting times",
NewGenesisAccountRaw(addr, sdk.NewCoins(sdk.NewInt64Coin("stake", 50)),
sdk.NewCoins(sdk.NewInt64Coin("stake", 50)), 1654668078, 1554668078),
errors.New("vesting start-time cannot be before end-time"),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := tt.acc.Validate()
require.Equal(t, tt.expErr, err)
})
}
}
func TestToAccount(t *testing.T) {
priv := ed25519.GenPrivKey()
addr := sdk.AccAddress(priv.PubKey().Address())
authAcc := auth.NewBaseAccountWithAddress(addr)
authAcc.SetCoins(sdk.NewCoins(sdk.NewInt64Coin(sdk.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, err := NewGenesisAccountI(vacc)
require.NoError(t, err)
acc = genAcc.ToAccount()
require.IsType(t, &auth.ContinuousVestingAccount{}, acc)
require.Equal(t, vacc, acc.(*auth.ContinuousVestingAccount))
}

View File

@ -0,0 +1,85 @@
package genaccounts
import (
"encoding/json"
"fmt"
"sort"
"time"
"github.com/cosmos/cosmos-sdk/codec"
)
// State to Unmarshal
type GenesisState struct {
Accounts GenesisAccounts `json:"accounts"`
}
// NewGenesisState creates a new GenesisState object
func NewGenesisState(accounts GenesisAccounts) GenesisState {
return GenesisState{
Accounts: accounts,
}
}
// get the genesis state from the expected app state
func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState {
var genesisState GenesisState
if appState[ModuleName] != nil {
cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState)
}
return genesisState
}
// set the genesis state within the expected app state
func SetGenesisStateInAppState(cdc *codec.Codec,
appState map[string]json.RawMessage, genesisState GenesisState) map[string]json.RawMessage {
genesisStateBz := cdc.MustMarshalJSON(genesisState)
appState[ModuleName] = genesisStateBz
return appState
}
// 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()
}
}
// ValidateGenesis 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 ValidateGenesis(genesisState GenesisState) error {
addrMap := make(map[string]bool, len(genesisState.Accounts))
for _, acc := range genesisState.Accounts {
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
}

View File

@ -0,0 +1,85 @@
package genaccounts
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
)
func TestSanitize(t *testing.T) {
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 := NewGenesisState([]GenesisAccount{genAcc1, genAcc2})
require.NoError(t, ValidateGenesis(genesisState))
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")
}
var (
pk1 = ed25519.GenPrivKey().PubKey()
pk2 = ed25519.GenPrivKey().PubKey()
addr1 = sdk.ValAddress(pk1.Address())
addr2 = sdk.ValAddress(pk2.Address())
)
// require duplicate accounts fails validation
func TestValidateGenesisDuplicateAccounts(t *testing.T) {
acc1 := auth.NewBaseAccountWithAddress(sdk.AccAddress(addr1))
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
genAccs := make([]GenesisAccount, 2)
genAccs[0] = NewGenesisAccount(&acc1)
genAccs[1] = NewGenesisAccount(&acc1)
genesisState := NewGenesisState(genAccs)
err := ValidateGenesis(genesisState)
require.Error(t, err)
}
// require invalid vesting account fails validation (invalid end time)
func TestValidateGenesisInvalidAccounts(t *testing.T) {
acc1 := auth.NewBaseAccountWithAddress(sdk.AccAddress(addr1))
acc1.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
acc2 := auth.NewBaseAccountWithAddress(sdk.AccAddress(addr2))
acc2.Coins = sdk.NewCoins(sdk.NewInt64Coin(sdk.DefaultBondDenom, 150))
genAccs := make([]GenesisAccount, 2)
genAccs[0] = NewGenesisAccount(&acc1)
genAccs[1] = NewGenesisAccount(&acc2)
genesisState := NewGenesisState(genAccs)
genesisState.Accounts[0].OriginalVesting = genesisState.Accounts[0].Coins
err := ValidateGenesis(genesisState)
require.Error(t, err)
genesisState.Accounts[0].StartTime = 1548888000
genesisState.Accounts[0].EndTime = 1548775410
err = ValidateGenesis(genesisState)
require.Error(t, err)
}

View File

@ -0,0 +1,20 @@
package genaccounts
import (
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// initialize accounts and deliver genesis transactions
func InitGenesis(ctx sdk.Context, cdc *codec.Codec,
accountKeeper AccountKeeper, genesisState GenesisState) {
genesisState.Sanitize()
// load the accounts
for _, gacc := range genesisState.Accounts {
acc := gacc.ToAccount()
acc = accountKeeper.NewAccount(ctx, acc) // set account number
accountKeeper.SetAccount(ctx, acc)
}
}

View File

@ -0,0 +1,89 @@
package genaccounts
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModuleGenesis = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// module name
const ModuleName = "accounts"
// app module basics object
type AppModuleBasic struct{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return moduleCdc.MustMarshalJSON(GenesisState{})
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := moduleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
// extra function from sdk.AppModuleBasic
// iterate the genesis accounts and perform an operation at each of them
// - to used by other modules
func (AppModuleBasic) IterateGenesisAccounts(cdc *codec.Codec, appGenesis map[string]json.RawMessage,
iterateFn func(auth.Account) (stop bool)) {
genesisState := GetGenesisStateFromAppState(cdc, appGenesis)
for _, genAcc := range genesisState.Accounts {
acc := genAcc.ToAccount()
if iterateFn(acc) {
break
}
}
}
//___________________________
// app module
type AppModule struct {
AppModuleBasic
accountKeeper AccountKeeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(accountKeeper AccountKeeper) sdk.AppModule {
return sdk.NewGenesisOnlyAppModule(AppModule{
AppModuleBasic: AppModuleBasic{},
accountKeeper: accountKeeper,
})
}
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
moduleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, moduleCdc, am.accountKeeper, genesisState)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.accountKeeper)
return moduleCdc.MustMarshalJSON(gs)
}

View File

@ -15,8 +15,8 @@ type GenesisState struct {
// NewGenesisState - Create a new genesis state
func NewGenesisState(collectedFees sdk.Coins, params Params) GenesisState {
return GenesisState{
Params: params,
CollectedFees: collectedFees,
Params: params,
}
}

111
x/auth/module.go Normal file
View File

@ -0,0 +1,111 @@
package auth
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModule = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// name of this module
const ModuleName = "auth"
// app module basics object
type AppModuleBasic struct{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return moduleCdc.MustMarshalJSON(DefaultGenesisState())
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := moduleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
//___________________________
// app module object
type AppModule struct {
AppModuleBasic
accountKeeper AccountKeeper
feeCollectionKeeper FeeCollectionKeeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(accountKeeper AccountKeeper,
feeCollectionKeeper FeeCollectionKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
accountKeeper: accountKeeper,
feeCollectionKeeper: feeCollectionKeeper,
}
}
// module name
func (AppModule) Name() string {
return ModuleName
}
// register invariants
func (AppModule) RegisterInvariants(_ sdk.InvariantRouter) {}
// module message route name
func (AppModule) Route() string { return "" }
// module handler
func (AppModule) NewHandler() sdk.Handler { return nil }
// module querier route name
func (AppModule) QuerierRoute() string {
return QuerierRoute
}
// module querier
func (am AppModule) NewQuerierHandler() sdk.Querier {
return NewQuerier(am.accountKeeper)
}
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
moduleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.accountKeeper, am.feeCollectionKeeper, genesisState)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.accountKeeper, am.feeCollectionKeeper)
return moduleCdc.MustMarshalJSON(gs)
}
// module begin-block
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) sdk.Tags {
return sdk.EmptyTags()
}
// module end-block
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) {
return []abci.ValidatorUpdate{}, sdk.EmptyTags()
}

View File

@ -10,7 +10,7 @@ import (
)
// DefaultParamspace defines the default auth module parameter subspace
const DefaultParamspace = "auth"
const DefaultParamspace = ModuleName
// Default parameter values
const (
@ -41,6 +41,19 @@ type Params struct {
SigVerifyCostSecp256k1 uint64 `json:"sig_verify_cost_secp256k1"`
}
// NewParams creates a new Params object
func NewParams(maxMemoCharacters, txSigLimit, txSizeCostPerByte,
sigVerifyCostED25519, sigVerifyCostSecp256k1 uint64) Params {
return Params{
MaxMemoCharacters: maxMemoCharacters,
TxSigLimit: txSigLimit,
TxSizeCostPerByte: txSizeCostPerByte,
SigVerifyCostED25519: sigVerifyCostED25519,
SigVerifyCostSecp256k1: sigVerifyCostSecp256k1,
}
}
// ParamKeyTable for auth module
func ParamKeyTable() params.KeyTable {
return params.NewKeyTable().RegisterParamSet(&Params{})
@ -61,8 +74,8 @@ func (p *Params) ParamSetPairs() subspace.ParamSetPairs {
// Equal returns a boolean determining if two Params types are identical.
func (p Params) Equal(p2 Params) bool {
bz1 := msgCdc.MustMarshalBinaryLengthPrefixed(&p)
bz2 := msgCdc.MustMarshalBinaryLengthPrefixed(&p2)
bz1 := moduleCdc.MustMarshalBinaryLengthPrefixed(&p)
bz2 := moduleCdc.MustMarshalBinaryLengthPrefixed(&p2)
return bytes.Equal(bz1, bz2)
}

View File

@ -20,7 +20,7 @@ func SimulateDeductFee(m auth.AccountKeeper, f auth.FeeCollectionKeeper) simulat
account := simulation.RandomAcc(r, accs)
stored := m.GetAccount(ctx, account.Address)
initCoins := stored.GetCoins()
opMsg = simulation.NewOperationMsgBasic("auth", "deduct_fee", "", false, nil)
opMsg = simulation.NewOperationMsgBasic(auth.ModuleName, "deduct_fee", "", false, nil)
if len(initCoins) == 0 {
return opMsg, nil, nil

View File

@ -143,7 +143,7 @@ func (fee StdFee) Bytes() []byte {
if len(fee.Amount) == 0 {
fee.Amount = sdk.NewCoins()
}
bz, err := msgCdc.MarshalJSON(fee) // TODO
bz, err := moduleCdc.MarshalJSON(fee) // TODO
if err != nil {
panic(err)
}
@ -181,7 +181,7 @@ func StdSignBytes(chainID string, accnum uint64, sequence uint64, fee StdFee, ms
for _, msg := range msgs {
msgsBytes = append(msgsBytes, json.RawMessage(msg.GetSignBytes()))
}
bz, err := msgCdc.MarshalJSON(StdSignDoc{
bz, err := moduleCdc.MarshalJSON(StdSignDoc{
AccountNumber: accnum,
ChainID: chainID,
Fee: json.RawMessage(fee.Bytes()),

View File

@ -21,7 +21,7 @@ func getBenchmarkMockApp() (*mock.App, error) {
mapp.ParamsKeeper.Subspace(DefaultParamspace),
DefaultCodespace,
)
mapp.Router().AddRoute("bank", NewHandler(bankKeeper))
mapp.Router().AddRoute(RouterKey, NewHandler(bankKeeper))
mapp.SetInitChainer(getInitChainer(mapp, bankKeeper))
err := mapp.CompleteSetup()

View File

@ -26,10 +26,10 @@ type SendReq struct {
Amount sdk.Coins `json:"amount"`
}
var msgCdc = codec.New()
var moduleCdc = codec.New()
func init() {
bank.RegisterCodec(msgCdc)
bank.RegisterCodec(moduleCdc)
}
// SendRequestHandlerFn - http request handler to send coins to a address.

View File

@ -10,8 +10,8 @@ func RegisterCodec(cdc *codec.Codec) {
cdc.RegisterConcrete(MsgMultiSend{}, "cosmos-sdk/MsgMultiSend", nil)
}
var msgCdc = codec.New()
var moduleCdc = codec.New()
func init() {
RegisterCodec(msgCdc)
RegisterCodec(moduleCdc)
}

View File

@ -6,7 +6,7 @@ import (
// Bank errors reserve 100 ~ 199.
const (
DefaultCodespace sdk.CodespaceType = "bank"
DefaultCodespace sdk.CodespaceType = ModuleName
CodeSendDisabled sdk.CodeType = 101
CodeInvalidInputsOutputs sdk.CodeType = 102

View File

@ -1,10 +0,0 @@
package bank
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// expected crisis keeper
type CrisisKeeper interface {
RegisterRoute(moduleName, route string, invar sdk.Invariant)
}

View File

@ -9,8 +9,8 @@ import (
)
// register bank invariants
func RegisterInvariants(c CrisisKeeper, ak auth.AccountKeeper) {
c.RegisterRoute("bank", "nonnegative-outstanding",
func RegisterInvariants(ir sdk.InvariantRouter, ak auth.AccountKeeper) {
ir.RegisterRoute(RouterKey, "nonnegative-outstanding",
NonnegativeBalanceInvariant(ak))
}

115
x/bank/module.go Normal file
View File

@ -0,0 +1,115 @@
package bank
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModule = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// name of this module
const ModuleName = "bank"
// app module basics object
type AppModuleBasic struct{}
var _ sdk.AppModuleBasic = AppModuleBasic{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return moduleCdc.MustMarshalJSON(DefaultGenesisState())
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := moduleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
//___________________________
// app module
type AppModule struct {
AppModuleBasic
keeper Keeper
accountKeeper auth.AccountKeeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper, accountKeeper auth.AccountKeeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
accountKeeper: accountKeeper,
}
}
// module name
func (AppModule) Name() string {
return ModuleName
}
// register invariants
func (am AppModule) RegisterInvariants(ir sdk.InvariantRouter) {
RegisterInvariants(ir, am.accountKeeper)
}
// module message route name
func (AppModule) Route() string {
return RouterKey
}
// module handler
func (am AppModule) NewHandler() sdk.Handler {
return NewHandler(am.keeper)
}
// module querier route name
func (AppModule) QuerierRoute() string { return "" }
// module querier
func (AppModule) NewQuerierHandler() sdk.Querier { return nil }
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
moduleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, genesisState)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return moduleCdc.MustMarshalJSON(gs)
}
// module begin-block
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) sdk.Tags {
return sdk.EmptyTags()
}
// module end-block
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) {
return []abci.ValidatorUpdate{}, sdk.EmptyTags()
}

View File

@ -5,7 +5,7 @@ import (
)
// RouterKey is they name of the bank module
const RouterKey = "bank"
const RouterKey = ModuleName
// MsgSend - high level transaction of the coin module
type MsgSend struct {
@ -46,7 +46,7 @@ func (msg MsgSend) ValidateBasic() sdk.Error {
// GetSignBytes Implements Msg.
func (msg MsgSend) GetSignBytes() []byte {
return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg))
return sdk.MustSortJSON(moduleCdc.MustMarshalJSON(msg))
}
// GetSigners Implements Msg.
@ -89,7 +89,7 @@ func (msg MsgMultiSend) ValidateBasic() sdk.Error {
// GetSignBytes Implements Msg.
func (msg MsgMultiSend) GetSignBytes() []byte {
return sdk.MustSortJSON(msgCdc.MustMarshalJSON(msg))
return sdk.MustSortJSON(moduleCdc.MustMarshalJSON(msg))
}
// GetSigners Implements Msg.

View File

@ -15,7 +15,7 @@ func TestMsgSendRoute(t *testing.T) {
coins := sdk.NewCoins(sdk.NewInt64Coin("atom", 10))
var msg = NewMsgSend(addr1, addr2, coins)
require.Equal(t, msg.Route(), "bank")
require.Equal(t, msg.Route(), RouterKey)
require.Equal(t, msg.Type(), "send")
}
@ -80,7 +80,7 @@ func TestMsgMultiSendRoute(t *testing.T) {
}
// TODO some failures for bad result
require.Equal(t, msg.Route(), "bank")
require.Equal(t, msg.Route(), RouterKey)
require.Equal(t, msg.Type(), "multisend")
}

View File

@ -6,7 +6,7 @@ import (
const (
// DefaultParamspace for params keeper
DefaultParamspace = "bank"
DefaultParamspace = ModuleName
// DefaultSendEnabled enabled
DefaultSendEnabled = true
)

16
x/crisis/abci_app.go Normal file
View File

@ -0,0 +1,16 @@
package crisis
import (
"github.com/tendermint/tendermint/libs/log"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// check all registered invariants
func EndBlocker(ctx sdk.Context, k Keeper, logger log.Logger) {
if k.invCheckPeriod == 0 || ctx.BlockHeight()%int64(k.invCheckPeriod) != 0 {
// skip running the invariant check
return
}
k.AssertInvariants(ctx, logger)
}

View File

@ -10,11 +10,11 @@ func RegisterCodec(cdc *codec.Codec) {
}
// generic sealed codec to be used throughout module
var MsgCdc *codec.Codec
var moduleCdc *codec.Codec
func init() {
cdc := codec.New()
RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
MsgCdc = cdc.Seal()
moduleCdc = cdc.Seal()
}

View File

@ -7,11 +7,8 @@ import (
"github.com/cosmos/cosmos-sdk/x/crisis/tags"
)
// ModuleName is the module name for this module
const (
ModuleName = "crisis"
RouterKey = ModuleName
)
// RouterKey
const RouterKey = ModuleName
func NewHandler(k Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {

View File

@ -27,7 +27,7 @@ func CreateTestInput(t *testing.T) (sdk.Context, Keeper, auth.AccountKeeper, dis
distr.CreateTestInputAdvanced(t, false, 10, communityTax)
paramSpace := paramsKeeper.Subspace(DefaultParamspace)
crisisKeeper := NewKeeper(paramSpace, distrKeeper, bankKeeper, feeCollectionKeeper)
crisisKeeper := NewKeeper(paramSpace, 1, distrKeeper, bankKeeper, feeCollectionKeeper)
constantFee := sdk.NewInt64Coin("stake", 10000000)
crisisKeeper.SetConstantFee(ctx, constantFee)

View File

@ -1,14 +1,20 @@
package crisis
import (
"fmt"
"time"
"github.com/tendermint/tendermint/libs/log"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/params"
)
// Keeper - crisis keeper
type Keeper struct {
routes []InvarRoute
paramSpace params.Subspace
routes []InvarRoute
paramSpace params.Subspace
invCheckPeriod uint
distrKeeper DistrKeeper
bankKeeper BankKeeper
@ -16,13 +22,14 @@ type Keeper struct {
}
// NewKeeper creates a new Keeper object
func NewKeeper(paramSpace params.Subspace,
func NewKeeper(paramSpace params.Subspace, invCheckPeriod uint,
distrKeeper DistrKeeper, bankKeeper BankKeeper,
feeCollectionKeeper FeeCollectionKeeper) Keeper {
return Keeper{
routes: []InvarRoute{},
paramSpace: paramSpace.WithKeyTable(ParamKeyTable()),
invCheckPeriod: invCheckPeriod,
distrKeeper: distrKeeper,
bankKeeper: bankKeeper,
feeCollectionKeeper: feeCollectionKeeper,
@ -49,4 +56,25 @@ func (k Keeper) Invariants() []sdk.Invariant {
return invars
}
// assert all invariants
func (k Keeper) AssertInvariants(ctx sdk.Context, logger log.Logger) {
start := time.Now()
invarRoutes := k.Routes()
for _, ir := range invarRoutes {
if err := ir.Invar(ctx); err != nil {
// TODO make "gaiacli" app name a part of context to allow for this to be variable
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)
logger.With("module", "x/crisis").Info(
"Asserted all invariants", "duration", diff, "height", ctx.BlockHeight())
}
// DONTCOVER

117
x/crisis/module.go Normal file
View File

@ -0,0 +1,117 @@
package crisis
import (
"encoding/json"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModule = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// name of this module
const ModuleName = "crisis"
// app module basics object
type AppModuleBasic struct{}
var _ sdk.AppModuleBasic = AppModuleBasic{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return moduleCdc.MustMarshalJSON(DefaultGenesisState())
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := moduleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
//___________________________
// app module for bank
type AppModule struct {
AppModuleBasic
keeper Keeper
logger log.Logger
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper, logger log.Logger) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
logger: logger,
}
}
// module name
func (AppModule) Name() string {
return ModuleName
}
// register invariants
func (AppModule) RegisterInvariants(_ sdk.InvariantRouter) {}
// module querier route name
func (AppModule) Route() string {
return RouterKey
}
// module handler
func (am AppModule) NewHandler() sdk.Handler {
return NewHandler(am.keeper)
}
// module querier route name
func (AppModule) QuerierRoute() string { return "" }
// module querier
func (AppModule) NewQuerierHandler() sdk.Querier { return nil }
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
moduleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, genesisState)
am.keeper.AssertInvariants(ctx, am.logger)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return moduleCdc.MustMarshalJSON(gs)
}
// module begin-block
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) sdk.Tags {
return sdk.EmptyTags()
}
// module end-block
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) {
EndBlocker(ctx, am.keeper, am.logger)
return []abci.ValidatorUpdate{}, sdk.EmptyTags()
}

View File

@ -34,7 +34,7 @@ func (msg MsgVerifyInvariant) GetSigners() []sdk.AccAddress { return []sdk.AccAd
// GetSignBytes gets the sign bytes for the msg MsgVerifyInvariant
func (msg MsgVerifyInvariant) GetSignBytes() []byte {
bz := MsgCdc.MustMarshalJSON(msg)
bz := moduleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}

View File

@ -8,6 +8,7 @@ import (
)
// set the proposer for determining distribution during endblock
// and distribute rewards for the previous block
func BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock, k keeper.Keeper) {
// determine the total power signing the block

View File

@ -34,6 +34,7 @@ type (
)
const (
ModuleName = types.ModuleName
DefaultCodespace = types.DefaultCodespace
CodeInvalidInput = types.CodeInvalidInput
StoreKey = types.StoreKey
@ -49,6 +50,7 @@ var (
TagValidator = tags.Validator
ModuleCdc = types.ModuleCdc
NewMsgSetWithdrawAddress = types.NewMsgSetWithdrawAddress
NewMsgWithdrawDelegatorReward = types.NewMsgWithdrawDelegatorReward
NewMsgWithdrawValidatorCommission = types.NewMsgWithdrawValidatorCommission

View File

@ -8,19 +8,19 @@ import (
)
// register all distribution invariants
func RegisterInvariants(c types.CrisisKeeper, k Keeper, stk types.StakingKeeper) {
c.RegisterRoute(types.ModuleName, "nonnegative-outstanding",
func RegisterInvariants(ir sdk.InvariantRouter, k Keeper) {
ir.RegisterRoute(types.ModuleName, "nonnegative-outstanding",
NonNegativeOutstandingInvariant(k))
c.RegisterRoute(types.ModuleName, "can-withdraw",
CanWithdrawInvariant(k, stk))
c.RegisterRoute(types.ModuleName, "reference-count",
ReferenceCountInvariant(k, stk))
ir.RegisterRoute(types.ModuleName, "can-withdraw",
CanWithdrawInvariant(k))
ir.RegisterRoute(types.ModuleName, "reference-count",
ReferenceCountInvariant(k))
}
// AllInvariants runs all invariants of the distribution module
func AllInvariants(k Keeper, stk types.StakingKeeper) sdk.Invariant {
func AllInvariants(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) error {
err := CanWithdrawInvariant(k, stk)(ctx)
err := CanWithdrawInvariant(k)(ctx)
if err != nil {
return err
}
@ -28,7 +28,7 @@ func AllInvariants(k Keeper, stk types.StakingKeeper) sdk.Invariant {
if err != nil {
return err
}
err = ReferenceCountInvariant(k, stk)(ctx)
err = ReferenceCountInvariant(k)(ctx)
if err != nil {
return err
}
@ -60,7 +60,7 @@ func NonNegativeOutstandingInvariant(k Keeper) sdk.Invariant {
}
// CanWithdrawInvariant checks that current rewards can be completely withdrawn
func CanWithdrawInvariant(k Keeper, sk types.StakingKeeper) sdk.Invariant {
func CanWithdrawInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) error {
// cache, we don't want to write changes
@ -69,13 +69,13 @@ func CanWithdrawInvariant(k Keeper, sk types.StakingKeeper) sdk.Invariant {
var remaining sdk.DecCoins
valDelegationAddrs := make(map[string][]sdk.AccAddress)
for _, del := range sk.GetAllSDKDelegations(ctx) {
for _, del := range k.stakingKeeper.GetAllSDKDelegations(ctx) {
valAddr := del.GetValidatorAddr().String()
valDelegationAddrs[valAddr] = append(valDelegationAddrs[valAddr], del.GetDelegatorAddr())
}
// iterate over all validators
sk.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
k.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
_, _ = k.WithdrawValidatorCommission(ctx, val.GetOperator())
delegationAddrs, ok := valDelegationAddrs[val.GetOperator().String()]
@ -104,15 +104,15 @@ func CanWithdrawInvariant(k Keeper, sk types.StakingKeeper) sdk.Invariant {
}
// ReferenceCountInvariant checks that the number of historical rewards records is correct
func ReferenceCountInvariant(k Keeper, sk types.StakingKeeper) sdk.Invariant {
func ReferenceCountInvariant(k Keeper) sdk.Invariant {
return func(ctx sdk.Context) error {
valCount := uint64(0)
sk.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
k.stakingKeeper.IterateValidators(ctx, func(_ int64, val sdk.Validator) (stop bool) {
valCount++
return false
})
dels := sk.GetAllSDKDelegations(ctx)
dels := k.stakingKeeper.GetAllSDKDelegations(ctx)
slashCount := uint64(0)
k.IterateValidatorSlashEvents(ctx,
func(_ sdk.ValAddress, _ uint64, _ types.ValidatorSlashEvent) (stop bool) {

111
x/distribution/module.go Normal file
View File

@ -0,0 +1,111 @@
package distribution
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModule = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// app module basics object
type AppModuleBasic struct{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return ModuleCdc.MustMarshalJSON(DefaultGenesisState())
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := ModuleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
// app module
type AppModule struct {
AppModuleBasic
keeper Keeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
}
}
// module name
func (AppModule) Name() string {
return ModuleName
}
// register invariants
func (am AppModule) RegisterInvariants(ir sdk.InvariantRouter) {
RegisterInvariants(ir, am.keeper)
}
// module message route name
func (AppModule) Route() string {
return RouterKey
}
// module handler
func (am AppModule) NewHandler() sdk.Handler {
return NewHandler(am.keeper)
}
// module querier route name
func (AppModule) QuerierRoute() string {
return QuerierRoute
}
// module querier
func (am AppModule) NewQuerierHandler() sdk.Querier {
return NewQuerier(am.keeper)
}
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
ModuleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, genesisState)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return ModuleCdc.MustMarshalJSON(gs)
}
// module begin-block
func (am AppModule) BeginBlock(ctx sdk.Context, req abci.RequestBeginBlock) sdk.Tags {
BeginBlocker(ctx, req, am.keeper)
return sdk.EmptyTags()
}
// module end-block
func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) {
return []abci.ValidatorUpdate{}, sdk.EmptyTags()
}

View File

@ -12,11 +12,11 @@ func RegisterCodec(cdc *codec.Codec) {
}
// generic sealed codec to be used throughout module
var MsgCdc *codec.Codec
var ModuleCdc *codec.Codec
func init() {
cdc := codec.New()
RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
MsgCdc = cdc.Seal()
ModuleCdc = cdc.Seal()
}

View File

@ -28,8 +28,3 @@ type FeeCollectionKeeper interface {
GetCollectedFees(ctx sdk.Context) sdk.Coins
ClearCollectedFees(ctx sdk.Context)
}
// expected crisis keeper
type CrisisKeeper interface {
RegisterRoute(moduleName, route string, invar sdk.Invariant)
}

View File

@ -31,7 +31,7 @@ func (msg MsgSetWithdrawAddress) GetSigners() []sdk.AccAddress {
// get the bytes for the message signer to sign on
func (msg MsgSetWithdrawAddress) GetSignBytes() []byte {
bz := MsgCdc.MustMarshalJSON(msg)
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}
@ -69,7 +69,7 @@ func (msg MsgWithdrawDelegatorReward) GetSigners() []sdk.AccAddress {
// get the bytes for the message signer to sign on
func (msg MsgWithdrawDelegatorReward) GetSignBytes() []byte {
bz := MsgCdc.MustMarshalJSON(msg)
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}
@ -105,7 +105,7 @@ func (msg MsgWithdrawValidatorCommission) GetSigners() []sdk.AccAddress {
// get the bytes for the message signer to sign on
func (msg MsgWithdrawValidatorCommission) GetSignBytes() []byte {
bz := MsgCdc.MustMarshalJSON(msg)
bz := ModuleCdc.MustMarshalJSON(msg)
return sdk.MustSortJSON(bz)
}

View File

@ -0,0 +1,69 @@
package cli
import (
"encoding/json"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/tendermint/libs/cli"
tmtypes "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/genutil"
)
const flagGenTxDir = "gentx-dir"
// CollectGenTxsCmd - return the cobra command to collect genesis transactions
func CollectGenTxsCmd(ctx *server.Context, cdc *codec.Codec,
genAccIterator genutil.GenesisAccountsIterator) *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 := genutil.InitializeNodeValidatorFiles(config)
if err != nil {
return err
}
genDoc, err := tmtypes.GenesisDocFromFile(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 := genutil.NewInitConfig(genDoc.ChainID, genTxsDir, name, nodeID, valPubKey)
appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genAccIterator)
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
}
// DONTCOVER

View File

@ -1,9 +1,8 @@
package init
// DONTCOVER
package cli
import (
"bytes"
"encoding/json"
"fmt"
"io"
"io/ioutil"
@ -23,13 +22,14 @@ import (
"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/genutil"
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
)
@ -44,7 +44,9 @@ var (
// GenTxCmd builds the gaiad gentx command.
// nolint: errcheck
func GenTxCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm sdk.ModuleBasicManager,
genAccIterator genutil.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command {
cmd := &cobra.Command{
Use: "gentx",
Short: "Generate a genesis tx carrying a self delegation",
@ -64,7 +66,7 @@ following delegation and commission default parameters:
config := ctx.Config
config.SetRoot(viper.GetString(tmcli.HomeFlag))
nodeID, valPubKey, err := InitializeNodeValidatorFiles(ctx.Config)
nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config)
if err != nil {
return err
}
@ -85,12 +87,12 @@ following delegation and commission default parameters:
return err
}
genesisState := app.GenesisState{}
var genesisState map[string]json.RawMessage
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
return err
}
if err = app.GaiaValidateGenesisState(genesisState); err != nil {
if err = mbm.ValidateGenesis(genesisState); err != nil {
return err
}
@ -127,7 +129,7 @@ following delegation and commission default parameters:
return err
}
err = accountInGenesis(genesisState, key.GetAddress(), coins)
err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc)
if err != nil {
return err
}
@ -199,8 +201,8 @@ following delegation and commission default parameters:
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(tmcli.HomeFlag, defaultNodeHome, "node's home directory")
cmd.Flags().String(flagClientHome, 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")
@ -217,32 +219,36 @@ following delegation and commission default parameters:
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
}
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
}
if accountIsInGenesis {
return 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
}
return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key)
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)
defer outputFile.Close()
if err != nil {
return err
}
json, err := cdc.MarshalJSON(tx)
if err != nil {
return err
}
_, err = fmt.Fprintf(outputFile, "%s\n", json)
return err
}
func prepareFlagsForTxCreateValidator(
@ -279,35 +285,4 @@ func prepareFlagsForTxCreateValidator(
}
}
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
}
// DONTCOVER

View File

@ -1,4 +1,4 @@
package init
package cli
import (
"testing"
@ -50,7 +50,10 @@ func Test_prepareFlagsForTxCreateValidator(t *testing.T) {
}
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)
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))
@ -66,7 +69,13 @@ func Test_prepareFlagsForTxCreateValidator(t *testing.T) {
{"Optional parameters fed", args{ctx.Config, "X", "0.0.0.0", "chainId", valPubKey, "cosmos.network", "details", "identity"}},
}
defaultParams := extraParams{defaultAmount, defaultCommissionRate, defaultCommissionMaxRate, defaultCommissionMaxChangeRate, defaultMinSelfDelegation}
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) })

View File

@ -1,4 +1,4 @@
package init
package cli
import (
"encoding/json"
@ -17,14 +17,13 @@ import (
"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/genutil"
)
const (
flagOverwrite = "overwrite"
flagClientHome = "home-client"
flagVestingStart = "vesting-start-time"
flagVestingEnd = "vesting-end-time"
flagVestingAmt = "vesting-amount"
flagOverwrite = "overwrite"
flagClientHome = "home-client"
)
type printInfo struct {
@ -35,6 +34,18 @@ type printInfo struct {
AppMessage json.RawMessage `json:"app_message"`
}
func newPrintInfo(moniker, chainID, nodeID, genTxsDir string,
appMessage json.RawMessage) printInfo {
return printInfo{
Moniker: moniker,
ChainID: chainID,
NodeID: nodeID,
GenTxsDir: genTxsDir,
AppMessage: appMessage,
}
}
func displayInfo(cdc *codec.Codec, info printInfo) error {
out, err := codec.MarshalJSONIndent(cdc, info)
if err != nil {
@ -47,7 +58,7 @@ func displayInfo(cdc *codec.Codec, info printInfo) error {
// 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
func InitCmd(ctx *server.Context, cdc *codec.Codec, mbm sdk.ModuleBasicManager) *cobra.Command { // nolint: golint
cmd := &cobra.Command{
Use: "init [moniker]",
Short: "Initialize private validator, p2p, genesis, and application configuration files",
@ -62,18 +73,19 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { // nolint:
chainID = fmt.Sprintf("test-chain-%v", common.RandStr(6))
}
nodeID, _, err := InitializeNodeValidatorFiles(config)
nodeID, _, err := genutil.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 {
if !viper.GetBool(flagOverwrite) && common.FileExists(genFile) {
return fmt.Errorf("genesis.json file already exists: %v", genFile)
}
appState, err := codec.MarshalJSONIndent(cdc, mbm.DefaultGenesis())
if err != nil {
return err
}
@ -92,7 +104,7 @@ func InitCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command { // nolint:
genDoc.ChainID = chainID
genDoc.Validators = nil
genDoc.AppState = appState
if err = ExportGenesisFile(genDoc, genFile); err != nil {
if err = genutil.ExportGenesisFile(genDoc, genFile); err != nil {
return err
}

View File

@ -1,4 +1,4 @@
package init
package cli
import (
"bytes"
@ -19,8 +19,12 @@ import (
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/server"
"github.com/cosmos/cosmos-sdk/server/mock"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/genutil"
)
var testMbm = sdk.NewModuleBasicManager(genutil.AppModuleBasic{})
func TestInitCmd(t *testing.T) {
defer server.SetupViper(t)()
defer setupClientHome(t)()
@ -31,7 +35,7 @@ func TestInitCmd(t *testing.T) {
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
cmd := InitCmd(ctx, cdc)
cmd := InitCmd(ctx, cdc, testMbm)
require.NoError(t, cmd.RunE(nil, []string{"gaianode-test"}))
}
@ -59,7 +63,7 @@ func TestEmptyState(t *testing.T) {
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
cmd := InitCmd(ctx, cdc)
cmd := InitCmd(ctx, cdc, testMbm)
require.NoError(t, cmd.RunE(nil, []string{"gaianode-test"}))
old := os.Stdout
@ -80,11 +84,12 @@ func TestEmptyState(t *testing.T) {
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")
require.Contains(t, out, "app_state")
}
func TestStartStandAlone(t *testing.T) {
@ -101,7 +106,7 @@ func TestStartStandAlone(t *testing.T) {
require.Nil(t, err)
ctx := server.NewContext(cfg, logger)
cdc := app.MakeCodec()
initCmd := InitCmd(ctx, cdc)
initCmd := InitCmd(ctx, cdc, testMbm)
require.NoError(t, initCmd.RunE(nil, []string{"gaianode-test"}))
app, err := mock.NewApp(home, logger)
@ -130,7 +135,7 @@ func TestInitNodeValidatorFiles(t *testing.T) {
viper.Set(client.FlagName, "moniker")
cfg, err := tcmd.ParseConfig()
require.Nil(t, err)
nodeID, valPubKey, err := InitializeNodeValidatorFiles(cfg)
nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(cfg)
require.Nil(t, err)
require.NotEqual(t, "", nodeID)
require.NotEqual(t, 0, len(valPubKey.Bytes()))

View File

@ -1,19 +1,20 @@
package init
package cli
import (
"encoding/json"
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/tendermint/tendermint/types"
tmtypes "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"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Validate genesis command takes
func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec, mbm sdk.ModuleBasicManager) *cobra.Command {
return &cobra.Command{
Use: "validate-genesis [file]",
Args: cobra.RangeArgs(0, 1),
@ -28,23 +29,24 @@ func ValidateGenesisCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command {
genesis = args[0]
}
//nolint
fmt.Fprintf(os.Stderr, "validating genesis file at %s\n", genesis)
var genDoc *types.GenesisDoc
if genDoc, err = types.GenesisDocFromFile(genesis); err != nil {
return fmt.Errorf("Error loading genesis doc from %s: %s", genesis, err.Error())
var genDoc *tmtypes.GenesisDoc
if genDoc, err = tmtypes.GenesisDocFromFile(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())
var genState map[string]json.RawMessage
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())
if err = mbm.ValidateGenesis(genState); err != nil {
return fmt.Errorf("error validating genesis file %s: %s", genesis, err.Error())
}
// TODO test to make sure initchain doesn't panic
fmt.Printf("File at %s is a valid genesis file for gaiad\n", genesis)
return nil
},

23
x/genutil/codec.go Normal file
View File

@ -0,0 +1,23 @@
package genutil
import (
"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/staking"
)
// generic sealed codec to be used throughout this module
var moduleCdc *codec.Codec
func init() {
cdc := codec.New()
// TODO abstract genesis transactions registration back to staking
// required for genesis transactions
staking.RegisterCodec(cdc)
auth.RegisterCodec(cdc)
sdk.RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
moduleCdc = cdc.Seal()
}

205
x/genutil/collect.go Normal file
View File

@ -0,0 +1,205 @@
package genutil
// DONTCOVER
import (
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sort"
"strings"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
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/staking"
)
const flagGenTxDir = "gentx-dir"
// common config options for init
type InitConfig struct {
ChainID string
GenTxsDir string
Name string
NodeID string
ValPubKey crypto.PubKey
}
// NewInitConfig creates a new InitConfig object
func NewInitConfig(chainID, genTxsDir, name, nodeID string, valPubKey crypto.PubKey) InitConfig {
return InitConfig{
ChainID: chainID,
GenTxsDir: genTxsDir,
Name: name,
NodeID: nodeID,
ValPubKey: valPubKey,
}
}
// get the genesis app state from the config
func GenAppStateFromConfig(cdc *codec.Codec, config *cfg.Config,
initCfg InitConfig, genDoc tmtypes.GenesisDoc,
genAccIterator GenesisAccountsIterator,
) (appState json.RawMessage, err error) {
// process genesis transactions, else create default genesis.json
appGenTxs, persistentPeers, err := CollectStdTxs(
cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genAccIterator)
if err != nil {
return appState, err
}
config.P2P.PersistentPeers = persistentPeers
cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
// if there are no gen txs to be processed, return the default empty state
if len(appGenTxs) == 0 {
return appState, errors.New("there must be at least one genesis tx")
}
// create the app state
appGenesisState, err := GenesisStateFromGenDoc(cdc, genDoc)
if err != nil {
return appState, err
}
appGenesisState, err = SetGenTxsInAppGenesisState(cdc, appGenesisState, appGenTxs)
if err != nil {
return appState, err
}
appState, err = codec.MarshalJSONIndent(cdc, appGenesisState)
if err != nil {
return appState, err
}
genDoc.AppState = appState
err = ExportGenesisFile(&genDoc, config.GenesisFile())
return appState, err
}
// Set the genesis transactions int the app genesis state
func SetGenTxsInAppGenesisState(cdc *codec.Codec, appGenesisState map[string]json.RawMessage,
genTxs []auth.StdTx) (map[string]json.RawMessage, error) {
genesisState := GetGenesisStateFromAppState(cdc, appGenesisState)
// convert all the GenTxs to JSON
var genTxsBz []json.RawMessage
for _, genTx := range genTxs {
txBz, err := cdc.MarshalJSON(genTx)
if err != nil {
return appGenesisState, err
}
genTxsBz = append(genTxsBz, txBz)
}
genesisState.GenTxs = genTxsBz
return SetGenesisStateInAppState(cdc, appGenesisState, genesisState), nil
}
// 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, genTxsDir string,
genDoc tmtypes.GenesisDoc, genAccIterator GenesisAccountsIterator,
) (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 map[string]json.RawMessage
if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
return appGenTxs, persistentPeers, err
}
addrMap := make(map[string]auth.Account)
genAccIterator.IterateGenesisAccounts(cdc, appState,
func(acc auth.Account) (stop bool) {
addrMap[acc.GetAddress().String()] = acc
return false
},
)
// 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")
}
// TODO abstract out staking reference here through the expected staking keeper
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]
if !delOk {
return appGenTxs, persistentPeers, fmt.Errorf(
"account %v not in genesis.json: %+v", delAddr, addrMap)
}
_, valOk := addrMap[valAddr]
if !valOk {
return appGenTxs, persistentPeers, fmt.Errorf(
"account %v not in genesis.json: %+v", valAddr, addrMap)
}
if delAcc.GetCoins().AmountOf(msg.Value.Denom).LT(msg.Value.Amount) {
return appGenTxs, persistentPeers, fmt.Errorf(
"insufficient fund for delegation %v: %v < %v",
delAcc.GetAddress(), delAcc.GetCoins().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
}

10
x/genutil/doc.go Normal file
View File

@ -0,0 +1,10 @@
/*
Package genutil contains a variety of genesis utility functionality
for usage within a blockchain application. Namely:
- Genesis transactions related (gentx)
- commands for collection and creation of gentxs
- initchain processing of gentxs
- Genesis file validation
- Tendermint related initialization
*/
package genutil

32
x/genutil/expected.go Normal file
View File

@ -0,0 +1,32 @@
package genutil
import (
"encoding/json"
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
)
// expected staking keeper
type StakingKeeper interface {
ApplyAndReturnValidatorSetUpdates(sdk.Context) (updates []abci.ValidatorUpdate)
}
// expected account keeper
type AccountKeeper interface {
NewAccount(sdk.Context, auth.Account) auth.Account
SetAccount(sdk.Context, auth.Account)
IterateAccounts(ctx sdk.Context, process func(auth.Account) (stop bool))
}
// The expected interface for iterating genesis accounts object
type GenesisAccountsIterator interface {
IterateGenesisAccounts(
cdc *codec.Codec,
appGenesis map[string]json.RawMessage,
iterateFn func(auth.Account) (stop bool),
)
}

106
x/genutil/genesis_state.go Normal file
View File

@ -0,0 +1,106 @@
package genutil
import (
"encoding/json"
"errors"
"fmt"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/tendermint/tendermint/libs/common"
tmtypes "github.com/tendermint/tendermint/types"
)
// State to Unmarshal
type GenesisState struct {
GenTxs []json.RawMessage `json:"gentxs"`
}
// NewGenesisState creates a new GenesisState object
func NewGenesisState(genTxs []json.RawMessage) GenesisState {
return GenesisState{
GenTxs: genTxs,
}
}
// NewGenesisStateFromStdTx creates a new GenesisState object
// from auth transactions
func NewGenesisStateFromStdTx(genTxs []auth.StdTx) GenesisState {
genTxsBz := make([]json.RawMessage, len(genTxs))
for i, genTx := range genTxs {
genTxsBz[i] = moduleCdc.MustMarshalJSON(genTx)
}
return GenesisState{
GenTxs: genTxsBz,
}
}
// get the genutil genesis state from the expected app state
func GetGenesisStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) GenesisState {
var genesisState GenesisState
if appState[ModuleName] != nil {
cdc.MustUnmarshalJSON(appState[ModuleName], &genesisState)
}
return genesisState
}
// set the genutil genesis state within the expected app state
func SetGenesisStateInAppState(cdc *codec.Codec,
appState map[string]json.RawMessage, genesisState GenesisState) map[string]json.RawMessage {
genesisStateBz := cdc.MustMarshalJSON(genesisState)
appState[ModuleName] = genesisStateBz
return appState
}
// Create the core parameters for genesis initialization for gaia
// note that the pubkey input is this machines pubkey
func GenesisStateFromGenDoc(cdc *codec.Codec, genDoc tmtypes.GenesisDoc,
) (genesisState map[string]json.RawMessage, err error) {
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
return genesisState, err
}
return genesisState, nil
}
// Create the core parameters for genesis initialization for gaia
// note that the pubkey input is this machines pubkey
func GenesisStateFromGenFile(cdc *codec.Codec, genFile string,
) (genesisState map[string]json.RawMessage, genDoc *tmtypes.GenesisDoc, err error) {
if !common.FileExists(genFile) {
return genesisState, genDoc,
fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
}
genDoc, err = tmtypes.GenesisDocFromFile(genFile)
if err != nil {
return genesisState, genDoc, err
}
genesisState, err = GenesisStateFromGenDoc(cdc, *genDoc)
return genesisState, genDoc, err
}
// validate GenTx transactions
func ValidateGenesis(genesisState GenesisState) error {
for i, genTx := range genesisState.GenTxs {
var tx auth.StdTx
if err := moduleCdc.UnmarshalJSON(genTx, &tx); err != nil {
return err
}
msgs := tx.GetMsgs()
if len(msgs) != 1 {
return errors.New(
"must provide genesis StdTx with exactly 1 CreateValidator message")
}
if _, ok := msgs[0].(staking.MsgCreateValidator); !ok {
return fmt.Errorf(
"Genesis transaction %v does not contain a MsgCreateValidator", i)
}
}
return nil
}

View File

@ -0,0 +1,46 @@
package genutil
import (
"testing"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
"github.com/cosmos/cosmos-sdk/x/staking"
"github.com/stretchr/testify/require"
"github.com/tendermint/tendermint/crypto/ed25519"
)
var (
pk1 = ed25519.GenPrivKey().PubKey()
pk2 = ed25519.GenPrivKey().PubKey()
)
func TestValidateGenesisMultipleMessages(t *testing.T) {
desc := staking.NewDescription("testname", "", "", "")
comm := staking.CommissionMsg{}
msg1 := staking.NewMsgCreateValidator(sdk.ValAddress(pk1.Address()), pk1,
sdk.NewInt64Coin(sdk.DefaultBondDenom, 50), desc, comm, sdk.OneInt())
msg2 := staking.NewMsgCreateValidator(sdk.ValAddress(pk2.Address()), pk2,
sdk.NewInt64Coin(sdk.DefaultBondDenom, 50), desc, comm, sdk.OneInt())
genTxs := auth.NewStdTx([]sdk.Msg{msg1, msg2}, auth.StdFee{}, nil, "")
genesisState := NewGenesisStateFromStdTx([]auth.StdTx{genTxs})
err := ValidateGenesis(genesisState)
require.Error(t, err)
}
func TestValidateGenesisBadMessage(t *testing.T) {
desc := staking.NewDescription("testname", "", "", "")
msg1 := staking.NewMsgEditValidator(sdk.ValAddress(pk1.Address()), desc, nil, nil)
genTxs := auth.NewStdTx([]sdk.Msg{msg1}, auth.StdFee{}, nil, "")
genesisState := NewGenesisStateFromStdTx([]auth.StdTx{genTxs})
err := ValidateGenesis(genesisState)
require.Error(t, err)
}

94
x/genutil/gentx.go Normal file
View File

@ -0,0 +1,94 @@
package genutil
// DONTCOVER
import (
"encoding/json"
"fmt"
abci "github.com/tendermint/tendermint/abci/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/staking"
)
var (
defaultTokens = sdk.TokensFromTendermintPower(100)
defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom
defaultCommissionRate = "0.1"
defaultCommissionMaxRate = "0.2"
defaultCommissionMaxChangeRate = "0.01"
defaultMinSelfDelegation = "1"
)
// ValidateAccountInGenesis checks that the provided key has sufficient
// coins in the genesis accounts
func ValidateAccountInGenesis(appGenesisState map[string]json.RawMessage,
genAccIterator GenesisAccountsIterator,
key sdk.AccAddress, coins sdk.Coins, cdc *codec.Codec) error {
accountIsInGenesis := false
// TODO refactor out bond denom to common state area
stakingDataBz := appGenesisState[staking.ModuleName]
var stakingData staking.GenesisState
cdc.MustUnmarshalJSON(stakingDataBz, &stakingData)
bondDenom := stakingData.Params.BondDenom
genUtilDataBz := appGenesisState[staking.ModuleName]
var genesisState GenesisState
cdc.MustUnmarshalJSON(genUtilDataBz, &genesisState)
var err error
genAccIterator.IterateGenesisAccounts(cdc, appGenesisState,
func(acc auth.Account) (stop bool) {
accAddress := acc.GetAddress()
accCoins := acc.GetCoins()
// Ensure that account is in genesis
if accAddress.Equals(key) {
// Ensure account contains enough funds of default bond denom
if coins.AmountOf(bondDenom).GT(accCoins.AmountOf(bondDenom)) {
err = fmt.Errorf(
"account %v is in genesis, but it only has %v%v available to stake, not %v%v",
key.String(), accCoins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom,
)
return true
}
accountIsInGenesis = true
return true
}
return false
},
)
if err != nil {
return err
}
if !accountIsInGenesis {
return fmt.Errorf("account %s in not in the app_state.accounts array of genesis.json", key)
}
return nil
}
type deliverTxfn func([]byte) abci.ResponseDeliverTx
// deliver a genesis transaction
func DeliverGenTxs(ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage,
stakingKeeper StakingKeeper, deliverTx deliverTxfn) []abci.ValidatorUpdate {
for _, genTx := range genTxs {
var tx auth.StdTx
cdc.MustUnmarshalJSON(genTx, &tx)
bz := cdc.MustMarshalBinaryLengthPrefixed(tx)
res := deliverTx(bz)
if !res.IsOK() {
panic(res.Log)
}
}
return stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
}

14
x/genutil/gentx_test.go Normal file
View File

@ -0,0 +1,14 @@
package genutil
import "testing"
func TestGenTx(t *testing.T) {
// 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
// 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
}

19
x/genutil/init.go Normal file
View File

@ -0,0 +1,19 @@
package genutil
import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// initialize accounts and deliver genesis transactions
func InitGenesis(ctx sdk.Context, cdc *codec.Codec, stakingKeeper StakingKeeper,
deliverTx deliverTxfn, genesisState GenesisState) []abci.ValidatorUpdate {
var validators []abci.ValidatorUpdate
if len(genesisState.GenTxs) > 0 {
validators = DeliverGenTxs(ctx, cdc, genesisState.GenTxs, stakingKeeper, deliverTx)
}
return validators
}

76
x/genutil/module.go Normal file
View File

@ -0,0 +1,76 @@
package genutil
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModuleGenesis = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// module name
const ModuleName = "genutil"
// app module basics object
type AppModuleBasic struct{}
// module name
func (AppModuleBasic) Name() string {
return ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return moduleCdc.MustMarshalJSON(GenesisState{})
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := moduleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
//___________________________
// app module
type AppModule struct {
AppModuleBasic
accountKeeper AccountKeeper
stakingKeeper StakingKeeper
deliverTx deliverTxfn
}
// NewAppModule creates a new AppModule object
func NewAppModule(accountKeeper AccountKeeper,
stakingKeeper StakingKeeper, deliverTx deliverTxfn) sdk.AppModule {
return sdk.NewGenesisOnlyAppModule(AppModule{
AppModuleBasic: AppModuleBasic{},
accountKeeper: accountKeeper,
stakingKeeper: stakingKeeper,
deliverTx: deliverTx,
})
}
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
moduleCdc.MustUnmarshalJSON(data, &genesisState)
return InitGenesis(ctx, moduleCdc, am.stakingKeeper, am.deliverTx, genesisState)
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
return nil
}

View File

@ -1,8 +1,7 @@
package init
package genutil
import (
"encoding/json"
"fmt"
"path/filepath"
"time"
@ -11,16 +10,14 @@ import (
"github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/p2p"
"github.com/tendermint/tendermint/privval"
"github.com/tendermint/tendermint/types"
tmtypes "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(genDoc *types.GenesisDoc, genFile string) error {
func ExportGenesisFile(genDoc *tmtypes.GenesisDoc, genFile string) error {
if err := genDoc.ValidateAndComplete(); err != nil {
return err
}
@ -31,11 +28,11 @@ func ExportGenesisFile(genDoc *types.GenesisDoc, genFile string) error {
// 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,
genFile, chainID string, validators []tmtypes.GenesisValidator,
appState json.RawMessage, genTime time.Time,
) error {
genDoc := types.GenesisDoc{
genDoc := tmtypes.GenesisDoc{
GenesisTime: genTime,
ChainID: chainID,
Validators: validators,
@ -50,9 +47,8 @@ func ExportGenesisFileWithTime(
}
// InitializeNodeValidatorFiles creates private validator and p2p configuration files.
func InitializeNodeValidatorFiles(
config *cfg.Config) (nodeID string, valPubKey crypto.PubKey, err error,
) {
func InitializeNodeValidatorFiles(config *cfg.Config,
) (nodeID string, valPubKey crypto.PubKey, err error) {
nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile())
if err != nil {
@ -76,14 +72,3 @@ func InitializeNodeValidatorFiles(
return nodeID, valPubKey, nil
}
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())
}

View File

@ -1,4 +1,4 @@
package init
package genutil
import (
"encoding/json"

View File

@ -5,8 +5,8 @@ import (
"fmt"
"time"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
const (
@ -68,12 +68,8 @@ func DefaultGenesisState() GenesisState {
// Checks whether 2 GenesisState structs are equivalent.
func (data GenesisState) Equal(data2 GenesisState) bool {
cdc := codec.New()
RegisterCodec(cdc)
b1 := cdc.MustMarshalBinaryBare(data)
b2 := cdc.MustMarshalBinaryBare(data2)
b1 := types.ModuleCdc.MustMarshalBinaryBare(data)
b2 := types.ModuleCdc.MustMarshalBinaryBare(data2)
return bytes.Equal(b1, b2)
}

113
x/gov/module.go Normal file
View File

@ -0,0 +1,113 @@
package gov
import (
"encoding/json"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/gov/types"
abci "github.com/tendermint/tendermint/abci/types"
)
var (
_ sdk.AppModule = AppModule{}
_ sdk.AppModuleBasic = AppModuleBasic{}
)
// app module basics object
type AppModuleBasic struct{}
var _ sdk.AppModuleBasic = AppModuleBasic{}
// module name
func (AppModuleBasic) Name() string {
return types.ModuleName
}
// register module codec
func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) {
RegisterCodec(cdc)
}
// default genesis state
func (AppModuleBasic) DefaultGenesis() json.RawMessage {
return types.ModuleCdc.MustMarshalJSON(DefaultGenesisState())
}
// module validate genesis
func (AppModuleBasic) ValidateGenesis(bz json.RawMessage) error {
var data GenesisState
err := types.ModuleCdc.UnmarshalJSON(bz, &data)
if err != nil {
return err
}
return ValidateGenesis(data)
}
//___________________________
// app module
type AppModule struct {
AppModuleBasic
keeper Keeper
}
// NewAppModule creates a new AppModule object
func NewAppModule(keeper Keeper) AppModule {
return AppModule{
AppModuleBasic: AppModuleBasic{},
keeper: keeper,
}
}
// module name
func (AppModule) Name() string {
return types.ModuleName
}
// register invariants
func (AppModule) RegisterInvariants(_ sdk.InvariantRouter) {}
// module message route name
func (AppModule) Route() string {
return RouterKey
}
// module handler
func (am AppModule) NewHandler() sdk.Handler {
return NewHandler(am.keeper)
}
// module querier route name
func (AppModule) QuerierRoute() string {
return QuerierRoute
}
// module querier
func (am AppModule) NewQuerierHandler() sdk.Querier {
return NewQuerier(am.keeper)
}
// module init-genesis
func (am AppModule) InitGenesis(ctx sdk.Context, data json.RawMessage) []abci.ValidatorUpdate {
var genesisState GenesisState
types.ModuleCdc.MustUnmarshalJSON(data, &genesisState)
InitGenesis(ctx, am.keeper, genesisState)
return []abci.ValidatorUpdate{}
}
// module export genesis
func (am AppModule) ExportGenesis(ctx sdk.Context) json.RawMessage {
gs := ExportGenesis(ctx, am.keeper)
return types.ModuleCdc.MustMarshalJSON(gs)
}
// module begin-block
func (AppModule) BeginBlock(_ sdk.Context, _ abci.RequestBeginBlock) sdk.Tags {
return sdk.EmptyTags()
}
// module end-block
func (am AppModule) EndBlock(ctx sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) {
tags := EndBlocker(ctx, am.keeper)
return []abci.ValidatorUpdate{}, tags
}

View File

@ -13,6 +13,14 @@ type DepositParams struct {
MaxDepositPeriod time.Duration `json:"max_deposit_period"` // Maximum period for Atom holders to deposit on a proposal. Initial value: 2 months
}
// NewDepositParams creates a new DepositParams object
func NewDepositParams(minDeposit sdk.Coins, maxDepositPeriod time.Duration) DepositParams {
return DepositParams{
MinDeposit: minDeposit,
MaxDepositPeriod: maxDepositPeriod,
}
}
func (dp DepositParams) String() string {
return fmt.Sprintf(`Deposit Params:
Min Deposit: %s
@ -31,6 +39,15 @@ type TallyParams struct {
Veto sdk.Dec `json:"veto"` // Minimum value of Veto votes to Total votes ratio for proposal to be vetoed. Initial value: 1/3
}
// NewTallyParams creates a new TallyParams object
func NewTallyParams(quorum, threshold, veto sdk.Dec) TallyParams {
return TallyParams{
Quorum: quorum,
Threshold: threshold,
Veto: veto,
}
}
func (tp TallyParams) String() string {
return fmt.Sprintf(`Tally Params:
Quorum: %s
@ -44,6 +61,13 @@ type VotingParams struct {
VotingPeriod time.Duration `json:"voting_period"` // Length of the voting period.
}
// NewVotingParams creates a new VotingParams object
func NewVotingParams(votingPeriod time.Duration) VotingParams {
return VotingParams{
VotingPeriod: votingPeriod,
}
}
func (vp VotingParams) String() string {
return fmt.Sprintf(`Voting Params:
Voting Period: %s`, vp.VotingPeriod)

View File

@ -12,10 +12,10 @@ import (
abci "github.com/tendermint/tendermint/abci/types"
"github.com/tendermint/tendermint/crypto"
"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/gov/types"
"github.com/cosmos/cosmos-sdk/x/mock"
"github.com/cosmos/cosmos-sdk/x/staking"
)
@ -51,7 +51,7 @@ func getMockApp(t *testing.T, numGenAccs int, genState GenesisState, genAccs []a
mApp.QueryRouter().AddRoute(QuerierRoute, NewQuerier(keeper))
mApp.SetEndBlocker(getEndBlocker(keeper))
mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, genState))
mApp.SetInitChainer(getInitChainer(mApp, keeper, sk, mApp.AccountKeeper, genState))
require.NoError(t, mApp.CompleteSetup(keyStaking, tKeyStaking, keyGov))
@ -84,7 +84,9 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker {
}
// gov and staking initchainer
func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper, genState GenesisState) sdk.InitChainer {
func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper,
accountKeeper staking.AccountKeeper, genState GenesisState) sdk.InitChainer {
return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
mapp.InitChainer(ctx, req)
@ -92,10 +94,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper, stakingKeeper staking.Keeper,
tokens := sdk.TokensFromTendermintPower(100000)
stakingGenesis.Pool.NotBondedTokens = tokens
validators, err := staking.InitGenesis(ctx, stakingKeeper, stakingGenesis)
if err != nil {
panic(err)
}
validators := staking.InitGenesis(ctx, stakingKeeper, accountKeeper, stakingGenesis)
if genState.IsEmpty() {
InitGenesis(ctx, keeper, DefaultGenesisState())
} else {
@ -156,9 +155,8 @@ func testProposal() Content {
// checks if two proposals are equal (note: slow, for tests only)
func ProposalEqual(proposalA Proposal, proposalB Proposal) bool {
cdc := codec.New()
RegisterCodec(cdc)
return bytes.Equal(cdc.MustMarshalBinaryBare(proposalA), cdc.MustMarshalBinaryBare(proposalB))
return bytes.Equal(types.ModuleCdc.MustMarshalBinaryBare(proposalA),
types.ModuleCdc.MustMarshalBinaryBare(proposalB))
}
var (

View File

@ -4,9 +4,8 @@ import (
"github.com/cosmos/cosmos-sdk/codec"
)
var (
msgCdc = codec.New()
)
// module codec
var ModuleCdc = codec.New()
// RegisterCodec registers all the necessary types and interfaces for
// governance.
@ -22,12 +21,12 @@ func RegisterCodec(cdc *codec.Codec) {
}
// RegisterProposalTypeCodec registers an external proposal content type defined
// in another module for the internal msgCdc. This allows the MsgSubmitProposal
// in another module for the internal ModuleCdc. This allows the MsgSubmitProposal
// to be correctly Amino encoded and decoded.
func RegisterProposalTypeCodec(o interface{}, name string) {
msgCdc.RegisterConcrete(o, name, nil)
ModuleCdc.RegisterConcrete(o, name, nil)
}
func init() {
RegisterCodec(msgCdc)
RegisterCodec(ModuleCdc)
}

Some files were not shown because too many files have changed in this diff Show More