Merge PR #4159: Module/Genesis Generalization
* first commit * gaia cleanup * ... * staking multihooks * missing module function return args * bank module name constant * working, module interface for x/ * got this thing compiling * make test compiles and passes * remove expanded simulation invariants * genesis issue * continued * continued * register crisis routes thought mm * begin blocker to mm * end blocker to mm * empty routes not initialized * move gaia initChainer sanity check to baseapp * remove codecs from module manager * reorging genesis stuff * module manager passed by reference/bugfixes from working last commit int int * move invariant checks from gaia to crisis * typo * basic refactors cmd/gaia/init * working * MultiStakingHooks from types to x/staking/types int * default module manager order of operations from input modules * working * typo * add AppModuleBasic * moduleBasicManager / non-test code compiles * working attempting to get tests passing * make test passes * sim random genesis fix * export bug * ... * genutil module * genutil working * refactored - happy with non-testing code in cmd/ * ... * lint fixes * comment improvement * cli test fix * compile housing * working through compile errors * working gettin' compilin' * non-test code compiles * move testnet to its own module * reworking tests int * bez staging PR 1 comments * concise module function-of names * moved all tests from genesis_test.go to other genutil tests * genaccounts package, add genutil and genaccounts to app.go * docs for genutil genaccounts * genaccounts iterate fn * non-test code with genaccounts/ now compiles * working test compiling * debugging tests * resolved all make test compile errors * test debuggin * resolved all unit tests, introduced param module * cli-test compile fixes * staking initialization bug * code comment improvements, changelog entries * BasicGaiaApp -> ModuleBasics * highlevel explanation in types/module.go * @alexanderbez comment revisions * @fedekunze PR comments * @alexanderbez PR comments (x2) * @cwgoes comments (minor updates) * @fedekunze suggestions * panic on init with multiple validator updates from different modules * initchain panic makes validate genesis fail int * AppModuleGenesis seperation int * test * remove init panic logic in validate genesis replaced with TODO * set maxprocs to match system's GOMAXPROCS * Update circleci * Cap maxprocs in CI to 4 * @alexanderbez recent comments addressed * less blocks in twouble sims int * runsim error output flag * -e on import_export as well * error out int * Try to fix failures * runsim
This commit is contained in:
parent
f8fd50a0d8
commit
3fe5869148
|
@ -0,0 +1 @@
|
|||
#4159 use module pattern and module manager for initialization
|
|
@ -0,0 +1 @@
|
|||
#4159 create the default module patterns and module manager
|
4
Makefile
4
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..."
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"sort"
|
||||
|
||||
bam "github.com/cosmos/cosmos-sdk/baseapp"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/version"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/params"
|
||||
|
@ -26,15 +26,45 @@ import (
|
|||
"github.com/tendermint/tendermint/libs/log"
|
||||
)
|
||||
|
||||
const (
|
||||
appName = "GaiaApp"
|
||||
const appName = "GaiaApp"
|
||||
|
||||
var (
|
||||
// default home directories for gaiacli
|
||||
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
|
||||
|
||||
// default home directories for gaiad
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
|
||||
|
||||
// The ModuleBasicManager is in charge of setting up basic,
|
||||
// non-dependant module elements, such as codec registration
|
||||
// and genesis verification.
|
||||
ModuleBasics sdk.ModuleBasicManager
|
||||
)
|
||||
|
||||
// default home directories for expected binaries
|
||||
var (
|
||||
DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli")
|
||||
DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad")
|
||||
)
|
||||
func init() {
|
||||
ModuleBasics = sdk.NewModuleBasicManager(
|
||||
genaccounts.AppModuleBasic{},
|
||||
genutil.AppModuleBasic{},
|
||||
auth.AppModuleBasic{},
|
||||
bank.AppModuleBasic{},
|
||||
staking.AppModuleBasic{},
|
||||
mint.AppModuleBasic{},
|
||||
distr.AppModuleBasic{},
|
||||
gov.AppModuleBasic{},
|
||||
params.AppModuleBasic{},
|
||||
crisis.AppModuleBasic{},
|
||||
slashing.AppModuleBasic{},
|
||||
)
|
||||
}
|
||||
|
||||
// custom tx codec
|
||||
func MakeCodec() *codec.Codec {
|
||||
var cdc = codec.New()
|
||||
ModuleBasics.RegisterCodec(cdc)
|
||||
sdk.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
return cdc
|
||||
}
|
||||
|
||||
// Extended ABCI application
|
||||
type GaiaApp struct {
|
||||
|
@ -57,7 +87,7 @@ type GaiaApp struct {
|
|||
keyParams *sdk.KVStoreKey
|
||||
tkeyParams *sdk.TransientStoreKey
|
||||
|
||||
// Manage getting and setting accounts
|
||||
// keepers
|
||||
accountKeeper auth.AccountKeeper
|
||||
feeCollectionKeeper auth.FeeCollectionKeeper
|
||||
bankKeeper bank.Keeper
|
||||
|
@ -68,12 +98,14 @@ type GaiaApp struct {
|
|||
govKeeper gov.Keeper
|
||||
crisisKeeper crisis.Keeper
|
||||
paramsKeeper params.Keeper
|
||||
|
||||
// the module manager
|
||||
mm *sdk.ModuleManager
|
||||
}
|
||||
|
||||
// NewGaiaApp returns a reference to an initialized GaiaApp.
|
||||
func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest bool,
|
||||
invCheckPeriod uint,
|
||||
baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
|
||||
invCheckPeriod uint, baseAppOptions ...func(*bam.BaseApp)) *GaiaApp {
|
||||
|
||||
cdc := MakeCodec()
|
||||
|
||||
|
@ -99,103 +131,79 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
|||
tkeyParams: sdk.NewTransientStoreKey(params.TStoreKey),
|
||||
}
|
||||
|
||||
// init params keeper and subspaces
|
||||
app.paramsKeeper = params.NewKeeper(app.cdc, app.keyParams, app.tkeyParams, params.DefaultCodespace)
|
||||
authSubspace := app.paramsKeeper.Subspace(auth.DefaultParamspace)
|
||||
bankSubspace := app.paramsKeeper.Subspace(bank.DefaultParamspace)
|
||||
stakingSubspace := app.paramsKeeper.Subspace(staking.DefaultParamspace)
|
||||
mintSubspace := app.paramsKeeper.Subspace(mint.DefaultParamspace)
|
||||
distrSubspace := app.paramsKeeper.Subspace(distr.DefaultParamspace)
|
||||
slashingSubspace := app.paramsKeeper.Subspace(slashing.DefaultParamspace)
|
||||
govSubspace := app.paramsKeeper.Subspace(gov.DefaultParamspace)
|
||||
crisisSubspace := app.paramsKeeper.Subspace(crisis.DefaultParamspace)
|
||||
|
||||
// define the accountKeeper
|
||||
app.accountKeeper = auth.NewAccountKeeper(
|
||||
app.cdc,
|
||||
app.keyAccount,
|
||||
app.paramsKeeper.Subspace(auth.DefaultParamspace),
|
||||
auth.ProtoBaseAccount,
|
||||
)
|
||||
|
||||
// add handlers
|
||||
app.bankKeeper = bank.NewBaseKeeper(
|
||||
app.accountKeeper,
|
||||
app.paramsKeeper.Subspace(bank.DefaultParamspace),
|
||||
bank.DefaultCodespace,
|
||||
)
|
||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(
|
||||
app.cdc,
|
||||
app.keyFeeCollection,
|
||||
)
|
||||
stakingKeeper := staking.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyStaking, app.tkeyStaking,
|
||||
app.bankKeeper, app.paramsKeeper.Subspace(staking.DefaultParamspace),
|
||||
staking.DefaultCodespace,
|
||||
)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint,
|
||||
app.paramsKeeper.Subspace(mint.DefaultParamspace),
|
||||
&stakingKeeper, app.feeCollectionKeeper,
|
||||
)
|
||||
app.distrKeeper = distr.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyDistr,
|
||||
app.paramsKeeper.Subspace(distr.DefaultParamspace),
|
||||
app.bankKeeper, &stakingKeeper, app.feeCollectionKeeper,
|
||||
distr.DefaultCodespace,
|
||||
)
|
||||
app.slashingKeeper = slashing.NewKeeper(
|
||||
app.cdc,
|
||||
app.keySlashing,
|
||||
&stakingKeeper, app.paramsKeeper.Subspace(slashing.DefaultParamspace),
|
||||
slashing.DefaultCodespace,
|
||||
)
|
||||
// add keepers
|
||||
app.accountKeeper = auth.NewAccountKeeper(app.cdc, app.keyAccount, authSubspace, auth.ProtoBaseAccount)
|
||||
app.bankKeeper = bank.NewBaseKeeper(app.accountKeeper, bankSubspace, bank.DefaultCodespace)
|
||||
app.feeCollectionKeeper = auth.NewFeeCollectionKeeper(app.cdc, app.keyFeeCollection)
|
||||
stakingKeeper := staking.NewKeeper(app.cdc, app.keyStaking, app.tkeyStaking, app.bankKeeper,
|
||||
stakingSubspace, staking.DefaultCodespace)
|
||||
app.mintKeeper = mint.NewKeeper(app.cdc, app.keyMint, mintSubspace, &stakingKeeper, app.feeCollectionKeeper)
|
||||
app.distrKeeper = distr.NewKeeper(app.cdc, app.keyDistr, distrSubspace, app.bankKeeper, &stakingKeeper,
|
||||
app.feeCollectionKeeper, distr.DefaultCodespace)
|
||||
app.slashingKeeper = slashing.NewKeeper(app.cdc, app.keySlashing, &stakingKeeper,
|
||||
slashingSubspace, slashing.DefaultCodespace)
|
||||
app.crisisKeeper = crisis.NewKeeper(crisisSubspace, invCheckPeriod, app.distrKeeper,
|
||||
app.bankKeeper, app.feeCollectionKeeper)
|
||||
|
||||
// register the proposal types
|
||||
govRouter := gov.NewRouter()
|
||||
govRouter.AddRoute(gov.RouterKey, gov.ProposalHandler).
|
||||
AddRoute(params.RouterKey, params.NewParamChangeProposalHandler(app.paramsKeeper))
|
||||
|
||||
app.govKeeper = gov.NewKeeper(
|
||||
app.cdc,
|
||||
app.keyGov,
|
||||
app.paramsKeeper, app.paramsKeeper.Subspace(gov.DefaultParamspace), app.bankKeeper, &stakingKeeper,
|
||||
gov.DefaultCodespace,
|
||||
govRouter,
|
||||
)
|
||||
app.crisisKeeper = crisis.NewKeeper(
|
||||
app.paramsKeeper.Subspace(crisis.DefaultParamspace),
|
||||
app.distrKeeper,
|
||||
app.bankKeeper,
|
||||
app.feeCollectionKeeper,
|
||||
)
|
||||
app.govKeeper = gov.NewKeeper(app.cdc, app.keyGov, app.paramsKeeper, govSubspace,
|
||||
app.bankKeeper, &stakingKeeper, gov.DefaultCodespace, govRouter)
|
||||
|
||||
// register the staking hooks
|
||||
// NOTE: The stakingKeeper above is passed by reference, so that it can be
|
||||
// modified like below:
|
||||
// NOTE: stakingKeeper above is passed by reference, so that it will contain these hooks
|
||||
app.stakingKeeper = *stakingKeeper.SetHooks(
|
||||
NewStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()),
|
||||
staking.NewMultiStakingHooks(app.distrKeeper.Hooks(), app.slashingKeeper.Hooks()))
|
||||
|
||||
app.mm = sdk.NewModuleManager(
|
||||
genaccounts.NewAppModule(app.accountKeeper),
|
||||
genutil.NewAppModule(app.accountKeeper, app.stakingKeeper, app.BaseApp.DeliverTx),
|
||||
auth.NewAppModule(app.accountKeeper, app.feeCollectionKeeper),
|
||||
bank.NewAppModule(app.bankKeeper, app.accountKeeper),
|
||||
crisis.NewAppModule(app.crisisKeeper, app.Logger()),
|
||||
distr.NewAppModule(app.distrKeeper),
|
||||
gov.NewAppModule(app.govKeeper),
|
||||
mint.NewAppModule(app.mintKeeper),
|
||||
slashing.NewAppModule(app.slashingKeeper, app.stakingKeeper),
|
||||
staking.NewAppModule(app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper),
|
||||
)
|
||||
|
||||
// register the crisis routes
|
||||
bank.RegisterInvariants(&app.crisisKeeper, app.accountKeeper)
|
||||
distr.RegisterInvariants(&app.crisisKeeper, app.distrKeeper, app.stakingKeeper)
|
||||
staking.RegisterInvariants(&app.crisisKeeper, app.stakingKeeper, app.feeCollectionKeeper, app.distrKeeper, app.accountKeeper)
|
||||
// During begin block slashing happens after distr.BeginBlocker so that
|
||||
// there is nothing left over in the validator fee pool, so as to keep the
|
||||
// CanWithdrawInvariant invariant.
|
||||
app.mm.SetOrderBeginBlockers(mint.ModuleName, distr.ModuleName, slashing.ModuleName)
|
||||
|
||||
// register message routes
|
||||
app.Router().
|
||||
AddRoute(bank.RouterKey, bank.NewHandler(app.bankKeeper)).
|
||||
AddRoute(staking.RouterKey, staking.NewHandler(app.stakingKeeper)).
|
||||
AddRoute(distr.RouterKey, distr.NewHandler(app.distrKeeper)).
|
||||
AddRoute(slashing.RouterKey, slashing.NewHandler(app.slashingKeeper)).
|
||||
AddRoute(gov.RouterKey, gov.NewHandler(app.govKeeper)).
|
||||
AddRoute(crisis.RouterKey, crisis.NewHandler(app.crisisKeeper))
|
||||
app.mm.SetOrderEndBlockers(gov.ModuleName, staking.ModuleName)
|
||||
|
||||
app.QueryRouter().
|
||||
AddRoute(auth.QuerierRoute, auth.NewQuerier(app.accountKeeper)).
|
||||
AddRoute(distr.QuerierRoute, distr.NewQuerier(app.distrKeeper)).
|
||||
AddRoute(gov.QuerierRoute, gov.NewQuerier(app.govKeeper)).
|
||||
AddRoute(slashing.QuerierRoute, slashing.NewQuerier(app.slashingKeeper, app.cdc)).
|
||||
AddRoute(staking.QuerierRoute, staking.NewQuerier(app.stakingKeeper, app.cdc)).
|
||||
AddRoute(mint.QuerierRoute, mint.NewQuerier(app.mintKeeper))
|
||||
// genutils must occur after staking so that pools are properly
|
||||
// initialized with tokens from genesis accounts.
|
||||
app.mm.SetOrderInitGenesis(genaccounts.ModuleName, distr.ModuleName,
|
||||
staking.ModuleName, auth.ModuleName, bank.ModuleName, slashing.ModuleName,
|
||||
gov.ModuleName, mint.ModuleName, crisis.ModuleName, genutil.ModuleName)
|
||||
|
||||
app.mm.RegisterInvariants(&app.crisisKeeper)
|
||||
app.mm.RegisterRoutes(app.Router(), app.QueryRouter())
|
||||
|
||||
// initialize stores
|
||||
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint,
|
||||
app.keyDistr, app.keySlashing, app.keyGov, app.keyFeeCollection,
|
||||
app.keyParams, app.tkeyParams, app.tkeyStaking, app.tkeyDistr)
|
||||
|
||||
// initialize BaseApp
|
||||
app.MountStores(app.keyMain, app.keyAccount, app.keyStaking, app.keyMint, app.keyDistr,
|
||||
app.keySlashing, app.keyGov, app.keyFeeCollection, app.keyParams,
|
||||
app.tkeyParams, app.tkeyStaking, app.tkeyDistr,
|
||||
)
|
||||
app.SetInitChainer(app.initChainer)
|
||||
app.SetInitChainer(app.InitChainer)
|
||||
app.SetBeginBlocker(app.BeginBlocker)
|
||||
app.SetAnteHandler(auth.NewAnteHandler(app.accountKeeper, app.feeCollectionKeeper, auth.DefaultSigVerificationGasConsumer))
|
||||
app.SetEndBlocker(app.EndBlocker)
|
||||
|
@ -206,210 +214,27 @@ func NewGaiaApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
|
|||
cmn.Exit(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
// custom tx codec
|
||||
func MakeCodec() *codec.Codec {
|
||||
var cdc = codec.New()
|
||||
bank.RegisterCodec(cdc)
|
||||
staking.RegisterCodec(cdc)
|
||||
distr.RegisterCodec(cdc)
|
||||
slashing.RegisterCodec(cdc)
|
||||
params.RegisterCodec(cdc)
|
||||
gov.RegisterCodec(cdc)
|
||||
auth.RegisterCodec(cdc)
|
||||
crisis.RegisterCodec(cdc)
|
||||
sdk.RegisterCodec(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
return cdc
|
||||
}
|
||||
|
||||
// application updates every end block
|
||||
// application updates every begin block
|
||||
func (app *GaiaApp) BeginBlocker(ctx sdk.Context, req abci.RequestBeginBlock) abci.ResponseBeginBlock {
|
||||
// mint new tokens for the previous block
|
||||
mint.BeginBlocker(ctx, app.mintKeeper)
|
||||
|
||||
// distribute rewards for the previous block
|
||||
distr.BeginBlocker(ctx, req, app.distrKeeper)
|
||||
|
||||
// slash anyone who double signed.
|
||||
// NOTE: This should happen after distr.BeginBlocker so that
|
||||
// there is nothing left over in the validator fee pool,
|
||||
// so as to keep the CanWithdrawInvariant invariant.
|
||||
// TODO: This should really happen at EndBlocker.
|
||||
tags := slashing.BeginBlocker(ctx, req, app.slashingKeeper)
|
||||
|
||||
return abci.ResponseBeginBlock{
|
||||
Tags: tags.ToKVPairs(),
|
||||
}
|
||||
return app.mm.BeginBlock(ctx, req)
|
||||
}
|
||||
|
||||
// application updates every end block
|
||||
// nolint: unparam
|
||||
func (app *GaiaApp) EndBlocker(ctx sdk.Context, req abci.RequestEndBlock) abci.ResponseEndBlock {
|
||||
tags := gov.EndBlocker(ctx, app.govKeeper)
|
||||
validatorUpdates, endBlockerTags := staking.EndBlocker(ctx, app.stakingKeeper)
|
||||
tags = append(tags, endBlockerTags...)
|
||||
|
||||
if app.invCheckPeriod != 0 && ctx.BlockHeight()%int64(app.invCheckPeriod) == 0 {
|
||||
app.assertRuntimeInvariants()
|
||||
}
|
||||
|
||||
return abci.ResponseEndBlock{
|
||||
ValidatorUpdates: validatorUpdates,
|
||||
Tags: tags,
|
||||
}
|
||||
return app.mm.EndBlock(ctx, req)
|
||||
}
|
||||
|
||||
// initialize store from a genesis state
|
||||
func (app *GaiaApp) initFromGenesisState(ctx sdk.Context, genesisState GenesisState) []abci.ValidatorUpdate {
|
||||
genesisState.Sanitize()
|
||||
|
||||
// load the accounts
|
||||
for _, gacc := range genesisState.Accounts {
|
||||
acc := gacc.ToAccount()
|
||||
acc = app.accountKeeper.NewAccount(ctx, acc) // set account number
|
||||
app.accountKeeper.SetAccount(ctx, acc)
|
||||
}
|
||||
|
||||
// initialize distribution (must happen before staking)
|
||||
distr.InitGenesis(ctx, app.distrKeeper, genesisState.DistrData)
|
||||
|
||||
// load the initial staking information
|
||||
validators, err := staking.InitGenesis(ctx, app.stakingKeeper, genesisState.StakingData)
|
||||
if err != nil {
|
||||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
// initialize module-specific stores
|
||||
auth.InitGenesis(ctx, app.accountKeeper, app.feeCollectionKeeper, genesisState.AuthData)
|
||||
bank.InitGenesis(ctx, app.bankKeeper, genesisState.BankData)
|
||||
slashing.InitGenesis(ctx, app.slashingKeeper, genesisState.SlashingData, genesisState.StakingData.Validators.ToSDKValidators())
|
||||
gov.InitGenesis(ctx, app.govKeeper, genesisState.GovData)
|
||||
crisis.InitGenesis(ctx, app.crisisKeeper, genesisState.CrisisData)
|
||||
mint.InitGenesis(ctx, app.mintKeeper, genesisState.MintData)
|
||||
|
||||
// validate genesis state
|
||||
if err := GaiaValidateGenesisState(genesisState); err != nil {
|
||||
panic(err) // TODO find a way to do this w/o panics
|
||||
}
|
||||
|
||||
if len(genesisState.GenTxs) > 0 {
|
||||
for _, genTx := range genesisState.GenTxs {
|
||||
var tx auth.StdTx
|
||||
err = app.cdc.UnmarshalJSON(genTx, &tx)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
bz := app.cdc.MustMarshalBinaryLengthPrefixed(tx)
|
||||
res := app.BaseApp.DeliverTx(bz)
|
||||
if !res.IsOK() {
|
||||
panic(res.Log)
|
||||
}
|
||||
}
|
||||
|
||||
validators = app.stakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx)
|
||||
}
|
||||
return validators
|
||||
}
|
||||
|
||||
// custom logic for gaia initialization
|
||||
func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
stateJSON := req.AppStateBytes
|
||||
// TODO is this now the whole genesis file?
|
||||
|
||||
// application update at chain initialization
|
||||
func (app *GaiaApp) InitChainer(ctx sdk.Context, req abci.RequestInitChain) abci.ResponseInitChain {
|
||||
var genesisState GenesisState
|
||||
err := app.cdc.UnmarshalJSON(stateJSON, &genesisState)
|
||||
if err != nil {
|
||||
panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468
|
||||
// return sdk.ErrGenesisParse("").TraceCause(err, "")
|
||||
}
|
||||
|
||||
validators := app.initFromGenesisState(ctx, genesisState)
|
||||
|
||||
// sanity check
|
||||
if len(req.Validators) > 0 {
|
||||
if len(req.Validators) != len(validators) {
|
||||
panic(fmt.Errorf("len(RequestInitChain.Validators) != len(validators) (%d != %d)",
|
||||
len(req.Validators), len(validators)))
|
||||
}
|
||||
sort.Sort(abci.ValidatorUpdates(req.Validators))
|
||||
sort.Sort(abci.ValidatorUpdates(validators))
|
||||
for i, val := range validators {
|
||||
if !val.Equal(req.Validators[i]) {
|
||||
panic(fmt.Errorf("validators[%d] != req.Validators[%d] ", i, i))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// assert runtime invariants
|
||||
app.assertRuntimeInvariants()
|
||||
|
||||
return abci.ResponseInitChain{
|
||||
Validators: validators,
|
||||
}
|
||||
app.cdc.MustUnmarshalJSON(req.AppStateBytes, &genesisState)
|
||||
return app.mm.InitGenesis(ctx, genesisState)
|
||||
}
|
||||
|
||||
// load a particular height
|
||||
func (app *GaiaApp) LoadHeight(height int64) error {
|
||||
return app.LoadVersion(height, app.keyMain)
|
||||
}
|
||||
|
||||
// ______________________________________________________________________________________________
|
||||
|
||||
var _ sdk.StakingHooks = StakingHooks{}
|
||||
|
||||
// StakingHooks contains combined distribution and slashing hooks needed for the
|
||||
// staking module.
|
||||
type StakingHooks struct {
|
||||
dh distr.Hooks
|
||||
sh slashing.Hooks
|
||||
}
|
||||
|
||||
func NewStakingHooks(dh distr.Hooks, sh slashing.Hooks) StakingHooks {
|
||||
return StakingHooks{dh, sh}
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (h StakingHooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.AfterValidatorCreated(ctx, valAddr)
|
||||
h.sh.AfterValidatorCreated(ctx, valAddr)
|
||||
}
|
||||
func (h StakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
|
||||
h.dh.BeforeValidatorModified(ctx, valAddr)
|
||||
h.sh.BeforeValidatorModified(ctx, valAddr)
|
||||
}
|
||||
func (h StakingHooks) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.AfterValidatorRemoved(ctx, consAddr, valAddr)
|
||||
h.sh.AfterValidatorRemoved(ctx, consAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.AfterValidatorBonded(ctx, consAddr, valAddr)
|
||||
h.sh.AfterValidatorBonded(ctx, consAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
|
||||
h.sh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) BeforeDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.BeforeDelegationCreated(ctx, delAddr, valAddr)
|
||||
h.sh.BeforeDelegationCreated(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) BeforeDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
h.sh.BeforeDelegationSharesModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) BeforeDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
|
||||
h.sh.BeforeDelegationRemoved(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) AfterDelegationModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
|
||||
h.dh.AfterDelegationModified(ctx, delAddr, valAddr)
|
||||
h.sh.AfterDelegationModified(ctx, delAddr, valAddr)
|
||||
}
|
||||
func (h StakingHooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {
|
||||
h.dh.BeforeValidatorSlashed(ctx, valAddr, fraction)
|
||||
h.sh.BeforeValidatorSlashed(ctx, valAddr, fraction)
|
||||
}
|
||||
|
|
|
@ -4,55 +4,15 @@ import (
|
|||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/x/bank"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
|
||||
"github.com/stretchr/testify/require"
|
||||
"github.com/tendermint/tendermint/libs/db"
|
||||
"github.com/tendermint/tendermint/libs/log"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
"github.com/cosmos/cosmos-sdk/x/slashing"
|
||||
"github.com/cosmos/cosmos-sdk/x/staking"
|
||||
|
||||
abci "github.com/tendermint/tendermint/abci/types"
|
||||
)
|
||||
|
||||
func setGenesis(gapp *GaiaApp, accs ...*auth.BaseAccount) error {
|
||||
genaccs := make([]GenesisAccount, len(accs))
|
||||
for i, acc := range accs {
|
||||
genaccs[i] = NewGenesisAccount(acc)
|
||||
}
|
||||
|
||||
genesisState := NewGenesisState(
|
||||
genaccs,
|
||||
auth.DefaultGenesisState(),
|
||||
bank.DefaultGenesisState(),
|
||||
staking.DefaultGenesisState(),
|
||||
mint.DefaultGenesisState(),
|
||||
distr.DefaultGenesisState(),
|
||||
gov.DefaultGenesisState(),
|
||||
crisis.DefaultGenesisState(),
|
||||
slashing.DefaultGenesisState(),
|
||||
)
|
||||
|
||||
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
vals := []abci.ValidatorUpdate{}
|
||||
gapp.InitChain(abci.RequestInitChain{Validators: vals, AppStateBytes: stateBytes})
|
||||
gapp.Commit()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func TestGaiadExport(t *testing.T) {
|
||||
db := db.NewMemDB()
|
||||
gapp := NewGaiaApp(log.NewTMLogger(log.NewSyncWriter(os.Stdout)), db, nil, true, 0)
|
||||
|
@ -63,3 +23,22 @@ func TestGaiadExport(t *testing.T) {
|
|||
_, _, err := newGapp.ExportAppStateAndValidators(false, []string{})
|
||||
require.NoError(t, err, "ExportAppStateAndValidators should not have an error")
|
||||
}
|
||||
|
||||
func setGenesis(gapp *GaiaApp) error {
|
||||
|
||||
genesisState := NewDefaultGenesisState()
|
||||
stateBytes, err := codec.MarshalJSONIndent(gapp.cdc, genesisState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Initialize the chain
|
||||
gapp.InitChain(
|
||||
abci.RequestInitChain{
|
||||
Validators: []abci.ValidatorUpdate{},
|
||||
AppStateBytes: stateBytes,
|
||||
},
|
||||
)
|
||||
gapp.Commit()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -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{})
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
```
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -2,7 +2,6 @@ package lcd_test
|
|||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net"
|
||||
|
@ -16,19 +15,17 @@ import (
|
|||
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stretchr/testify/require"
|
||||
amino "github.com/tendermint/go-amino"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client"
|
||||
clientkeys "github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/client/lcd"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/rpc"
|
||||
"github.com/cosmos/cosmos-sdk/client/tx"
|
||||
clienttx "github.com/cosmos/cosmos-sdk/client/tx"
|
||||
"github.com/cosmos/cosmos-sdk/client/utils"
|
||||
gapp "github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
crkeys "github.com/cosmos/cosmos-sdk/crypto/keys"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
"github.com/cosmos/cosmos-sdk/tests"
|
||||
|
@ -37,12 +34,16 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest"
|
||||
txbuilder "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
bankrest "github.com/cosmos/cosmos-sdk/x/bank/client/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/crisis"
|
||||
distr "github.com/cosmos/cosmos-sdk/x/distribution"
|
||||
distrrest "github.com/cosmos/cosmos-sdk/x/distribution/client/rest"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
"github.com/cosmos/cosmos-sdk/x/gov"
|
||||
govrest "github.com/cosmos/cosmos-sdk/x/gov/client/rest"
|
||||
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
|
||||
"github.com/cosmos/cosmos-sdk/x/mint"
|
||||
mintrest "github.com/cosmos/cosmos-sdk/x/mint/client/rest"
|
||||
paramsrest "github.com/cosmos/cosmos-sdk/x/params/client/rest"
|
||||
paramscutils "github.com/cosmos/cosmos-sdk/x/params/client/utils"
|
||||
|
@ -68,10 +69,10 @@ import (
|
|||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
)
|
||||
|
||||
var cdc = amino.NewCodec()
|
||||
var cdc = codec.New()
|
||||
|
||||
func init() {
|
||||
ctypes.RegisterAmino(cdc)
|
||||
codec.RegisterCrypto(cdc)
|
||||
}
|
||||
|
||||
// makePathname creates a unique pathname for each test. It will panic if it
|
||||
|
@ -238,10 +239,10 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
|||
require.Nil(t, err)
|
||||
genDoc.Validators = nil
|
||||
require.NoError(t, genDoc.SaveAs(genesisFile))
|
||||
genTxs := []json.RawMessage{}
|
||||
|
||||
// append any additional (non-proposing) validators
|
||||
var accs []gapp.GenesisAccount
|
||||
var genTxs []auth.StdTx
|
||||
var accs []genaccounts.GenesisAccount
|
||||
for i := 0; i < nValidators; i++ {
|
||||
operPrivKey := secp256k1.GenPrivKey()
|
||||
operAddr := operPrivKey.PubKey().Address()
|
||||
|
@ -268,61 +269,80 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
|||
}
|
||||
sig, err := operPrivKey.Sign(stdSignMsg.Bytes())
|
||||
require.Nil(t, err)
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
|
||||
txBytes, err := cdc.MarshalJSON(tx)
|
||||
require.Nil(t, err)
|
||||
|
||||
genTxs = append(genTxs, txBytes)
|
||||
tx := auth.NewStdTx([]sdk.Msg{msg}, auth.StdFee{}, []auth.StdSignature{{Signature: sig, PubKey: operPrivKey.PubKey()}}, "")
|
||||
genTxs = append(genTxs, tx)
|
||||
|
||||
valConsPubKeys = append(valConsPubKeys, pubKey)
|
||||
valOperAddrs = append(valOperAddrs, sdk.ValAddress(operAddr))
|
||||
|
||||
accAuth := auth.NewBaseAccountWithAddress(sdk.AccAddress(operAddr))
|
||||
accTokens := sdk.TokensFromTendermintPower(150)
|
||||
accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)}
|
||||
accs = append(accs, gapp.NewGenesisAccount(&accAuth))
|
||||
accs = append(accs, genaccounts.NewGenesisAccount(&accAuth))
|
||||
}
|
||||
|
||||
appGenState := gapp.NewDefaultGenesisState()
|
||||
appGenState.Accounts = accs
|
||||
genDoc.AppState, err = cdc.MarshalJSON(appGenState)
|
||||
genesisState := gapp.NewDefaultGenesisState()
|
||||
genDoc.AppState, err = cdc.MarshalJSON(genesisState)
|
||||
require.NoError(t, err)
|
||||
genesisState, err := gapp.GaiaAppGenState(cdc, *genDoc, genTxs)
|
||||
genesisState, err = genutil.SetGenTxsInAppGenesisState(cdc, genesisState, genTxs)
|
||||
require.NoError(t, err)
|
||||
|
||||
// add some tokens to init accounts
|
||||
stakingDataBz := genesisState[staking.ModuleName]
|
||||
var stakingData staking.GenesisState
|
||||
cdc.MustUnmarshalJSON(stakingDataBz, &stakingData)
|
||||
for _, addr := range initAddrs {
|
||||
accAuth := auth.NewBaseAccountWithAddress(addr)
|
||||
accTokens := sdk.TokensFromTendermintPower(100)
|
||||
accAuth.Coins = sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, accTokens)}
|
||||
acc := gapp.NewGenesisAccount(&accAuth)
|
||||
genesisState.Accounts = append(genesisState.Accounts, acc)
|
||||
genesisState.StakingData.Pool.NotBondedTokens = genesisState.StakingData.Pool.NotBondedTokens.Add(accTokens)
|
||||
acc := genaccounts.NewGenesisAccount(&accAuth)
|
||||
accs = append(accs, acc)
|
||||
}
|
||||
|
||||
// now add the account tokens to the non-bonded pool
|
||||
for _, acc := range accs {
|
||||
accTokens := acc.Coins.AmountOf(sdk.DefaultBondDenom)
|
||||
stakingData.Pool.NotBondedTokens = stakingData.Pool.NotBondedTokens.Add(accTokens)
|
||||
}
|
||||
stakingDataBz = cdc.MustMarshalJSON(stakingData)
|
||||
genesisState[staking.ModuleName] = stakingDataBz
|
||||
|
||||
genaccountsData := genaccounts.NewGenesisState(accs)
|
||||
genaccountsDataBz := cdc.MustMarshalJSON(genaccountsData)
|
||||
genesisState[genaccounts.ModuleName] = genaccountsDataBz
|
||||
|
||||
// mint genesis (none set within genesisState)
|
||||
mintData := mint.DefaultGenesisState()
|
||||
inflationMin := sdk.ZeroDec()
|
||||
if minting {
|
||||
inflationMin = sdk.MustNewDecFromStr("10000.0")
|
||||
genesisState.MintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
|
||||
mintData.Params.InflationMax = sdk.MustNewDecFromStr("15000.0")
|
||||
} else {
|
||||
genesisState.MintData.Params.InflationMax = inflationMin
|
||||
mintData.Params.InflationMax = inflationMin
|
||||
}
|
||||
genesisState.MintData.Minter.Inflation = inflationMin
|
||||
genesisState.MintData.Params.InflationMin = inflationMin
|
||||
mintData.Minter.Inflation = inflationMin
|
||||
mintData.Params.InflationMin = inflationMin
|
||||
mintDataBz := cdc.MustMarshalJSON(mintData)
|
||||
genesisState[mint.ModuleName] = mintDataBz
|
||||
|
||||
// initialize crisis data
|
||||
genesisState.CrisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
|
||||
crisisDataBz := genesisState[crisis.ModuleName]
|
||||
var crisisData crisis.GenesisState
|
||||
cdc.MustUnmarshalJSON(crisisDataBz, &crisisData)
|
||||
crisisData.ConstantFee = sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000)
|
||||
crisisDataBz = cdc.MustMarshalJSON(crisisData)
|
||||
genesisState[crisis.ModuleName] = crisisDataBz
|
||||
|
||||
// double check inflation is set according to the minting boolean flag
|
||||
if minting {
|
||||
require.Equal(t, sdk.MustNewDecFromStr("15000.0"),
|
||||
genesisState.MintData.Params.InflationMax)
|
||||
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), genesisState.MintData.Minter.Inflation)
|
||||
require.Equal(t, sdk.MustNewDecFromStr("10000.0"),
|
||||
genesisState.MintData.Params.InflationMin)
|
||||
require.Equal(t, sdk.MustNewDecFromStr("15000.0"), mintData.Params.InflationMax)
|
||||
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Minter.Inflation)
|
||||
require.Equal(t, sdk.MustNewDecFromStr("10000.0"), mintData.Params.InflationMin)
|
||||
} else {
|
||||
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Params.InflationMax)
|
||||
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Minter.Inflation)
|
||||
require.Equal(t, sdk.ZeroDec(), genesisState.MintData.Params.InflationMin)
|
||||
require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMax)
|
||||
require.Equal(t, sdk.ZeroDec(), mintData.Minter.Inflation)
|
||||
require.Equal(t, sdk.ZeroDec(), mintData.Params.InflationMin)
|
||||
}
|
||||
|
||||
appState, err := codec.MarshalJSONIndent(cdc, genesisState)
|
||||
|
@ -332,13 +352,13 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
|||
listenAddr, port, err := server.FreeTCPAddr()
|
||||
require.NoError(t, err)
|
||||
|
||||
// XXX: Need to set this so LCD knows the tendermint node address!
|
||||
// NOTE: Need to set this so LCD knows the tendermint node address!
|
||||
viper.Set(client.FlagNode, config.RPC.ListenAddress)
|
||||
viper.Set(client.FlagChainID, genDoc.ChainID)
|
||||
// TODO Set to false once the upstream Tendermint proof verification issue is fixed.
|
||||
viper.Set(client.FlagTrustNode, true)
|
||||
|
||||
node, err := startTM(config, logger, genDoc, privVal, app)
|
||||
node := startTM(t, config, logger, genDoc, privVal, app)
|
||||
require.NoError(t, err)
|
||||
|
||||
tests.WaitForNextHeightTM(tests.ExtractPortFromAddress(config.RPC.ListenAddress))
|
||||
|
@ -365,16 +385,15 @@ func InitializeTestLCD(t *testing.T, nValidators int, initAddrs []sdk.AccAddress
|
|||
//
|
||||
// TODO: Clean up the WAL dir or enable it to be not persistent!
|
||||
func startTM(
|
||||
tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc,
|
||||
t *testing.T, tmcfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc,
|
||||
privVal tmtypes.PrivValidator, app abci.Application,
|
||||
) (*nm.Node, error) {
|
||||
) *nm.Node {
|
||||
|
||||
genDocProvider := func() (*tmtypes.GenesisDoc, error) { return genDoc, nil }
|
||||
dbProvider := func(*nm.DBContext) (dbm.DB, error) { return dbm.NewMemDB(), nil }
|
||||
nodeKey, err := p2p.LoadOrGenNodeKey(tmcfg.NodeKeyFile())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
node, err := nm.NewNode(
|
||||
tmcfg,
|
||||
privVal,
|
||||
|
@ -385,19 +404,15 @@ func startTM(
|
|||
nm.DefaultMetricsProvider(tmcfg.Instrumentation),
|
||||
logger.With("module", "node"),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
err = node.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
require.NoError(t, err)
|
||||
|
||||
tests.WaitForRPC(tmcfg.RPC.ListenAddress)
|
||||
logger.Info("Tendermint running!")
|
||||
|
||||
return node, err
|
||||
return node
|
||||
}
|
||||
|
||||
// startLCD starts the LCD.
|
||||
|
@ -412,6 +427,7 @@ func startLCD(logger log.Logger, listenAddr string, cdc *codec.Codec, t *testing
|
|||
return listener, nil
|
||||
}
|
||||
|
||||
// TODO generalize this with the module basic manager
|
||||
// NOTE: If making updates here also update cmd/gaia/cmd/gaiacli/main.go
|
||||
func registerRoutes(rs *lcd.RestServer) {
|
||||
rpc.RegisterRoutes(rs.CliCtx, rs.Mux)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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..."
|
||||
|
|
|
@ -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).
|
|
@ -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
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package init
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
@ -6,15 +6,21 @@ import (
|
|||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/tendermint/tendermint/libs/cli"
|
||||
"github.com/tendermint/tendermint/libs/common"
|
||||
tmtypes "github.com/tendermint/tendermint/types"
|
||||
|
||||
"github.com/cosmos/cosmos-sdk/client/keys"
|
||||
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
|
||||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
"github.com/cosmos/cosmos-sdk/server"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth"
|
||||
"github.com/cosmos/cosmos-sdk/x/auth/genaccounts"
|
||||
"github.com/cosmos/cosmos-sdk/x/genutil"
|
||||
)
|
||||
|
||||
const (
|
||||
flagClientHome = "home-client"
|
||||
flagVestingStart = "vesting-start-time"
|
||||
flagVestingEnd = "vesting-end-time"
|
||||
flagVestingAmt = "vesting-amount"
|
||||
)
|
||||
|
||||
// AddGenesisAccountCmd returns add-genesis-account cobra Command.
|
||||
|
@ -54,33 +60,38 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
|
|||
return err
|
||||
}
|
||||
|
||||
genAcc := genaccounts.NewGenesisAccountRaw(addr, coins, vestingAmt, vestingStart, vestingEnd)
|
||||
if err := genAcc.Validate(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// retrieve the app state
|
||||
genFile := config.GenesisFile()
|
||||
if !common.FileExists(genFile) {
|
||||
return fmt.Errorf("%s does not exist, run `gaiad init` first", genFile)
|
||||
}
|
||||
|
||||
genDoc, err := tmtypes.GenesisDocFromFile(genFile)
|
||||
appState, genDoc, err := genutil.GenesisStateFromGenFile(cdc, genFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var appState app.GenesisState
|
||||
if err = cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil {
|
||||
return err
|
||||
// add genesis account to the app state
|
||||
var genesisState genaccounts.GenesisState
|
||||
cdc.MustUnmarshalJSON(appState[genaccounts.ModuleName], &genesisState)
|
||||
if genesisState.Accounts.Contains(addr) {
|
||||
return fmt.Errorf("cannot add account at existing address %v", addr)
|
||||
}
|
||||
genesisState.Accounts = append(genesisState.Accounts, genAcc)
|
||||
|
||||
appState, err = addGenesisAccount(cdc, appState, addr, coins, vestingAmt, vestingStart, vestingEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
genesisStateBz := cdc.MustMarshalJSON(genesisState)
|
||||
appState[genaccounts.ModuleName] = genesisStateBz
|
||||
|
||||
appStateJSON, err := cdc.MarshalJSON(appState)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// export app state
|
||||
genDoc.AppState = appStateJSON
|
||||
return ExportGenesisFile(genDoc, genFile)
|
||||
|
||||
return genutil.ExportGenesisFile(genDoc, genFile)
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -89,55 +100,5 @@ func AddGenesisAccountCmd(ctx *server.Context, cdc *codec.Codec) *cobra.Command
|
|||
cmd.Flags().String(flagVestingAmt, "", "amount of coins for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingStart, 0, "schedule start time (unix epoch) for vesting accounts")
|
||||
cmd.Flags().Uint64(flagVestingEnd, 0, "schedule end time (unix epoch) for vesting accounts")
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func addGenesisAccount(
|
||||
cdc *codec.Codec, appState app.GenesisState, addr sdk.AccAddress,
|
||||
coins, vestingAmt sdk.Coins, vestingStart, vestingEnd int64,
|
||||
) (app.GenesisState, error) {
|
||||
|
||||
for _, stateAcc := range appState.Accounts {
|
||||
if stateAcc.Address.Equals(addr) {
|
||||
return appState, fmt.Errorf("the application state already contains account %v", addr)
|
||||
}
|
||||
}
|
||||
|
||||
acc := auth.NewBaseAccountWithAddress(addr)
|
||||
acc.Coins = coins
|
||||
|
||||
if !vestingAmt.IsZero() {
|
||||
var vacc auth.VestingAccount
|
||||
|
||||
bvacc := &auth.BaseVestingAccount{
|
||||
BaseAccount: &acc,
|
||||
OriginalVesting: vestingAmt,
|
||||
EndTime: vestingEnd,
|
||||
}
|
||||
|
||||
if bvacc.OriginalVesting.IsAnyGT(acc.Coins) {
|
||||
return appState, fmt.Errorf("vesting amount cannot be greater than total amount")
|
||||
}
|
||||
if vestingStart >= vestingEnd {
|
||||
return appState, fmt.Errorf("vesting start time must before end time")
|
||||
}
|
||||
|
||||
if vestingStart != 0 {
|
||||
vacc = &auth.ContinuousVestingAccount{
|
||||
BaseVestingAccount: bvacc,
|
||||
StartTime: vestingStart,
|
||||
}
|
||||
} else {
|
||||
vacc = &auth.DelayedVestingAccount{
|
||||
BaseVestingAccount: bvacc,
|
||||
}
|
||||
}
|
||||
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccountI(vacc))
|
||||
} else {
|
||||
appState.Accounts = append(appState.Accounts, app.NewGenesisAccount(&acc))
|
||||
}
|
||||
|
||||
return appState, nil
|
||||
}
|
|
@ -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()
|
||||
}
|
|
@ -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
|
|
@ -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))
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()),
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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.
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
|
||||
const (
|
||||
// DefaultParamspace for params keeper
|
||||
DefaultParamspace = "bank"
|
||||
DefaultParamspace = ModuleName
|
||||
// DefaultSendEnabled enabled
|
||||
DefaultSendEnabled = true
|
||||
)
|
||||
|
|
|
@ -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)
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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) })
|
|
@ -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
|
||||
}
|
||||
|
|
@ -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()))
|
|
@ -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
|
||||
},
|
|
@ -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()
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
|
@ -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),
|
||||
)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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())
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package init
|
||||
package genutil
|
||||
|
||||
import (
|
||||
"encoding/json"
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
|
|
|
@ -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 (
|
||||
|
|
|
@ -4,9 +4,8 @@ import (
|
|||
"github.com/cosmos/cosmos-sdk/codec"
|
||||
)
|
||||
|
||||
var (
|
||||
msgCdc = codec.New()
|
||||
)
|
||||
// module codec
|
||||
var ModuleCdc = codec.New()
|
||||
|
||||
// RegisterCodec registers all the necessary types and interfaces for
|
||||
// governance.
|
||||
|
@ -22,12 +21,12 @@ func RegisterCodec(cdc *codec.Codec) {
|
|||
}
|
||||
|
||||
// RegisterProposalTypeCodec registers an external proposal content type defined
|
||||
// in another module for the internal msgCdc. This allows the MsgSubmitProposal
|
||||
// in another module for the internal ModuleCdc. This allows the MsgSubmitProposal
|
||||
// to be correctly Amino encoded and decoded.
|
||||
func RegisterProposalTypeCodec(o interface{}, name string) {
|
||||
msgCdc.RegisterConcrete(o, name, nil)
|
||||
ModuleCdc.RegisterConcrete(o, name, nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
RegisterCodec(msgCdc)
|
||||
RegisterCodec(ModuleCdc)
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue