From 3fe5869148f085139207c2d0bb64f694a6141539 Mon Sep 17 00:00:00 2001 From: frog power 4000 Date: Thu, 16 May 2019 11:25:32 -0400 Subject: [PATCH] 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 --- .pending/breaking/gaia/4159-use-module-patt | 1 + .pending/breaking/sdk/4159-create-the-defa | 1 + Makefile | 4 +- baseapp/baseapp.go | 25 +- baseapp/queryrouter.go | 10 +- baseapp/router.go | 10 +- cmd/gaia/app/app.go | 397 +++++------------ cmd/gaia/app/app_test.go | 57 +-- cmd/gaia/app/export.go | 35 +- cmd/gaia/app/genesis.go | 416 +----------------- cmd/gaia/app/genesis_test.go | 188 -------- cmd/gaia/app/invariants.go | 31 -- cmd/gaia/app/sim_test.go | 125 +++--- cmd/gaia/app/test_util.go | 22 + cmd/gaia/cli_test/README.md | 2 +- cmd/gaia/cli_test/cli_test.go | 28 +- cmd/gaia/cmd/gaiacli/main.go | 6 +- cmd/gaia/cmd/gaiad/main.go | 17 +- cmd/gaia/{init => cmd/gaiad}/testnet.go | 176 ++++---- cmd/gaia/cmd/gaiadebug/hack.go | 175 +------- cmd/gaia/contrib/runsim/main.go | 60 ++- cmd/gaia/init/collect.go | 145 ------ cmd/gaia/init/genesis_accts_test.go | 101 ----- cmd/gaia/lcd_test/helpers_test.go | 110 +++-- cmd/gaia/lcd_test/lcd_test.go | 10 +- cmd/gaia/sims.mk | 4 +- cmd/gaia/testnets/README.md | 7 - cmd/gaia/testnets/STATUS.md | 132 ------ types/address.go | 7 +- types/invariant.go | 5 + types/module.go | 281 ++++++++++++ types/module_clients.go | 11 - types/module_test.go | 16 + types/router.go | 13 + x/auth/account.go | 43 ++ x/auth/ante.go | 2 +- x/auth/codec.go | 6 +- .../genaccounts/client/cli}/genesis_accts.go | 93 ++-- x/auth/genaccounts/codec.go | 14 + x/auth/genaccounts/doc.go | 9 + x/auth/genaccounts/expected.go | 13 + x/auth/genaccounts/export.go | 25 ++ x/auth/genaccounts/genesis_account.go | 125 ++++++ x/auth/genaccounts/genesis_account_test.go | 75 ++++ x/auth/genaccounts/genesis_state.go | 85 ++++ x/auth/genaccounts/genesis_state_test.go | 85 ++++ x/auth/genaccounts/init.go | 20 + x/auth/genaccounts/module.go | 89 ++++ x/auth/genesis.go | 2 +- x/auth/module.go | 111 +++++ x/auth/params.go | 19 +- x/auth/simulation/fake.go | 2 +- x/auth/stdtx.go | 4 +- x/bank/bench_test.go | 2 +- x/bank/client/rest/sendtx.go | 4 +- x/bank/codec.go | 4 +- x/bank/errors.go | 2 +- x/bank/expected_keepers.go | 10 - x/bank/invariants.go | 4 +- x/bank/module.go | 115 +++++ x/bank/msgs.go | 6 +- x/bank/msgs_test.go | 4 +- x/bank/params.go | 2 +- x/crisis/abci_app.go | 16 + x/crisis/codec.go | 4 +- x/crisis/handler.go | 7 +- x/crisis/handler_test.go | 2 +- x/crisis/keeper.go | 34 +- x/crisis/module.go | 117 +++++ x/crisis/msg.go | 2 +- x/distribution/abci_app.go | 1 + x/distribution/alias.go | 2 + x/distribution/keeper/invariants.go | 30 +- x/distribution/module.go | 111 +++++ x/distribution/types/codec.go | 4 +- x/distribution/types/expected_keepers.go | 5 - x/distribution/types/msg.go | 6 +- x/genutil/client/cli/collect.go | 69 +++ .../init => x/genutil/client/cli}/gentx.go | 105 ++--- .../genutil/client/cli}/gentx_test.go | 15 +- .../init => x/genutil/client/cli}/init.go | 38 +- .../genutil/client/cli}/init_test.go | 17 +- .../genutil/client/cli}/validate_genesis.go | 28 +- x/genutil/codec.go | 23 + x/genutil/collect.go | 205 +++++++++ x/genutil/doc.go | 10 + x/genutil/expected.go | 32 ++ x/genutil/genesis_state.go | 106 +++++ x/genutil/genesis_state_test.go | 46 ++ x/genutil/gentx.go | 94 ++++ x/genutil/gentx_test.go | 14 + x/genutil/init.go | 19 + x/genutil/module.go | 76 ++++ {cmd/gaia/init => x/genutil}/utils.go | 29 +- {cmd/gaia/init => x/genutil}/utils_test.go | 2 +- x/gov/genesis.go | 10 +- x/gov/module.go | 113 +++++ x/gov/params.go | 24 + x/gov/test_common.go | 18 +- x/gov/types/codec.go | 11 +- x/gov/types/errors.go | 1 - x/gov/types/msgs.go | 6 +- x/mint/abci_app.go | 2 +- x/mint/codec.go | 14 + x/mint/keeper.go | 13 +- x/mint/module.go | 109 +++++ x/mint/test_common.go | 19 +- x/params/module.go | 34 ++ x/slashing/app_test.go | 11 +- x/slashing/codec.go | 9 +- x/slashing/expected_keepers.go | 17 + x/slashing/genesis.go | 22 +- x/slashing/keys.go | 3 - x/slashing/module.go | 116 +++++ x/slashing/msg.go | 5 +- x/slashing/msg_test.go | 6 +- x/slashing/params.go | 15 + x/slashing/querier.go | 27 +- x/slashing/querier_test.go | 5 +- x/slashing/test_common.go | 5 +- x/staking/alias.go | 6 + x/staking/app_test.go | 11 +- x/staking/genesis.go | 18 +- x/staking/genesis_test.go | 10 +- x/staking/handler.go | 4 +- x/staking/handler_test.go | 18 +- x/staking/keeper/invariants.go | 16 +- x/staking/module.go | 120 +++++ x/staking/querier/querier.go | 115 +++-- x/staking/querier/querier_test.go | 56 +-- x/staking/types/codec.go | 6 +- x/staking/types/delegation.go | 8 +- x/staking/types/expected_keepers.go | 11 +- x/staking/types/hooks.go | 64 +++ x/staking/types/msg.go | 10 +- x/staking/types/params.go | 4 +- x/staking/types/pool.go | 4 +- 137 files changed, 3661 insertions(+), 2307 deletions(-) create mode 100644 .pending/breaking/gaia/4159-use-module-patt create mode 100644 .pending/breaking/sdk/4159-create-the-defa delete mode 100644 cmd/gaia/app/genesis_test.go delete mode 100644 cmd/gaia/app/invariants.go create mode 100644 cmd/gaia/app/test_util.go rename cmd/gaia/{init => cmd/gaiad}/testnet.go (68%) delete mode 100644 cmd/gaia/init/collect.go delete mode 100644 cmd/gaia/init/genesis_accts_test.go delete mode 100644 cmd/gaia/testnets/README.md delete mode 100644 cmd/gaia/testnets/STATUS.md create mode 100644 types/module.go delete mode 100644 types/module_clients.go create mode 100644 types/module_test.go create mode 100644 types/router.go rename {cmd/gaia/init => x/auth/genaccounts/client/cli}/genesis_accts.go (51%) create mode 100644 x/auth/genaccounts/codec.go create mode 100644 x/auth/genaccounts/doc.go create mode 100644 x/auth/genaccounts/expected.go create mode 100644 x/auth/genaccounts/export.go create mode 100644 x/auth/genaccounts/genesis_account.go create mode 100644 x/auth/genaccounts/genesis_account_test.go create mode 100644 x/auth/genaccounts/genesis_state.go create mode 100644 x/auth/genaccounts/genesis_state_test.go create mode 100644 x/auth/genaccounts/init.go create mode 100644 x/auth/genaccounts/module.go create mode 100644 x/auth/module.go delete mode 100644 x/bank/expected_keepers.go create mode 100644 x/bank/module.go create mode 100644 x/crisis/abci_app.go create mode 100644 x/crisis/module.go create mode 100644 x/distribution/module.go create mode 100644 x/genutil/client/cli/collect.go rename {cmd/gaia/init => x/genutil/client/cli}/gentx.go (85%) rename {cmd/gaia/init => x/genutil/client/cli}/gentx_test.go (90%) rename {cmd/gaia/init => x/genutil/client/cli}/init.go (74%) rename {cmd/gaia/init => x/genutil/client/cli}/init_test.go (88%) rename {cmd/gaia/init => x/genutil/client/cli}/validate_genesis.go (53%) create mode 100644 x/genutil/codec.go create mode 100644 x/genutil/collect.go create mode 100644 x/genutil/doc.go create mode 100644 x/genutil/expected.go create mode 100644 x/genutil/genesis_state.go create mode 100644 x/genutil/genesis_state_test.go create mode 100644 x/genutil/gentx.go create mode 100644 x/genutil/gentx_test.go create mode 100644 x/genutil/init.go create mode 100644 x/genutil/module.go rename {cmd/gaia/init => x/genutil}/utils.go (69%) rename {cmd/gaia/init => x/genutil}/utils_test.go (96%) create mode 100644 x/gov/module.go create mode 100644 x/mint/codec.go create mode 100644 x/mint/module.go create mode 100644 x/params/module.go create mode 100644 x/slashing/expected_keepers.go create mode 100644 x/slashing/module.go create mode 100644 x/staking/module.go create mode 100644 x/staking/types/hooks.go diff --git a/.pending/breaking/gaia/4159-use-module-patt b/.pending/breaking/gaia/4159-use-module-patt new file mode 100644 index 000000000000..1a3d4398dab5 --- /dev/null +++ b/.pending/breaking/gaia/4159-use-module-patt @@ -0,0 +1 @@ +#4159 use module pattern and module manager for initialization \ No newline at end of file diff --git a/.pending/breaking/sdk/4159-create-the-defa b/.pending/breaking/sdk/4159-create-the-defa new file mode 100644 index 000000000000..611b5084275a --- /dev/null +++ b/.pending/breaking/sdk/4159-create-the-defa @@ -0,0 +1 @@ +#4159 create the default module patterns and module manager \ No newline at end of file diff --git a/Makefile b/Makefile index 302e9bccb2ee..ef68d42b0b7b 100644 --- a/Makefile +++ b/Makefile @@ -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..." diff --git a/baseapp/baseapp.go b/baseapp/baseapp.go index 0ad9f2309d4d..8bd81f6eba22 100644 --- a/baseapp/baseapp.go +++ b/baseapp/baseapp.go @@ -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 diff --git a/baseapp/queryrouter.go b/baseapp/queryrouter.go index 178646b7ebb5..9e38674def6d 100644 --- a/baseapp/queryrouter.go +++ b/baseapp/queryrouter.go @@ -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") } diff --git a/baseapp/router.go b/baseapp/router.go index 5e829d73cfa6..9eebce23941c 100644 --- a/baseapp/router.go +++ b/baseapp/router.go @@ -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") } diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 5c732aff81f1..1cd5e797dbc8 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -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,16 +26,46 @@ import ( "github.com/tendermint/tendermint/libs/log" ) -const ( - appName = "GaiaApp" -) +const appName = "GaiaApp" -// default home directories for expected binaries var ( - DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli") + // 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 ) +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 { *bam.BaseApp @@ -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) - - // 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, - ) - + authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace) + bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace) + stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace) + mintSubspace := app.paramsKeeper.Subspace(mint.DefaultParamspace) + distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace) + slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace) + govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace) + crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace) + + // add keepers + app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.keyAccount, authSubspace, auth.ProtoBaseAccount) + app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace) + app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection) + stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper, + stakingSubspace, staking.DefaultCodespace) + app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.feeCollectionKeeper) + app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, app.bankKeeper, &stakingKeeper, + app.feeCollectionKeeper, distr.DefaultCodespace) + app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, &stakingKeeper, + slashingSubspace, slashing.DefaultCodespace) + app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.distrKeeper, + app.bankKeeper, app.feeCollectionKeeper) + + // register the proposal types govRouter := gov.NewRouter() govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler). AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper)) - - 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) - - // register message routes - app.Router(). - AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)). - AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)). - AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)). - AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)). - AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)). - AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper)) - - app.QueryRouter(). - AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)). - AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)). - AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)). - AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)). - AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc)). - AddRoute(mint.QuerierRoute, mint.NewQuerier(app.mintKeeper)) + // During begin block slashing happens after distr.BeginBlocker so that + // there is nothing left over in the validator fee pool, so as to keep the + // CanWithdrawInvariant invariant. + app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName) + + app.mm.SetOrderEndBlockers(gov.ModuleName, staking.ModuleName) + + // genutils must occur after staking so that pools are properly + // initialized with tokens from genesis accounts. + app.mm.SetOrderInitGenesis(genaccounts.ModuleName, distr.ModuleName, + staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName, + gov.ModuleName, mint.ModuleName, crisis.ModuleName, genutil.ModuleName) + + app.mm.RegisterInvariants(&app.crisisKeeper) + app.mm.RegisterRoutes(app.Router(), app.QueryRouter()) + + // initialize stores + app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, + app.keyDistr, app.keySlashing, app.keyGov, app.keyFeeCollection, + app.keyParams, app.tkeyParams, app.tkeyStaking, app.tkeyDistr) // initialize BaseApp - app.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) -} diff --git a/cmd/gaia/app/app_test.go b/cmd/gaia/app/app_test.go index 95fa02119d68..1e880cd94449 100644 --- a/cmd/gaia/app/app_test.go +++ b/cmd/gaia/app/app_test.go @@ -4,62 +4,41 @@ 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) - } +func TestGaiadExport(t *testing.T) { + db := db.NewMemDB() + gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + setGenesis(gapp) - genesisState := NewGenesisState( - genaccs, - auth.DefaultGenesisState(), - bank.DefaultGenesisState(), - staking.DefaultGenesisState(), - mint.DefaultGenesisState(), - distr.DefaultGenesisState(), - gov.DefaultGenesisState(), - crisis.DefaultGenesisState(), - slashing.DefaultGenesisState(), - ) + // Making a new app object with the db, so that initchain hasn't been called + newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) + _, _, err := newGapp.ExportAppStateAndValidators(false, []string{}) + require.NoError(t, err, "ExportAppStateAndValidators should not have an error") +} + +func setGenesis(gapp *GaiaApp) error { + genesisState := NewDefaultGenesisState() 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.InitChain( + abci.RequestInitChain{ + Validators: []abci.ValidatorUpdate{}, + AppStateBytes: stateBytes, + }, + ) gapp.Commit() - return nil } - -func TestGaiadExport(t *testing.T) { - db := db.NewMemDB() - gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) - setGenesis(gapp) - - // Making a new app object with the db, so that initchain hasn't been called - newGapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0) - _, _, err := newGapp.ExportAppStateAndValidators(false, []string{}) - require.NoError(t, err, "ExportAppStateAndValidators should not have an error") -} diff --git a/cmd/gaia/app/export.go b/cmd/gaia/app/export.go index 2cb110bf8926..b9fc3366f2cd 100644 --- a/cmd/gaia/app/export.go +++ b/cmd/gaia/app/export.go @@ -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. */ diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 997cd131c751..d4e99dd4f973 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -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() } diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go deleted file mode 100644 index 300f4afcdec6..000000000000 --- a/cmd/gaia/app/genesis_test.go +++ /dev/null @@ -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") -} diff --git a/cmd/gaia/app/invariants.go b/cmd/gaia/app/invariants.go deleted file mode 100644 index 899d6bdbac22..000000000000 --- a/cmd/gaia/app/invariants.go +++ /dev/null @@ -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()) -} diff --git a/cmd/gaia/app/sim_test.go b/cmd/gaia/app/sim_test.go index eab5e95cd315..2beb339668f7 100644 --- a/cmd/gaia/app/sim_test.go +++ b/cmd/gaia/app/sim_test.go @@ -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{}) diff --git a/cmd/gaia/app/test_util.go b/cmd/gaia/app/test_util.go new file mode 100644 index 000000000000..6f89efab49c4 --- /dev/null +++ b/cmd/gaia/app/test_util.go @@ -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 +} diff --git a/cmd/gaia/cli_test/README.md b/cmd/gaia/cli_test/README.md index 37fd41ce7eff..857150ca574f 100644 --- a/cmd/gaia/cli_test/README.md +++ b/cmd/gaia/cli_test/README.md @@ -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 ``` diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 722fb643ea91..0aafbbe61c03 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -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() diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index af6f64054bb5..b9a5543f4f57 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -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", diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index d9f319f302bb..c2aef45b3f65 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -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) } } diff --git a/cmd/gaia/init/testnet.go b/cmd/gaia/cmd/gaiad/testnet.go similarity index 68% rename from cmd/gaia/init/testnet.go rename to cmd/gaia/cmd/gaiad/testnet.go index 56b0f2f86cf9..eb172897e18d 100644 --- a/cmd/gaia/init/testnet.go +++ b/cmd/gaia/cmd/gaiad/testnet.go @@ -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 -} diff --git a/cmd/gaia/cmd/gaiadebug/hack.go b/cmd/gaia/cmd/gaiadebug/hack.go index 8f42bbf61a53..7e33bb8cfef7 100644 --- a/cmd/gaia/cmd/gaiadebug/hack.go +++ b/cmd/gaia/cmd/gaiadebug/hack.go @@ -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, - } -} diff --git a/cmd/gaia/contrib/runsim/main.go b/cmd/gaia/contrib/runsim/main.go index ef6091593787..aa64ac424c4c 100644 --- a/cmd/gaia/contrib/runsim/main.go +++ b/cmd/gaia/contrib/runsim/main.go @@ -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) { diff --git a/cmd/gaia/init/collect.go b/cmd/gaia/init/collect.go deleted file mode 100644 index 0ad58252d9de..000000000000 --- a/cmd/gaia/init/collect.go +++ /dev/null @@ -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, - } -} diff --git a/cmd/gaia/init/genesis_accts_test.go b/cmd/gaia/init/genesis_accts_test.go deleted file mode 100644 index d0af91ae83a5..000000000000 --- a/cmd/gaia/init/genesis_accts_test.go +++ /dev/null @@ -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) - }) - } -} diff --git a/cmd/gaia/lcd_test/helpers_test.go b/cmd/gaia/lcd_test/helpers_test.go index 4573dcaf45d3..0ff227d0c6fb 100644 --- a/cmd/gaia/lcd_test/helpers_test.go +++ b/cmd/gaia/lcd_test/helpers_test.go @@ -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, tx) - genTxs = append(genTxs, txBytes) 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) diff --git a/cmd/gaia/lcd_test/lcd_test.go b/cmd/gaia/lcd_test/lcd_test.go index d7693cf8c70f..8a0ff0bfa87a 100644 --- a/cmd/gaia/lcd_test/lcd_test.go +++ b/cmd/gaia/lcd_test/lcd_test.go @@ -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) diff --git a/cmd/gaia/sims.mk b/cmd/gaia/sims.mk index 6dee8236a39f..918b8c93f602 100644 --- a/cmd/gaia/sims.mk +++ b/cmd/gaia/sims.mk @@ -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..." diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md deleted file mode 100644 index e64db9f7dd7e..000000000000 --- a/cmd/gaia/testnets/README.md +++ /dev/null @@ -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). diff --git a/cmd/gaia/testnets/STATUS.md b/cmd/gaia/testnets/STATUS.md deleted file mode 100644 index 4db4297845d6..000000000000 --- a/cmd/gaia/testnets/STATUS.md +++ /dev/null @@ -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 diff --git a/types/address.go b/types/address.go index 5b73ca47df26..08ff7916f0c6 100644 --- a/types/address.go +++ b/types/address.go @@ -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 } diff --git a/types/invariant.go b/types/invariant.go index aa8aca566507..01209d178488 100644 --- a/types/invariant.go +++ b/types/invariant.go @@ -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) +} diff --git a/types/module.go b/types/module.go new file mode 100644 index 000000000000..ff1743a55d9f --- /dev/null +++ b/types/module.go @@ -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 diff --git a/types/module_clients.go b/types/module_clients.go deleted file mode 100644 index 3b3a9d9a5d37..000000000000 --- a/types/module_clients.go +++ /dev/null @@ -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 -} diff --git a/types/module_test.go b/types/module_test.go new file mode 100644 index 000000000000..939d70bfb334 --- /dev/null +++ b/types/module_test.go @@ -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) +} diff --git a/types/router.go b/types/router.go new file mode 100644 index 000000000000..7b45918c3cc6 --- /dev/null +++ b/types/router.go @@ -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 +} diff --git a/x/auth/account.go b/x/auth/account.go index 0c0e71a48c40..99132d3ba26a 100644 --- a/x/auth/account.go +++ b/x/auth/account.go @@ -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{ diff --git a/x/auth/ante.go b/x/auth/ante.go index 762ed310ffe0..57b566d04f7d 100644 --- a/x/auth/ante.go +++ b/x/auth/ante.go @@ -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 diff --git a/x/auth/codec.go b/x/auth/codec.go index 0d7694300f1f..9b7b35204347 100644 --- a/x/auth/codec.go +++ b/x/auth/codec.go @@ -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) } diff --git a/cmd/gaia/init/genesis_accts.go b/x/auth/genaccounts/client/cli/genesis_accts.go similarity index 51% rename from cmd/gaia/init/genesis_accts.go rename to x/auth/genaccounts/client/cli/genesis_accts.go index ca568227adb1..7ac0759b5662 100644 --- a/cmd/gaia/init/genesis_accts.go +++ b/x/auth/genaccounts/client/cli/genesis_accts.go @@ -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 } - genFile := config.GenesisFile() - if !common.FileExists(genFile) { - return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile) + genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd) + if err := genAcc.Validate(); err != nil { + return err } - genDoc, err := tmtypes.GenesisDocFromFile(genFile) + // retrieve the app state + genFile := config.GenesisFile() + 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 -} diff --git a/x/auth/genaccounts/codec.go b/x/auth/genaccounts/codec.go new file mode 100644 index 000000000000..ccdc8b19e553 --- /dev/null +++ b/x/auth/genaccounts/codec.go @@ -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() +} diff --git a/x/auth/genaccounts/doc.go b/x/auth/genaccounts/doc.go new file mode 100644 index 000000000000..60c6e3c7307a --- /dev/null +++ b/x/auth/genaccounts/doc.go @@ -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 diff --git a/x/auth/genaccounts/expected.go b/x/auth/genaccounts/expected.go new file mode 100644 index 000000000000..3f7db1a6a4bb --- /dev/null +++ b/x/auth/genaccounts/expected.go @@ -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)) +} diff --git a/x/auth/genaccounts/export.go b/x/auth/genaccounts/export.go new file mode 100644 index 000000000000..f6445c9c693b --- /dev/null +++ b/x/auth/genaccounts/export.go @@ -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) +} diff --git a/x/auth/genaccounts/genesis_account.go b/x/auth/genaccounts/genesis_account.go new file mode 100644 index 000000000000..d0801b2f61c6 --- /dev/null +++ b/x/auth/genaccounts/genesis_account.go @@ -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 +} diff --git a/x/auth/genaccounts/genesis_account_test.go b/x/auth/genaccounts/genesis_account_test.go new file mode 100644 index 000000000000..dcd823199fe3 --- /dev/null +++ b/x/auth/genaccounts/genesis_account_test.go @@ -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)) +} diff --git a/x/auth/genaccounts/genesis_state.go b/x/auth/genaccounts/genesis_state.go new file mode 100644 index 000000000000..5596cd00c30e --- /dev/null +++ b/x/auth/genaccounts/genesis_state.go @@ -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 +} diff --git a/x/auth/genaccounts/genesis_state_test.go b/x/auth/genaccounts/genesis_state_test.go new file mode 100644 index 000000000000..a9ebf05ee512 --- /dev/null +++ b/x/auth/genaccounts/genesis_state_test.go @@ -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) +} diff --git a/x/auth/genaccounts/init.go b/x/auth/genaccounts/init.go new file mode 100644 index 000000000000..b40e6f978acc --- /dev/null +++ b/x/auth/genaccounts/init.go @@ -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) + } +} diff --git a/x/auth/genaccounts/module.go b/x/auth/genaccounts/module.go new file mode 100644 index 000000000000..2ffc0c4a51f0 --- /dev/null +++ b/x/auth/genaccounts/module.go @@ -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) +} diff --git a/x/auth/genesis.go b/x/auth/genesis.go index 7f94415dfa73..885234f61c71 100644 --- a/x/auth/genesis.go +++ b/x/auth/genesis.go @@ -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, } } diff --git a/x/auth/module.go b/x/auth/module.go new file mode 100644 index 000000000000..f7381e21f335 --- /dev/null +++ b/x/auth/module.go @@ -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() +} diff --git a/x/auth/params.go b/x/auth/params.go index e5a965bb9cf4..971d76e25fb2 100644 --- a/x/auth/params.go +++ b/x/auth/params.go @@ -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) } diff --git a/x/auth/simulation/fake.go b/x/auth/simulation/fake.go index 7849bd807848..b1b76f2dc969 100644 --- a/x/auth/simulation/fake.go +++ b/x/auth/simulation/fake.go @@ -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 diff --git a/x/auth/stdtx.go b/x/auth/stdtx.go index 5f11a2f3e7f7..20efaae424f2 100644 --- a/x/auth/stdtx.go +++ b/x/auth/stdtx.go @@ -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()), diff --git a/x/bank/bench_test.go b/x/bank/bench_test.go index 95918110c4de..8425f0f93008 100644 --- a/x/bank/bench_test.go +++ b/x/bank/bench_test.go @@ -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() diff --git a/x/bank/client/rest/sendtx.go b/x/bank/client/rest/sendtx.go index 552aa2d8ce03..3e634e551f61 100644 --- a/x/bank/client/rest/sendtx.go +++ b/x/bank/client/rest/sendtx.go @@ -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. diff --git a/x/bank/codec.go b/x/bank/codec.go index 58c59d5f6ac9..2c2cc32a3387 100644 --- a/x/bank/codec.go +++ b/x/bank/codec.go @@ -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) } diff --git a/x/bank/errors.go b/x/bank/errors.go index 7c5feaf4a848..5b579fabb28d 100644 --- a/x/bank/errors.go +++ b/x/bank/errors.go @@ -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 diff --git a/x/bank/expected_keepers.go b/x/bank/expected_keepers.go deleted file mode 100644 index 6d256d926d6e..000000000000 --- a/x/bank/expected_keepers.go +++ /dev/null @@ -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) -} diff --git a/x/bank/invariants.go b/x/bank/invariants.go index 4ca4c3d9a1df..a0e30db98372 100644 --- a/x/bank/invariants.go +++ b/x/bank/invariants.go @@ -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)) } diff --git a/x/bank/module.go b/x/bank/module.go new file mode 100644 index 000000000000..53be045fcdb2 --- /dev/null +++ b/x/bank/module.go @@ -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() +} diff --git a/x/bank/msgs.go b/x/bank/msgs.go index c9b4f554482b..2953488673f2 100644 --- a/x/bank/msgs.go +++ b/x/bank/msgs.go @@ -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. diff --git a/x/bank/msgs_test.go b/x/bank/msgs_test.go index 521e81761ba8..3b7813e0d508 100644 --- a/x/bank/msgs_test.go +++ b/x/bank/msgs_test.go @@ -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") } diff --git a/x/bank/params.go b/x/bank/params.go index b381e4e847e5..01602e52cceb 100644 --- a/x/bank/params.go +++ b/x/bank/params.go @@ -6,7 +6,7 @@ import ( const ( // DefaultParamspace for params keeper - DefaultParamspace = "bank" + DefaultParamspace = ModuleName // DefaultSendEnabled enabled DefaultSendEnabled = true ) diff --git a/x/crisis/abci_app.go b/x/crisis/abci_app.go new file mode 100644 index 000000000000..86dc23adf5cd --- /dev/null +++ b/x/crisis/abci_app.go @@ -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) +} diff --git a/x/crisis/codec.go b/x/crisis/codec.go index d5217676444f..9d35754139cf 100644 --- a/x/crisis/codec.go +++ b/x/crisis/codec.go @@ -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() } diff --git a/x/crisis/handler.go b/x/crisis/handler.go index da30d976aaa1..475ca8535c99 100644 --- a/x/crisis/handler.go +++ b/x/crisis/handler.go @@ -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 { diff --git a/x/crisis/handler_test.go b/x/crisis/handler_test.go index acc920e4a1ea..9632ebc52d7c 100644 --- a/x/crisis/handler_test.go +++ b/x/crisis/handler_test.go @@ -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) diff --git a/x/crisis/keeper.go b/x/crisis/keeper.go index 95c7cf09c1a0..5a25934d3b1e 100644 --- a/x/crisis/keeper.go +++ b/x/crisis/keeper.go @@ -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 diff --git a/x/crisis/module.go b/x/crisis/module.go new file mode 100644 index 000000000000..7bb64f10714c --- /dev/null +++ b/x/crisis/module.go @@ -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() +} diff --git a/x/crisis/msg.go b/x/crisis/msg.go index d6289d2b4181..f63623149410 100644 --- a/x/crisis/msg.go +++ b/x/crisis/msg.go @@ -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) } diff --git a/x/distribution/abci_app.go b/x/distribution/abci_app.go index 0a2ef5627a90..237145c2e3f3 100644 --- a/x/distribution/abci_app.go +++ b/x/distribution/abci_app.go @@ -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 diff --git a/x/distribution/alias.go b/x/distribution/alias.go index 57038618bcc6..c10a760d1c66 100644 --- a/x/distribution/alias.go +++ b/x/distribution/alias.go @@ -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 diff --git a/x/distribution/keeper/invariants.go b/x/distribution/keeper/invariants.go index 907ff02644b2..a224ae1c15ce 100644 --- a/x/distribution/keeper/invariants.go +++ b/x/distribution/keeper/invariants.go @@ -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) { diff --git a/x/distribution/module.go b/x/distribution/module.go new file mode 100644 index 000000000000..03e7a5df1aa3 --- /dev/null +++ b/x/distribution/module.go @@ -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() +} diff --git a/x/distribution/types/codec.go b/x/distribution/types/codec.go index 30ae415720f0..b4f509bde953 100644 --- a/x/distribution/types/codec.go +++ b/x/distribution/types/codec.go @@ -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() } diff --git a/x/distribution/types/expected_keepers.go b/x/distribution/types/expected_keepers.go index 9d2c6a4e53c4..6bf8eaa0a8c1 100644 --- a/x/distribution/types/expected_keepers.go +++ b/x/distribution/types/expected_keepers.go @@ -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) -} diff --git a/x/distribution/types/msg.go b/x/distribution/types/msg.go index 4e39aaedb2d7..ca96357be52f 100644 --- a/x/distribution/types/msg.go +++ b/x/distribution/types/msg.go @@ -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) } diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go new file mode 100644 index 000000000000..7484206dd8af --- /dev/null +++ b/x/genutil/client/cli/collect.go @@ -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 diff --git a/cmd/gaia/init/gentx.go b/x/genutil/client/cli/gentx.go similarity index 85% rename from cmd/gaia/init/gentx.go rename to x/genutil/client/cli/gentx.go index 67865426da65..2cdac84778de 100644 --- a/cmd/gaia/init/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -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 diff --git a/cmd/gaia/init/gentx_test.go b/x/genutil/client/cli/gentx_test.go similarity index 90% rename from cmd/gaia/init/gentx_test.go rename to x/genutil/client/cli/gentx_test.go index b83088b14011..337fe2023216 100644 --- a/cmd/gaia/init/gentx_test.go +++ b/x/genutil/client/cli/gentx_test.go @@ -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) }) diff --git a/cmd/gaia/init/init.go b/x/genutil/client/cli/init.go similarity index 74% rename from cmd/gaia/init/init.go rename to x/genutil/client/cli/init.go index b539c8632392..dc89e96f8b51 100644 --- a/cmd/gaia/init/init.go +++ b/x/genutil/client/cli/init.go @@ -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 } diff --git a/cmd/gaia/init/init_test.go b/x/genutil/client/cli/init_test.go similarity index 88% rename from cmd/gaia/init/init_test.go rename to x/genutil/client/cli/init_test.go index abfc343d1771..5d5aea8a0dd4 100644 --- a/cmd/gaia/init/init_test.go +++ b/x/genutil/client/cli/init_test.go @@ -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())) diff --git a/cmd/gaia/init/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go similarity index 53% rename from cmd/gaia/init/validate_genesis.go rename to x/genutil/client/cli/validate_genesis.go index 0f7303691e09..7609db8cc680 100644 --- a/cmd/gaia/init/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -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 }, diff --git a/x/genutil/codec.go b/x/genutil/codec.go new file mode 100644 index 000000000000..80a3f6951ce4 --- /dev/null +++ b/x/genutil/codec.go @@ -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() +} diff --git a/x/genutil/collect.go b/x/genutil/collect.go new file mode 100644 index 000000000000..ab646a3c21d5 --- /dev/null +++ b/x/genutil/collect.go @@ -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 +} diff --git a/x/genutil/doc.go b/x/genutil/doc.go new file mode 100644 index 000000000000..bccc82a1af00 --- /dev/null +++ b/x/genutil/doc.go @@ -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 diff --git a/x/genutil/expected.go b/x/genutil/expected.go new file mode 100644 index 000000000000..9fd28cf8d894 --- /dev/null +++ b/x/genutil/expected.go @@ -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), + ) +} diff --git a/x/genutil/genesis_state.go b/x/genutil/genesis_state.go new file mode 100644 index 000000000000..b5f2d36dbf3a --- /dev/null +++ b/x/genutil/genesis_state.go @@ -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 +} diff --git a/x/genutil/genesis_state_test.go b/x/genutil/genesis_state_test.go new file mode 100644 index 000000000000..87659756a939 --- /dev/null +++ b/x/genutil/genesis_state_test.go @@ -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) +} diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go new file mode 100644 index 000000000000..31a8b53d69b1 --- /dev/null +++ b/x/genutil/gentx.go @@ -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) +} diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go new file mode 100644 index 000000000000..ea03ce733ce9 --- /dev/null +++ b/x/genutil/gentx_test.go @@ -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 +} diff --git a/x/genutil/init.go b/x/genutil/init.go new file mode 100644 index 000000000000..786838719f40 --- /dev/null +++ b/x/genutil/init.go @@ -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 +} diff --git a/x/genutil/module.go b/x/genutil/module.go new file mode 100644 index 000000000000..ba69d4f54b7e --- /dev/null +++ b/x/genutil/module.go @@ -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 +} diff --git a/cmd/gaia/init/utils.go b/x/genutil/utils.go similarity index 69% rename from cmd/gaia/init/utils.go rename to x/genutil/utils.go index ce43781c71c9..65f27a839a03 100644 --- a/cmd/gaia/init/utils.go +++ b/x/genutil/utils.go @@ -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()) -} diff --git a/cmd/gaia/init/utils_test.go b/x/genutil/utils_test.go similarity index 96% rename from cmd/gaia/init/utils_test.go rename to x/genutil/utils_test.go index 87dfabd4d6ef..cb04c8f866b1 100644 --- a/cmd/gaia/init/utils_test.go +++ b/x/genutil/utils_test.go @@ -1,4 +1,4 @@ -package init +package genutil import ( "encoding/json" diff --git a/x/gov/genesis.go b/x/gov/genesis.go index 257c648ef9c1..841c125bd6c6 100644 --- a/x/gov/genesis.go +++ b/x/gov/genesis.go @@ -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) } diff --git a/x/gov/module.go b/x/gov/module.go new file mode 100644 index 000000000000..7db8824a0db5 --- /dev/null +++ b/x/gov/module.go @@ -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 +} diff --git a/x/gov/params.go b/x/gov/params.go index 112e92186206..c15d35614f3e 100644 --- a/x/gov/params.go +++ b/x/gov/params.go @@ -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) diff --git a/x/gov/test_common.go b/x/gov/test_common.go index 955aacdba807..2953fd98d4f6 100644 --- a/x/gov/test_common.go +++ b/x/gov/test_common.go @@ -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 ( diff --git a/x/gov/types/codec.go b/x/gov/types/codec.go index 8a0f931e2656..bec23cce0c5b 100644 --- a/x/gov/types/codec.go +++ b/x/gov/types/codec.go @@ -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) } diff --git a/x/gov/types/errors.go b/x/gov/types/errors.go index 0c35bc399cba..65b97d908e48 100644 --- a/x/gov/types/errors.go +++ b/x/gov/types/errors.go @@ -1,5 +1,4 @@ //nolint - package types import ( diff --git a/x/gov/types/msgs.go b/x/gov/types/msgs.go index bf12af08b172..e594773c3a2a 100644 --- a/x/gov/types/msgs.go +++ b/x/gov/types/msgs.go @@ -66,7 +66,7 @@ func (msg MsgSubmitProposal) String() string { // Implements Msg. func (msg MsgSubmitProposal) GetSignBytes() []byte { - bz := msgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -116,7 +116,7 @@ func (msg MsgDeposit) String() string { // Implements Msg. func (msg MsgDeposit) GetSignBytes() []byte { - bz := msgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -162,7 +162,7 @@ func (msg MsgVote) String() string { // Implements Msg. func (msg MsgVote) GetSignBytes() []byte { - bz := msgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } diff --git a/x/mint/abci_app.go b/x/mint/abci_app.go index 5016a464d18a..24eeeedfbd17 100644 --- a/x/mint/abci_app.go +++ b/x/mint/abci_app.go @@ -4,7 +4,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" ) -// Inflate every block, update inflation parameters once per hour +// mint new tokens for the previous block func BeginBlocker(ctx sdk.Context, k Keeper) { // fetch stored minter & params diff --git a/x/mint/codec.go b/x/mint/codec.go new file mode 100644 index 000000000000..e704d29f6054 --- /dev/null +++ b/x/mint/codec.go @@ -0,0 +1,14 @@ +package mint + +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() +} diff --git a/x/mint/keeper.go b/x/mint/keeper.go index 327e9c1ad1a0..f298b51611cc 100644 --- a/x/mint/keeper.go +++ b/x/mint/keeper.go @@ -9,14 +9,11 @@ import ( var minterKey = []byte{0x00} // the one key to use for the keeper store const ( - // ModuleName is the name of the module - ModuleName = "minting" - // default paramspace for params keeper - DefaultParamspace = "mint" + DefaultParamspace = ModuleName // StoreKey is the default store key for mint - StoreKey = "mint" + StoreKey = ModuleName // QuerierRoute is the querier route for the minting store. QuerierRoute = StoreKey @@ -51,7 +48,7 @@ func (k Keeper) GetMinter(ctx sdk.Context) (minter Minter) { store := ctx.KVStore(k.storeKey) b := store.Get(minterKey) if b == nil { - panic("Stored fee pool should not have been nil") + panic("stored minter should not have been nil") } k.cdc.MustUnmarshalBinaryLengthPrefixed(b, &minter) return @@ -66,13 +63,13 @@ func (k Keeper) SetMinter(ctx sdk.Context, minter Minter) { //______________________________________________________________________ -// GetParams returns the total set of slashing parameters. +// GetParams returns the total set of minting parameters. func (k Keeper) GetParams(ctx sdk.Context) (params Params) { k.paramSpace.GetParamSet(ctx, ¶ms) return params } -// set inflation params from the global param store +// SetParams sets the total set of minting parameters. func (k Keeper) SetParams(ctx sdk.Context, params Params) { k.paramSpace.SetParamSet(ctx, ¶ms) } diff --git a/x/mint/module.go b/x/mint/module.go new file mode 100644 index 000000000000..d645624fa09f --- /dev/null +++ b/x/mint/module.go @@ -0,0 +1,109 @@ +package mint + +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 = "mint" + +// 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) {} + +// 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(_ sdk.InvariantRouter) {} + +// module message route name +func (AppModule) Route() string { return "" } + +// module handler +func (am 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.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, _ abci.RequestBeginBlock) sdk.Tags { + BeginBlocker(ctx, am.keeper) + return sdk.EmptyTags() +} + +// module end-block +func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) { + return []abci.ValidatorUpdate{}, sdk.EmptyTags() +} diff --git a/x/mint/test_common.go b/x/mint/test_common.go index b4458b3ca264..d3615bdb3db5 100644 --- a/x/mint/test_common.go +++ b/x/mint/test_common.go @@ -27,14 +27,7 @@ type testInput struct { mintKeeper Keeper } -func createTestCodec() *codec.Codec { - cdc := codec.New() - codec.RegisterCrypto(cdc) - return cdc -} - func newTestInput(t *testing.T) testInput { - cdc := createTestCodec() db := dbm.NewMemDB() keyAcc := sdk.NewKVStoreKey(auth.StoreKey) @@ -56,15 +49,15 @@ func newTestInput(t *testing.T) testInput { err := ms.LoadLatestVersion() require.Nil(t, err) - paramsKeeper := params.NewKeeper(cdc, keyParams, tkeyParams, params.DefaultCodespace) - feeCollectionKeeper := auth.NewFeeCollectionKeeper(cdc, keyFeeCollection) - accountKeeper := auth.NewAccountKeeper(cdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) + paramsKeeper := params.NewKeeper(moduleCdc, keyParams, tkeyParams, params.DefaultCodespace) + feeCollectionKeeper := auth.NewFeeCollectionKeeper(moduleCdc, keyFeeCollection) + accountKeeper := auth.NewAccountKeeper(moduleCdc, keyAcc, paramsKeeper.Subspace(auth.DefaultParamspace), auth.ProtoBaseAccount) bankKeeper := bank.NewBaseKeeper(accountKeeper, paramsKeeper.Subspace(bank.DefaultParamspace), bank.DefaultCodespace) stakingKeeper := staking.NewKeeper( - cdc, keyStaking, tkeyStaking, bankKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace, + moduleCdc, keyStaking, tkeyStaking, bankKeeper, paramsKeeper.Subspace(staking.DefaultParamspace), staking.DefaultCodespace, ) mintKeeper := NewKeeper( - cdc, keyMint, paramsKeeper.Subspace(DefaultParamspace), &stakingKeeper, feeCollectionKeeper, + moduleCdc, keyMint, paramsKeeper.Subspace(DefaultParamspace), &stakingKeeper, feeCollectionKeeper, ) ctx := sdk.NewContext(ms, abci.Header{Time: time.Unix(0, 0)}, false, log.NewTMLogger(os.Stdout)) @@ -72,5 +65,5 @@ func newTestInput(t *testing.T) testInput { mintKeeper.SetParams(ctx, DefaultParams()) mintKeeper.SetMinter(ctx, DefaultInitialMinter()) - return testInput{ctx, cdc, mintKeeper} + return testInput{ctx, moduleCdc, mintKeeper} } diff --git a/x/params/module.go b/x/params/module.go new file mode 100644 index 000000000000..1749dfc5a82e --- /dev/null +++ b/x/params/module.go @@ -0,0 +1,34 @@ +package params + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/params/types" +) + +var ( + _ sdk.AppModuleBasic = AppModuleBasic{} +) + +const moduleName = "params" + +// app module basics object +type AppModuleBasic struct{} + +// module name +func (AppModuleBasic) Name() string { + return moduleName +} + +// register module codec +func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { + types.RegisterCodec(cdc) +} + +// default genesis state +func (AppModuleBasic) DefaultGenesis() json.RawMessage { return nil } + +// module validate genesis +func (AppModuleBasic) ValidateGenesis(_ json.RawMessage) error { return nil } diff --git a/x/slashing/app_test.go b/x/slashing/app_test.go index 94d53f5889c4..d1ff6214eca2 100644 --- a/x/slashing/app_test.go +++ b/x/slashing/app_test.go @@ -12,6 +12,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" "github.com/cosmos/cosmos-sdk/x/staking" + "github.com/cosmos/cosmos-sdk/x/staking/types" ) var ( @@ -38,7 +39,7 @@ func getMockApp(t *testing.T) (*mock.App, staking.Keeper, Keeper) { mapp.Router().AddRoute(RouterKey, NewHandler(keeper)) mapp.SetEndBlocker(getEndBlocker(stakingKeeper)) - mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper)) + mapp.SetInitChainer(getInitChainer(mapp, stakingKeeper, mapp.AccountKeeper)) require.NoError(t, mapp.CompleteSetup(keyStaking, tkeyStaking, keySlashing)) @@ -57,17 +58,13 @@ func getEndBlocker(keeper staking.Keeper) sdk.EndBlocker { } // overwrite the mock init chainer -func getInitChainer(mapp *mock.App, keeper staking.Keeper) sdk.InitChainer { +func getInitChainer(mapp *mock.App, keeper staking.Keeper, accountKeeper types.AccountKeeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) stakingGenesis := staking.DefaultGenesisState() tokens := sdk.TokensFromTendermintPower(100000) stakingGenesis.Pool.NotBondedTokens = tokens - validators, err := staking.InitGenesis(ctx, keeper, stakingGenesis) - if err != nil { - panic(err) - } - + validators := staking.InitGenesis(ctx, keeper, accountKeeper, stakingGenesis) return abci.ResponseInitChain{ Validators: validators, } diff --git a/x/slashing/codec.go b/x/slashing/codec.go index ebe08428c669..f48ce6fc6afa 100644 --- a/x/slashing/codec.go +++ b/x/slashing/codec.go @@ -9,4 +9,11 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgUnjail{}, "cosmos-sdk/MsgUnjail", nil) } -var cdcEmpty = codec.New() +var moduleCdc = codec.New() + +func init() { + cdc := codec.New() + RegisterCodec(cdc) + codec.RegisterCrypto(cdc) + moduleCdc = cdc.Seal() +} diff --git a/x/slashing/expected_keepers.go b/x/slashing/expected_keepers.go new file mode 100644 index 000000000000..c0a637abec2a --- /dev/null +++ b/x/slashing/expected_keepers.go @@ -0,0 +1,17 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" +) + +// expected staking keeper +type StakingKeeper interface { + IterateValidators(ctx sdk.Context, + fn func(index int64, validator sdk.Validator) (stop bool)) +} + +// expected bank keeper +type AccountKeeper interface { + IterateAccounts(ctx sdk.Context, process func(auth.Account) (stop bool)) +} diff --git a/x/slashing/genesis.go b/x/slashing/genesis.go index 49c1a866b380..11a9907bc65c 100644 --- a/x/slashing/genesis.go +++ b/x/slashing/genesis.go @@ -14,6 +14,17 @@ type GenesisState struct { MissedBlocks map[string][]MissedBlock `json:"missed_blocks"` } +// NewGenesisState creates a new GenesisState object +func NewGenesisState(params Params, signingInfos map[string]ValidatorSigningInfo, + missedBlocks map[string][]MissedBlock) GenesisState { + + return GenesisState{ + Params: params, + SigningInfos: signingInfos, + MissedBlocks: missedBlocks, + } +} + // MissedBlock type MissedBlock struct { Index int64 `json:"index"` @@ -66,10 +77,13 @@ func ValidateGenesis(data GenesisState) error { // InitGenesis initialize default parameters // and the keeper's address to pubkey map -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState, validators []sdk.Validator) { - for _, validator := range validators { - keeper.addPubkey(ctx, validator.GetConsPubKey()) - } +func InitGenesis(ctx sdk.Context, keeper Keeper, stakingKeeper StakingKeeper, data GenesisState) { + stakingKeeper.IterateValidators(ctx, + func(index int64, validator sdk.Validator) bool { + keeper.addPubkey(ctx, validator.GetConsPubKey()) + return false + }, + ) for addr, info := range data.SigningInfos { address, err := sdk.ConsAddressFromBech32(addr) diff --git a/x/slashing/keys.go b/x/slashing/keys.go index ce3da1c7e601..009a31b4aa48 100644 --- a/x/slashing/keys.go +++ b/x/slashing/keys.go @@ -7,9 +7,6 @@ import ( ) const ( - // ModuleName is the name of the module - ModuleName = "slashing" - // StoreKey is the store key string for slashing StoreKey = ModuleName diff --git a/x/slashing/module.go b/x/slashing/module.go new file mode 100644 index 000000000000..15caaf6bb429 --- /dev/null +++ b/x/slashing/module.go @@ -0,0 +1,116 @@ +package slashing + +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 = "slashing" + +// 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 + stakingKeeper StakingKeeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(keeper Keeper, stakingKeeper StakingKeeper) AppModule { + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + stakingKeeper: stakingKeeper, + } +} + +// module name +func (AppModule) Name() string { + return ModuleName +} + +// register invariants +func (am 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 + moduleCdc.MustUnmarshalJSON(data, &genesisState) + InitGenesis(ctx, am.keeper, am.stakingKeeper, 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 { + return BeginBlocker(ctx, req, am.keeper) +} + +// module end-block +func (AppModule) EndBlock(_ sdk.Context, _ abci.RequestEndBlock) ([]abci.ValidatorUpdate, sdk.Tags) { + return []abci.ValidatorUpdate{}, sdk.EmptyTags() +} diff --git a/x/slashing/msg.go b/x/slashing/msg.go index a108142f77ee..5e49969f8732 100644 --- a/x/slashing/msg.go +++ b/x/slashing/msg.go @@ -1,12 +1,9 @@ package slashing import ( - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) -var cdc = codec.New() - // verify interface at compile time var _ sdk.Msg = &MsgUnjail{} @@ -30,7 +27,7 @@ func (msg MsgUnjail) GetSigners() []sdk.AccAddress { // get the bytes for the message signer to sign on func (msg MsgUnjail) GetSignBytes() []byte { - bz := cdc.MustMarshalJSON(msg) + bz := moduleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } diff --git a/x/slashing/msg_test.go b/x/slashing/msg_test.go index 594658ce8612..f0e19fc54294 100644 --- a/x/slashing/msg_test.go +++ b/x/slashing/msg_test.go @@ -12,5 +12,9 @@ func TestMsgUnjailGetSignBytes(t *testing.T) { addr := sdk.AccAddress("abcd") msg := NewMsgUnjail(sdk.ValAddress(addr)) bytes := msg.GetSignBytes() - require.Equal(t, string(bytes), `{"address":"cosmosvaloper1v93xxeqhg9nn6"}`) + require.Equal( + t, + `{"type":"cosmos-sdk/MsgUnjail","value":{"address":"cosmosvaloper1v93xxeqhg9nn6"}}`, + string(bytes), + ) } diff --git a/x/slashing/params.go b/x/slashing/params.go index 0ec5386f266c..98cae397fe6f 100644 --- a/x/slashing/params.go +++ b/x/slashing/params.go @@ -49,6 +49,21 @@ type Params struct { SlashFractionDowntime sdk.Dec `json:"slash_fraction_downtime"` } +// NewParams creates a new Params object +func NewParams(maxEvidenceAge time.Duration, signedBlocksWindow int64, + minSignedPerWindow sdk.Dec, downtimeJailDuration time.Duration, + slashFractionDoubleSign sdk.Dec, slashFractionDowntime sdk.Dec) Params { + + return Params{ + MaxEvidenceAge: maxEvidenceAge, + SignedBlocksWindow: signedBlocksWindow, + MinSignedPerWindow: minSignedPerWindow, + DowntimeJailDuration: downtimeJailDuration, + SlashFractionDoubleSign: slashFractionDoubleSign, + SlashFractionDowntime: slashFractionDowntime, + } +} + func (p Params) String() string { return fmt.Sprintf(`Slashing Params: MaxEvidenceAge: %s diff --git a/x/slashing/querier.go b/x/slashing/querier.go index 291030f3dbbf..df6144b58515 100644 --- a/x/slashing/querier.go +++ b/x/slashing/querier.go @@ -17,28 +17,25 @@ const ( ) // NewQuerier creates a new querier for slashing clients. -func NewQuerier(k Keeper, cdc *codec.Codec) sdk.Querier { +func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, sdk.Error) { switch path[0] { case QueryParameters: - return queryParams(ctx, cdc, k) - + return queryParams(ctx, k) case QuerySigningInfo: - return querySigningInfo(ctx, cdc, req, k) - + return querySigningInfo(ctx, req, k) case QuerySigningInfos: - return querySigningInfos(ctx, cdc, req, k) - + return querySigningInfos(ctx, req, k) default: return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") } } } -func queryParams(ctx sdk.Context, cdc *codec.Codec, k Keeper) ([]byte, sdk.Error) { +func queryParams(ctx sdk.Context, k Keeper) ([]byte, sdk.Error) { params := k.GetParams(ctx) - res, err := codec.MarshalJSONIndent(cdc, params) + res, err := codec.MarshalJSONIndent(moduleCdc, params) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal JSON", err.Error())) } @@ -56,10 +53,10 @@ func NewQuerySigningInfoParams(consAddr sdk.ConsAddress) QuerySigningInfoParams return QuerySigningInfoParams{consAddr} } -func querySigningInfo(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfo(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params QuerySigningInfoParams - err := cdc.UnmarshalJSON(req.Data, ¶ms) + err := moduleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -69,7 +66,7 @@ func querySigningInfo(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, return nil, ErrNoSigningInfoFound(DefaultCodespace, params.ConsAddress) } - res, err := codec.MarshalJSONIndent(cdc, signingInfo) + res, err := codec.MarshalJSONIndent(moduleCdc, signingInfo) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) } @@ -87,10 +84,10 @@ func NewQuerySigningInfosParams(page, limit int) QuerySigningInfosParams { return QuerySigningInfosParams{page, limit} } -func querySigningInfos(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { +func querySigningInfos(ctx sdk.Context, req abci.RequestQuery, k Keeper) ([]byte, sdk.Error) { var params QuerySigningInfosParams - err := cdc.UnmarshalJSON(req.Data, ¶ms) + err := moduleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -121,7 +118,7 @@ func querySigningInfos(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, signingInfos = signingInfos[start:end] } - res, err := codec.MarshalJSONIndent(cdc, signingInfos) + res, err := codec.MarshalJSONIndent(moduleCdc, signingInfos) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) } diff --git a/x/slashing/querier_test.go b/x/slashing/querier_test.go index bc1ba804b1eb..a4941e0a9efe 100644 --- a/x/slashing/querier_test.go +++ b/x/slashing/querier_test.go @@ -10,9 +10,8 @@ import ( ) func TestNewQuerier(t *testing.T) { - cdc := codec.New() ctx, _, _, _, keeper := createTestInput(t, keeperTestParams()) - querier := NewQuerier(keeper, cdc) + querier := NewQuerier(keeper) query := abci.RequestQuery{ Path: "", @@ -29,7 +28,7 @@ func TestQueryParams(t *testing.T) { var params Params - res, errRes := queryParams(ctx, cdc, keeper) + res, errRes := queryParams(ctx, keeper) require.NoError(t, errRes) err := cdc.UnmarshalJSON(res, ¶ms) diff --git a/x/slashing/test_common.go b/x/slashing/test_common.go index cfc0297ff7b3..2a555d7b58ca 100644 --- a/x/slashing/test_common.go +++ b/x/slashing/test_common.go @@ -76,8 +76,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s genesis.Pool.NotBondedTokens = initCoins.MulRaw(int64(len(addrs))) - _, err = staking.InitGenesis(ctx, sk, genesis) - require.Nil(t, err) + _ = staking.InitGenesis(ctx, sk, accountKeeper, genesis) for _, addr := range addrs { _, err = ck.AddCoins(ctx, sdk.AccAddress(addr), sdk.Coins{ @@ -90,7 +89,7 @@ func createTestInput(t *testing.T, defaults Params) (sdk.Context, bank.Keeper, s sk.SetHooks(keeper.Hooks()) require.NotPanics(t, func() { - InitGenesis(ctx, keeper, GenesisState{defaults, nil, nil}, genesis.Validators.ToSDKValidators()) + InitGenesis(ctx, keeper, sk, GenesisState{defaults, nil, nil}) }) return ctx, ck, sk, paramstore, keeper diff --git a/x/staking/alias.go b/x/staking/alias.go index 893a2c81a134..1f28f622c2bf 100644 --- a/x/staking/alias.go +++ b/x/staking/alias.go @@ -12,6 +12,7 @@ type ( FeeCollectionKeeper = types.FeeCollectionKeeper BankKeeper = types.BankKeeper DistributionKeeper = types.DistributionKeeper + AccountKeeper = types.AccountKeeper Validator = types.Validator Validators = types.Validators Description = types.Description @@ -28,6 +29,7 @@ type ( RedelegationResponses = types.RedelegationResponses Params = types.Params Pool = types.Pool + MultiStakingHooks = types.MultiStakingHooks MsgCreateValidator = types.MsgCreateValidator MsgEditValidator = types.MsgEditValidator MsgDelegate = types.MsgDelegate @@ -83,7 +85,9 @@ var ( KeyMaxValidators = types.KeyMaxValidators KeyBondDenom = types.KeyBondDenom + ModuleCdc = types.ModuleCdc DefaultParams = types.DefaultParams + NewParams = types.NewParams InitialPool = types.InitialPool NewValidator = types.NewValidator NewDescription = types.NewDescription @@ -93,6 +97,7 @@ var ( NewGenesisState = types.NewGenesisState DefaultGenesisState = types.DefaultGenesisState RegisterCodec = types.RegisterCodec + NewMultiStakingHooks = types.NewMultiStakingHooks NewMsgCreateValidator = types.NewMsgCreateValidator NewMsgEditValidator = types.NewMsgEditValidator @@ -126,6 +131,7 @@ const ( ) const ( + ModuleName = types.ModuleName StoreKey = types.StoreKey TStoreKey = types.TStoreKey QuerierRoute = types.QuerierRoute diff --git a/x/staking/app_test.go b/x/staking/app_test.go index da8c52ea5b51..3555d3a6a453 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -10,6 +10,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" "github.com/cosmos/cosmos-sdk/x/mock" + "github.com/cosmos/cosmos-sdk/x/staking/types" ) // getMockApp returns an initialized mock application for this module. @@ -26,7 +27,7 @@ func getMockApp(t *testing.T) (*mock.App, Keeper) { mApp.Router().AddRoute(RouterKey, NewHandler(keeper)) mApp.SetEndBlocker(getEndBlocker(keeper)) - mApp.SetInitChainer(getInitChainer(mApp, keeper)) + mApp.SetInitChainer(getInitChainer(mApp, keeper, mApp.AccountKeeper)) require.NoError(t, mApp.CompleteSetup(keyStaking, tkeyStaking)) return mApp, keeper @@ -46,7 +47,7 @@ func getEndBlocker(keeper Keeper) sdk.EndBlocker { // getInitChainer initializes the chainer of the mock app and sets the genesis // state. It returns an empty ResponseInitChain. -func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { +func getInitChainer(mapp *mock.App, keeper Keeper, accountKeeper types.AccountKeeper) sdk.InitChainer { return func(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain { mapp.InitChainer(ctx, req) @@ -54,11 +55,7 @@ func getInitChainer(mapp *mock.App, keeper Keeper) sdk.InitChainer { tokens := sdk.TokensFromTendermintPower(100000) stakingGenesis.Pool.NotBondedTokens = tokens - validators, err := InitGenesis(ctx, keeper, stakingGenesis) - if err != nil { - panic(err) - } - + validators := InitGenesis(ctx, keeper, accountKeeper, stakingGenesis) return abci.ResponseInitChain{ Validators: validators, } diff --git a/x/staking/genesis.go b/x/staking/genesis.go index 7c10584b5e1e..358f9ebac008 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -7,6 +7,7 @@ import ( 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/types" ) @@ -15,7 +16,7 @@ import ( // setting the indexes. In addition, it also sets any delegations found in // data. Finally, it updates the bonded validators. // Returns final validator set after applying all declaration and delegations -func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res []abci.ValidatorUpdate, err error) { +func InitGenesis(ctx sdk.Context, keeper Keeper, accountKeeper types.AccountKeeper, data types.GenesisState) (res []abci.ValidatorUpdate) { // We need to pretend to be "n blocks before genesis", where "n" is the // validator update delay, so that e.g. slashing periods are correctly @@ -24,7 +25,18 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ // genesis.json are in block 0. ctx = ctx.WithBlockHeight(1 - sdk.ValidatorUpdateDelay) - keeper.SetPool(ctx, data.Pool) + // manually set the total supply for staking based on accounts if not provided + if data.Pool.NotBondedTokens.IsZero() { + accountKeeper.IterateAccounts(ctx, + func(acc auth.Account) (stop bool) { + data.Pool.NotBondedTokens = data.Pool.NotBondedTokens. + Add(acc.GetCoins().AmountOf(data.Params.BondDenom)) + return false + }, + ) + } + + keeper.SetPool(ctx, data.Pool) // TODO remove pool from genesis data and always calculate? keeper.SetParams(ctx, data.Params) keeper.SetLastTotalPower(ctx, data.LastTotalPower) @@ -88,7 +100,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [ res = keeper.ApplyAndReturnValidatorSetUpdates(ctx) } - return + return res } // ExportGenesis returns a GenesisState for a given context and keeper. The diff --git a/x/staking/genesis_test.go b/x/staking/genesis_test.go index c62b7caa5811..9b61d069d558 100644 --- a/x/staking/genesis_test.go +++ b/x/staking/genesis_test.go @@ -17,7 +17,7 @@ import ( ) func TestInitGenesis(t *testing.T) { - ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, keeper := keep.CreateTestInput(t, false, 1000) pool := keeper.GetPool(ctx) pool.BondedTokens = sdk.TokensFromTendermintPower(2) @@ -42,8 +42,7 @@ func TestInitGenesis(t *testing.T) { validators[1].DelegatorShares = valTokens.ToDec() genesisState := types.NewGenesisState(pool, params, validators, delegations) - vals, err := InitGenesis(ctx, keeper, genesisState) - require.NoError(t, err) + vals := InitGenesis(ctx, keeper, accKeeper, genesisState) actualGenesis := ExportGenesis(ctx, keeper) require.Equal(t, genesisState.Pool, actualGenesis.Pool) @@ -72,7 +71,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { size := 200 require.True(t, size > 100) - ctx, _, keeper := keep.CreateTestInput(t, false, 1000) + ctx, accKeeper, keeper := keep.CreateTestInput(t, false, 1000) // Assigning 2 to the first 100 vals, 1 to the rest pool := keeper.GetPool(ctx) @@ -98,8 +97,7 @@ func TestInitGenesisLargeValidatorSet(t *testing.T) { } genesisState := types.NewGenesisState(pool, params, validators, delegations) - vals, err := InitGenesis(ctx, keeper, genesisState) - require.NoError(t, err) + vals := InitGenesis(ctx, keeper, accKeeper, genesisState) abcivals := make([]abci.ValidatorUpdate, 100) for i, val := range validators[:100] { diff --git a/x/staking/handler.go b/x/staking/handler.go index 762260c9ab25..e2c1e8b03ed8 100644 --- a/x/staking/handler.go +++ b/x/staking/handler.go @@ -249,7 +249,7 @@ func handleMsgUndelegate(ctx sdk.Context, msg types.MsgUndelegate, k keeper.Keep return err.Result() } - finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(completionTime) + finishTime := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) resTags := sdk.NewTags( tags.Category, tags.TxCategory, tags.Sender, msg.DelegatorAddress.String(), @@ -275,7 +275,7 @@ func handleMsgBeginRedelegate(ctx sdk.Context, msg types.MsgBeginRedelegate, k k return err.Result() } - finishTime := types.MsgCdc.MustMarshalBinaryLengthPrefixed(completionTime) + finishTime := types.ModuleCdc.MustMarshalBinaryLengthPrefixed(completionTime) resTags := sdk.NewTags( tags.Category, tags.TxCategory, tags.Sender, msg.DelegatorAddress.String(), diff --git a/x/staking/handler_test.go b/x/staking/handler_test.go index bdf0ab4699c3..6f6c43b3d3ba 100644 --- a/x/staking/handler_test.go +++ b/x/staking/handler_test.go @@ -101,7 +101,7 @@ func TestValidatorByPowerIndex(t *testing.T) { require.True(t, got.IsOK(), "expected msg to be ok, got %v", got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -228,7 +228,7 @@ func TestLegacyValidatorDelegations(t *testing.T) { require.True(t, got.IsOK(), "expected begin unbonding validator msg to be ok, got %v", got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -451,7 +451,7 @@ func TestIncrementsMsgUnbond(t *testing.T) { got := handleMsgUndelegate(ctx, msgUndelegate, keeper) require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -557,7 +557,7 @@ func TestMultipleMsgCreateValidator(t *testing.T) { var finishTime time.Time // Jump to finishTime for unbonding period and remove from unbonding queue - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -606,7 +606,7 @@ func TestMultipleMsgDelegate(t *testing.T) { require.True(t, got.IsOK(), "expected msg %d to be ok, got %v", i, got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -639,7 +639,7 @@ func TestJailValidator(t *testing.T) { require.True(t, got.IsOK(), "expected no error: %v", got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -653,7 +653,7 @@ func TestJailValidator(t *testing.T) { got = handleMsgUndelegate(ctx, msgUndelegateDelegator, keeper) require.True(t, got.IsOK(), "expected no error") - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -693,7 +693,7 @@ func TestValidatorQueue(t *testing.T) { require.True(t, got.IsOK(), "expected no error: %v", got) var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime) EndBlocker(ctx, keeper) @@ -789,7 +789,7 @@ func TestUnbondingFromUnbondingValidator(t *testing.T) { // change the ctx to Block Time one second before the validator would have unbonded var finishTime time.Time - types.MsgCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) + types.ModuleCdc.MustUnmarshalBinaryLengthPrefixed(got.Data, &finishTime) ctx = ctx.WithBlockTime(finishTime.Add(time.Second * -1)) // unbond the delegator from the validator diff --git a/x/staking/keeper/invariants.go b/x/staking/keeper/invariants.go index f9a495a4f6eb..26c5428036a7 100644 --- a/x/staking/keeper/invariants.go +++ b/x/staking/keeper/invariants.go @@ -10,22 +10,22 @@ import ( ) // register all staking invariants -func RegisterInvariants(c types.CrisisKeeper, k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) { +func RegisterInvariants(ir sdk.InvariantRouter, k Keeper, f types.FeeCollectionKeeper, + d types.DistributionKeeper, am types.AccountKeeper) { - c.RegisterRoute(types.ModuleName, "supply", + ir.RegisterRoute(types.ModuleName, "supply", SupplyInvariants(k, f, d, am)) - c.RegisterRoute(types.ModuleName, "nonnegative-power", + ir.RegisterRoute(types.ModuleName, "nonnegative-power", NonNegativePowerInvariant(k)) - c.RegisterRoute(types.ModuleName, "positive-delegation", + ir.RegisterRoute(types.ModuleName, "positive-delegation", PositiveDelegationInvariant(k)) - c.RegisterRoute(types.ModuleName, "delegator-shares", + ir.RegisterRoute(types.ModuleName, "delegator-shares", DelegatorSharesInvariant(k)) } // AllInvariants runs all invariants of the staking module. func AllInvariants(k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { + d types.DistributionKeeper, am types.AccountKeeper) sdk.Invariant { return func(ctx sdk.Context) error { err := SupplyInvariants(k, f, d, am)(ctx) @@ -55,7 +55,7 @@ func AllInvariants(k Keeper, f types.FeeCollectionKeeper, // SupplyInvariants checks that the total supply reflects all held not-bonded tokens, bonded tokens, and unbonding delegations // nolint: unparam func SupplyInvariants(k Keeper, f types.FeeCollectionKeeper, - d types.DistributionKeeper, am auth.AccountKeeper) sdk.Invariant { + d types.DistributionKeeper, am types.AccountKeeper) sdk.Invariant { return func(ctx sdk.Context) error { pool := k.GetPool(ctx) diff --git a/x/staking/module.go b/x/staking/module.go new file mode 100644 index 000000000000..520829054b9a --- /dev/null +++ b/x/staking/module.go @@ -0,0 +1,120 @@ +package staking + +import ( + "encoding/json" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/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 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 + fcKeeper FeeCollectionKeeper + distrKeeper DistributionKeeper + accKeeper AccountKeeper +} + +// NewAppModule creates a new AppModule object +func NewAppModule(keeper Keeper, fcKeeper types.FeeCollectionKeeper, + distrKeeper types.DistributionKeeper, accKeeper AccountKeeper) AppModule { + + return AppModule{ + AppModuleBasic: AppModuleBasic{}, + keeper: keeper, + fcKeeper: fcKeeper, + distrKeeper: distrKeeper, + accKeeper: accKeeper, + } +} + +// module name +func (AppModule) Name() string { + return ModuleName +} + +// register invariants +func (am AppModule) RegisterInvariants(ir sdk.InvariantRouter) { + RegisterInvariants(ir, am.keeper, am.fcKeeper, am.distrKeeper, am.accKeeper) +} + +// 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) + return InitGenesis(ctx, am.keeper, am.accKeeper, genesisState) +} + +// 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) { + return EndBlocker(ctx, am.keeper) +} diff --git a/x/staking/querier/querier.go b/x/staking/querier/querier.go index 24715dac4af9..b18e77263066 100644 --- a/x/staking/querier/querier.go +++ b/x/staking/querier/querier.go @@ -31,48 +31,35 @@ const ( ) // creates a querier for staking REST endpoints -func NewQuerier(k keep.Keeper, cdc *codec.Codec) sdk.Querier { +func NewQuerier(k keep.Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) (res []byte, err sdk.Error) { switch path[0] { case QueryValidators: - return queryValidators(ctx, cdc, req, k) - + return queryValidators(ctx, req, k) case QueryValidator: - return queryValidator(ctx, cdc, req, k) - + return queryValidator(ctx, req, k) case QueryValidatorDelegations: - return queryValidatorDelegations(ctx, cdc, req, k) - + return queryValidatorDelegations(ctx, req, k) case QueryValidatorUnbondingDelegations: - return queryValidatorUnbondingDelegations(ctx, cdc, req, k) - + return queryValidatorUnbondingDelegations(ctx, req, k) case QueryDelegation: - return queryDelegation(ctx, cdc, req, k) - + return queryDelegation(ctx, req, k) case QueryUnbondingDelegation: - return queryUnbondingDelegation(ctx, cdc, req, k) - + return queryUnbondingDelegation(ctx, req, k) case QueryDelegatorDelegations: - return queryDelegatorDelegations(ctx, cdc, req, k) - + return queryDelegatorDelegations(ctx, req, k) case QueryDelegatorUnbondingDelegations: - return queryDelegatorUnbondingDelegations(ctx, cdc, req, k) - + return queryDelegatorUnbondingDelegations(ctx, req, k) case QueryRedelegations: - return queryRedelegations(ctx, cdc, req, k) - + return queryRedelegations(ctx, req, k) case QueryDelegatorValidators: - return queryDelegatorValidators(ctx, cdc, req, k) - + return queryDelegatorValidators(ctx, req, k) case QueryDelegatorValidator: - return queryDelegatorValidator(ctx, cdc, req, k) - + return queryDelegatorValidator(ctx, req, k) case QueryPool: - return queryPool(ctx, cdc, k) - + return queryPool(ctx, k) case QueryParameters: - return queryParameters(ctx, cdc, k) - + return queryParameters(ctx, k) default: return nil, sdk.ErrUnknownRequest("unknown staking query endpoint") } @@ -141,10 +128,10 @@ func NewQueryRedelegationParams(delegatorAddr sdk.AccAddress, srcValidatorAddr s } } -func queryValidators(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) ([]byte, sdk.Error) { +func queryValidators(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) ([]byte, sdk.Error) { var params QueryValidatorsParams - err := cdc.UnmarshalJSON(req.Data, ¶ms) + err := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if err != nil { return nil, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -177,7 +164,7 @@ func queryValidators(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k filteredVals = filteredVals[start:end] } - res, err := codec.MarshalJSONIndent(cdc, filteredVals) + res, err := codec.MarshalJSONIndent(types.ModuleCdc, filteredVals) if err != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to JSON marshal result: %s", err.Error())) } @@ -185,10 +172,10 @@ func queryValidators(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return res, nil } -func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryValidator(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryValidatorParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -198,17 +185,17 @@ func queryValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return []byte{}, types.ErrNoValidatorFound(types.DefaultCodespace) } - res, errRes = codec.MarshalJSONIndent(cdc, validator) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, validator) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryValidatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryValidatorDelegations(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryValidatorParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -219,7 +206,7 @@ func queryValidatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.Reque return nil, err } - res, errRes = codec.MarshalJSONIndent(cdc, delegationResps) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errRes.Error())) } @@ -227,27 +214,27 @@ func queryValidatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.Reque return res, nil } -func queryValidatorUnbondingDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryValidatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryValidatorParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } unbonds := k.GetUnbondingDelegationsFromValidator(ctx, params.ValidatorAddr) - res, errRes = codec.MarshalJSONIndent(cdc, unbonds) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, unbonds) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryDelegatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryDelegatorDelegations(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryDelegatorParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -258,7 +245,7 @@ func queryDelegatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.Reque return nil, err } - res, errRes = codec.MarshalJSONIndent(cdc, delegationResps) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, delegationResps) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errRes.Error())) } @@ -266,46 +253,46 @@ func queryDelegatorDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.Reque return res, nil } -func queryDelegatorUnbondingDelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryDelegatorUnbondingDelegations(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryDelegatorParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } unbondingDelegations := k.GetAllUnbondingDelegations(ctx, params.DelegatorAddr) - res, errRes = codec.MarshalJSONIndent(cdc, unbondingDelegations) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, unbondingDelegations) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryDelegatorValidators(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryDelegatorValidators(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryDelegatorParams stakingParams := k.GetParams(ctx) - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } validators := k.GetDelegatorValidators(ctx, params.DelegatorAddr, stakingParams.MaxValidators) - res, errRes = codec.MarshalJSONIndent(cdc, validators) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, validators) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryDelegatorValidator(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryDelegatorValidator(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryBondsParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -315,17 +302,17 @@ func queryDelegatorValidator(ctx sdk.Context, cdc *codec.Codec, req abci.Request return } - res, errRes = codec.MarshalJSONIndent(cdc, validator) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, validator) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryDelegation(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryBondsParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -340,7 +327,7 @@ func queryDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return nil, err } - res, errRes = codec.MarshalJSONIndent(cdc, delegationResp) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, delegationResp) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errRes.Error())) } @@ -348,10 +335,10 @@ func queryDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k return res, nil } -func queryUnbondingDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryUnbondingDelegation(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryBondsParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrInternal(fmt.Sprintf("failed to parse params: %s", err)) } @@ -361,17 +348,17 @@ func queryUnbondingDelegation(ctx sdk.Context, cdc *codec.Codec, req abci.Reques return []byte{}, types.ErrNoUnbondingDelegation(types.DefaultCodespace) } - res, errRes = codec.MarshalJSONIndent(cdc, unbond) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, unbond) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { +func queryRedelegations(ctx sdk.Context, req abci.RequestQuery, k keep.Keeper) (res []byte, err sdk.Error) { var params QueryRedelegationParams - errRes := cdc.UnmarshalJSON(req.Data, ¶ms) + errRes := types.ModuleCdc.UnmarshalJSON(req.Data, ¶ms) if errRes != nil { return []byte{}, sdk.ErrUnknownRequest(string(req.Data)) } @@ -396,7 +383,7 @@ func queryRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery return nil, err } - res, errRes = codec.MarshalJSONIndent(cdc, redelResponses) + res, errRes = codec.MarshalJSONIndent(types.ModuleCdc, redelResponses) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("failed to marshal result to JSON", errRes.Error())) } @@ -404,20 +391,20 @@ func queryRedelegations(ctx sdk.Context, cdc *codec.Codec, req abci.RequestQuery return res, nil } -func queryPool(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) { +func queryPool(ctx sdk.Context, k keep.Keeper) (res []byte, err sdk.Error) { pool := k.GetPool(ctx) - res, errRes := codec.MarshalJSONIndent(cdc, pool) + res, errRes := codec.MarshalJSONIndent(types.ModuleCdc, pool) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } return res, nil } -func queryParameters(ctx sdk.Context, cdc *codec.Codec, k keep.Keeper) (res []byte, err sdk.Error) { +func queryParameters(ctx sdk.Context, k keep.Keeper) (res []byte, err sdk.Error) { params := k.GetParams(ctx) - res, errRes := codec.MarshalJSONIndent(cdc, params) + res, errRes := codec.MarshalJSONIndent(types.ModuleCdc, params) if errRes != nil { return nil, sdk.ErrInternal(sdk.AppendMsgToErr("could not marshal result to JSON", errRes.Error())) } diff --git a/x/staking/querier/querier_test.go b/x/staking/querier/querier_test.go index c22b58938a01..515cfcab326b 100644 --- a/x/staking/querier/querier_test.go +++ b/x/staking/querier/querier_test.go @@ -39,7 +39,7 @@ func TestNewQuerier(t *testing.T) { Data: []byte{}, } - querier := NewQuerier(keeper, cdc) + querier := NewQuerier(keeper) bz, err := querier(ctx, []string{"other"}, query) require.NotNil(t, err) @@ -95,7 +95,7 @@ func TestQueryParametersPool(t *testing.T) { cdc := codec.New() ctx, _, keeper := keep.CreateTestInput(t, false, 1000) - res, err := queryParameters(ctx, cdc, keeper) + res, err := queryParameters(ctx, keeper) require.Nil(t, err) var params types.Params @@ -103,7 +103,7 @@ func TestQueryParametersPool(t *testing.T) { require.Nil(t, errRes) require.Equal(t, keeper.GetParams(ctx), params) - res, err = queryPool(ctx, cdc, keeper) + res, err = queryPool(ctx, keeper) require.Nil(t, err) var pool types.Pool @@ -138,20 +138,20 @@ func TestQueryValidators(t *testing.T) { for i, s := range status { queryValsParams := NewQueryValidatorsParams(1, int(params.MaxValidators), s.String()) - bz, errRes := cdc.MarshalJSON(queryValsParams) - require.Nil(t, errRes) + bz, err := cdc.MarshalJSON(queryValsParams) + require.Nil(t, err) req := abci.RequestQuery{ Path: fmt.Sprintf("/custom/%s/%s", types.QuerierRoute, QueryValidators), Data: bz, } - res, err := queryValidators(ctx, cdc, req, keeper) + res, err := queryValidators(ctx, req, keeper) require.Nil(t, err) var validatorsResp []types.Validator - errRes = cdc.UnmarshalJSON(res, &validatorsResp) - require.Nil(t, errRes) + err = cdc.UnmarshalJSON(res, &validatorsResp) + require.Nil(t, err) require.Equal(t, 1, len(validatorsResp)) require.ElementsMatch(t, validators[i].OperatorAddress, validatorsResp[0].OperatorAddress) @@ -160,19 +160,19 @@ func TestQueryValidators(t *testing.T) { // Query each validator queryParams := NewQueryValidatorParams(addrVal1) - bz, errRes := cdc.MarshalJSON(queryParams) - require.Nil(t, errRes) + bz, err := cdc.MarshalJSON(queryParams) + require.Nil(t, err) query := abci.RequestQuery{ Path: "/custom/staking/validator", Data: bz, } - res, err := queryValidator(ctx, cdc, query, keeper) + res, err := queryValidator(ctx, query, keeper) require.Nil(t, err) var validator types.Validator - errRes = cdc.UnmarshalJSON(res, &validator) - require.Nil(t, errRes) + err = cdc.UnmarshalJSON(res, &validator) + require.Nil(t, err) require.Equal(t, queriedValidators[0], validator) } @@ -209,7 +209,7 @@ func TestQueryDelegation(t *testing.T) { delValidators := keeper.GetDelegatorValidators(ctx, addrAcc2, params.MaxValidators) - res, err := queryDelegatorValidators(ctx, cdc, query, keeper) + res, err := queryDelegatorValidators(ctx, query, keeper) require.Nil(t, err) var validatorsResp []types.Validator @@ -222,7 +222,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - _, err = queryDelegatorValidators(ctx, cdc, query, keeper) + _, err = queryDelegatorValidators(ctx, query, keeper) require.NotNil(t, err) // Query bonded validator @@ -235,7 +235,7 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } - res, err = queryDelegatorValidator(ctx, cdc, query, keeper) + res, err = queryDelegatorValidator(ctx, query, keeper) require.Nil(t, err) var validator types.Validator @@ -247,7 +247,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - _, err = queryDelegatorValidator(ctx, cdc, query, keeper) + _, err = queryDelegatorValidator(ctx, query, keeper) require.NotNil(t, err) // Query delegation @@ -260,7 +260,7 @@ func TestQueryDelegation(t *testing.T) { delegation, found := keeper.GetDelegation(ctx, addrAcc2, addrVal1) require.True(t, found) - res, err = queryDelegation(ctx, cdc, query, keeper) + res, err = queryDelegation(ctx, query, keeper) require.Nil(t, err) var delegationRes types.DelegationResponse @@ -277,7 +277,7 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } - res, err = queryDelegatorDelegations(ctx, cdc, query, keeper) + res, err = queryDelegatorDelegations(ctx, query, keeper) require.Nil(t, err) var delegatorDelegations types.DelegationResponses @@ -291,7 +291,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - _, err = queryDelegation(ctx, cdc, query, keeper) + _, err = queryDelegation(ctx, query, keeper) require.NotNil(t, err) // Query validator delegations @@ -304,7 +304,7 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } - res, err = queryValidatorDelegations(ctx, cdc, query, keeper) + res, err = queryValidatorDelegations(ctx, query, keeper) require.Nil(t, err) var delegationsRes types.DelegationResponses @@ -332,7 +332,7 @@ func TestQueryDelegation(t *testing.T) { unbond, found := keeper.GetUnbondingDelegation(ctx, addrAcc2, addrVal1) require.True(t, found) - res, err = queryUnbondingDelegation(ctx, cdc, query, keeper) + res, err = queryUnbondingDelegation(ctx, query, keeper) require.Nil(t, err) var unbondRes types.UnbondingDelegation @@ -344,7 +344,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - _, err = queryUnbondingDelegation(ctx, cdc, query, keeper) + _, err = queryUnbondingDelegation(ctx, query, keeper) require.NotNil(t, err) // Query Delegator Delegations @@ -354,7 +354,7 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } - res, err = queryDelegatorUnbondingDelegations(ctx, cdc, query, keeper) + res, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) require.Nil(t, err) var delegatorUbds []types.UnbondingDelegation @@ -365,7 +365,7 @@ func TestQueryDelegation(t *testing.T) { // error unknown request query.Data = bz[:len(bz)-1] - _, err = queryDelegatorUnbondingDelegations(ctx, cdc, query, keeper) + _, err = queryDelegatorUnbondingDelegations(ctx, query, keeper) require.NotNil(t, err) // Query redelegation @@ -384,7 +384,7 @@ func TestQueryDelegation(t *testing.T) { Data: bz, } - res, err = queryRedelegations(ctx, cdc, query, keeper) + res, err = queryRedelegations(ctx, query, keeper) require.Nil(t, err) var redelRes types.RedelegationResponses @@ -428,7 +428,7 @@ func TestQueryRedelegations(t *testing.T) { Data: bz, } - res, err := queryRedelegations(ctx, cdc, query, keeper) + res, err := queryRedelegations(ctx, query, keeper) require.Nil(t, err) var redelRes types.RedelegationResponses @@ -450,7 +450,7 @@ func TestQueryRedelegations(t *testing.T) { Data: bz, } - res, err = queryRedelegations(ctx, cdc, query, keeper) + res, err = queryRedelegations(ctx, query, keeper) require.Nil(t, err) errRes = cdc.UnmarshalJSON(res, &redelRes) diff --git a/x/staking/types/codec.go b/x/staking/types/codec.go index 9b43705f8f49..d4f3ad594aff 100644 --- a/x/staking/types/codec.go +++ b/x/staking/types/codec.go @@ -13,12 +13,12 @@ func RegisterCodec(cdc *codec.Codec) { cdc.RegisterConcrete(MsgBeginRedelegate{}, "cosmos-sdk/MsgBeginRedelegate", nil) } -// generic sealed codec to be used throughout sdk -var MsgCdc *codec.Codec +// generic sealed codec to be used throughout this module +var ModuleCdc *codec.Codec func init() { cdc := codec.New() RegisterCodec(cdc) codec.RegisterCrypto(cdc) - MsgCdc = cdc.Seal() + ModuleCdc = cdc.Seal() } diff --git a/x/staking/types/delegation.go b/x/staking/types/delegation.go index 72ceebc17e7a..66ce5796b57d 100644 --- a/x/staking/types/delegation.go +++ b/x/staking/types/delegation.go @@ -184,8 +184,8 @@ func UnmarshalUBD(cdc *codec.Codec, value []byte) (ubd UnbondingDelegation, err // nolint // inefficient but only used in testing func (d UnbondingDelegation) Equal(d2 UnbondingDelegation) bool { - bz1 := MsgCdc.MustMarshalBinaryLengthPrefixed(&d) - bz2 := MsgCdc.MustMarshalBinaryLengthPrefixed(&d2) + bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d) + bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d2) return bytes.Equal(bz1, bz2) } @@ -305,8 +305,8 @@ func UnmarshalRED(cdc *codec.Codec, value []byte) (red Redelegation, err error) // nolint // inefficient but only used in tests func (d Redelegation) Equal(d2 Redelegation) bool { - bz1 := MsgCdc.MustMarshalBinaryLengthPrefixed(&d) - bz2 := MsgCdc.MustMarshalBinaryLengthPrefixed(&d2) + bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d) + bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&d2) return bytes.Equal(bz1, bz2) } diff --git a/x/staking/types/expected_keepers.go b/x/staking/types/expected_keepers.go index 2a2aff06046b..430a36905862 100644 --- a/x/staking/types/expected_keepers.go +++ b/x/staking/types/expected_keepers.go @@ -1,6 +1,9 @@ package types -import sdk "github.com/cosmos/cosmos-sdk/types" +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth" +) // expected coin keeper type DistributionKeeper interface { @@ -19,7 +22,7 @@ type BankKeeper interface { UndelegateCoins(ctx sdk.Context, addr sdk.AccAddress, amt sdk.Coins) (sdk.Tags, sdk.Error) } -// expected crisis keeper -type CrisisKeeper interface { - RegisterRoute(moduleName, route string, invar sdk.Invariant) +// expected bank keeper +type AccountKeeper interface { + IterateAccounts(ctx sdk.Context, process func(auth.Account) (stop bool)) } diff --git a/x/staking/types/hooks.go b/x/staking/types/hooks.go new file mode 100644 index 000000000000..83df7bc5af2d --- /dev/null +++ b/x/staking/types/hooks.go @@ -0,0 +1,64 @@ +package types + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// combine multiple staking hooks, all hook functions are run in array sequence +type MultiStakingHooks []sdk.StakingHooks + +func NewMultiStakingHooks(hooks ...sdk.StakingHooks) MultiStakingHooks { + return hooks +} + +// nolint +func (h MultiStakingHooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) { + for i := range h { + h[i].AfterValidatorCreated(ctx, valAddr) + } +} +func (h MultiStakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) { + for i := range h { + h[i].BeforeValidatorModified(ctx, valAddr) + } +} +func (h MultiStakingHooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].AfterValidatorRemoved(ctx, consAddr, valAddr) + } +} +func (h MultiStakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].AfterValidatorBonded(ctx, consAddr, valAddr) + } +} +func (h MultiStakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].AfterValidatorBeginUnbonding(ctx, consAddr, valAddr) + } +} +func (h MultiStakingHooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].BeforeDelegationCreated(ctx, delAddr, valAddr) + } +} +func (h MultiStakingHooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].BeforeDelegationSharesModified(ctx, delAddr, valAddr) + } +} +func (h MultiStakingHooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].BeforeDelegationRemoved(ctx, delAddr, valAddr) + } +} +func (h MultiStakingHooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) { + for i := range h { + h[i].AfterDelegationModified(ctx, delAddr, valAddr) + } +} +func (h MultiStakingHooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) { + for i := range h { + h[i].BeforeValidatorSlashed(ctx, valAddr, fraction) + } +} diff --git a/x/staking/types/msg.go b/x/staking/types/msg.go index 9bf839fa2443..0114324c74bd 100644 --- a/x/staking/types/msg.go +++ b/x/staking/types/msg.go @@ -114,7 +114,7 @@ func (msg *MsgCreateValidator) UnmarshalJSON(bz []byte) error { // GetSignBytes returns the message bytes to sign over. func (msg MsgCreateValidator) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -181,7 +181,7 @@ func (msg MsgEditValidator) GetSigners() []sdk.AccAddress { // get the bytes for the message signer to sign on func (msg MsgEditValidator) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -232,7 +232,7 @@ func (msg MsgDelegate) GetSigners() []sdk.AccAddress { // get the bytes for the message signer to sign on func (msg MsgDelegate) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -280,7 +280,7 @@ func (msg MsgBeginRedelegate) GetSigners() []sdk.AccAddress { // get the bytes for the message signer to sign on func (msg MsgBeginRedelegate) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } @@ -323,7 +323,7 @@ func (msg MsgUndelegate) GetSigners() []sdk.AccAddress { return []sdk.AccAddress // get the bytes for the message signer to sign on func (msg MsgUndelegate) GetSignBytes() []byte { - bz := MsgCdc.MustMarshalJSON(msg) + bz := ModuleCdc.MustMarshalJSON(msg) return sdk.MustSortJSON(bz) } diff --git a/x/staking/types/params.go b/x/staking/types/params.go index 3239bdc25da7..c0f0e636275e 100644 --- a/x/staking/types/params.go +++ b/x/staking/types/params.go @@ -66,8 +66,8 @@ func (p *Params) ParamSetPairs() params.ParamSetPairs { // Equal returns a boolean determining if two Param types are identical. // TODO: This is slower than comparing struct fields directly 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) } diff --git a/x/staking/types/pool.go b/x/staking/types/pool.go index d3905085a6c7..6ab2f17cdb53 100644 --- a/x/staking/types/pool.go +++ b/x/staking/types/pool.go @@ -17,8 +17,8 @@ type Pool struct { // nolint // TODO: This is slower than comparing struct fields directly func (p Pool) Equal(p2 Pool) bool { - bz1 := MsgCdc.MustMarshalBinaryLengthPrefixed(&p) - bz2 := MsgCdc.MustMarshalBinaryLengthPrefixed(&p2) + bz1 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p) + bz2 := ModuleCdc.MustMarshalBinaryLengthPrefixed(&p2) return bytes.Equal(bz1, bz2) }