diff --git a/server/v2/cometbft/go.mod b/server/v2/cometbft/go.mod index acaa2d7bcc2b..b047aee74234 100644 --- a/server/v2/cometbft/go.mod +++ b/server/v2/cometbft/go.mod @@ -24,7 +24,7 @@ require ( cosmossdk.io/errors v1.0.1 cosmossdk.io/log v1.4.0 cosmossdk.io/server/v2 v2.0.0-20240802142126-a26970e547ab // main - cosmossdk.io/server/v2/appmanager v0.0.0-20240731205446-aee9803a0af6 // main + cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c // main cosmossdk.io/store/v2 v2.0.0-20240731205446-aee9803a0af6 // main cosmossdk.io/x/consensus v0.0.0-00010101000000-000000000000 github.com/cometbft/cometbft v1.0.0-rc1 diff --git a/server/v2/cometbft/go.sum b/server/v2/cometbft/go.sum index 0e3a0ecb770e..03f6f807a240 100644 --- a/server/v2/cometbft/go.sum +++ b/server/v2/cometbft/go.sum @@ -26,8 +26,8 @@ cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA= cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= cosmossdk.io/server/v2 v2.0.0-20240802142126-a26970e547ab h1:6IGp/R/6D4NZT+MKIoM2OkmxZG4UFh32HgwN7mYynvk= cosmossdk.io/server/v2 v2.0.0-20240802142126-a26970e547ab/go.mod h1:alRmtz2gedZe+goFHbNjkBPNTkShFW6HEeXiyT7hdHM= -cosmossdk.io/server/v2/appmanager v0.0.0-20240731205446-aee9803a0af6 h1:vrHmVjfEjEwQh90dim272gYq7OFILg4Yrv3XzreMpe4= -cosmossdk.io/server/v2/appmanager v0.0.0-20240731205446-aee9803a0af6/go.mod h1:Xm5IOSjw45Sew7fiVckaTCIU5oQPs20V+54NOqR3H4o= +cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c h1:sxMoOFQvf5g1Wl1D2HidVtLpQhK1YCVq0YiDeT6qTNQ= +cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20= cosmossdk.io/store v1.0.0-rc.0.0.20240815194237-858ec2fcb897 h1:o024zaPHYtmUGL2BCX1ns9rfZmMc19U4hQ2CAPt2Xgg= cosmossdk.io/store v1.0.0-rc.0.0.20240815194237-858ec2fcb897/go.mod h1:Ma4uny4RFegWTbU71fBmkSIoHrWHlLC/JwwgWgehZm4= cosmossdk.io/store/v2 v2.0.0-20240731205446-aee9803a0af6 h1:/ffIfMKzoCVUI38t5Vq3BNW9U8exRMxK5QgS/ujn0lA= diff --git a/simapp/app.go b/simapp/app.go index 77cd0773eff3..db00b0fffa1e 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -50,7 +50,7 @@ import ( circuittypes "cosmossdk.io/x/circuit/types" "cosmossdk.io/x/consensus" consensusparamkeeper "cosmossdk.io/x/consensus/keeper" - consensusparamtypes "cosmossdk.io/x/consensus/types" + consensustypes "cosmossdk.io/x/consensus/types" distr "cosmossdk.io/x/distribution" distrkeeper "cosmossdk.io/x/distribution/keeper" distrtypes "cosmossdk.io/x/distribution/types" @@ -262,7 +262,7 @@ func NewSimApp( keys := storetypes.NewKVStoreKeys( authtypes.StoreKey, banktypes.StoreKey, stakingtypes.StoreKey, minttypes.StoreKey, distrtypes.StoreKey, slashingtypes.StoreKey, - govtypes.StoreKey, consensusparamtypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, + govtypes.StoreKey, consensustypes.StoreKey, upgradetypes.StoreKey, feegrant.StoreKey, evidencetypes.StoreKey, circuittypes.StoreKey, authzkeeper.StoreKey, nftkeeper.StoreKey, group.StoreKey, pooltypes.StoreKey, accounts.StoreKey, epochstypes.StoreKey, @@ -285,7 +285,7 @@ func NewSimApp( cometService := runtime.NewContextAwareCometInfoService() // set the BaseApp's parameter store - app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[consensusparamtypes.StoreKey]), logger.With(log.ModuleKey, "x/consensus")), authtypes.NewModuleAddress(govtypes.ModuleName).String()) + app.ConsensusParamsKeeper = consensusparamkeeper.NewKeeper(appCodec, runtime.NewEnvironment(runtime.NewKVStoreService(keys[consensustypes.StoreKey]), logger.With(log.ModuleKey, "x/consensus")), authtypes.NewModuleAddress(govtypes.ModuleName).String()) bApp.SetParamStore(app.ConsensusParamsKeeper.ParamsStore) // add keepers @@ -499,7 +499,7 @@ func NewSimApp( // properly initialized with tokens from genesis accounts. // NOTE: The genutils module must also occur after auth so that it can access the params from auth. genesisModuleOrder := []string{ - consensusparamtypes.ModuleName, + consensustypes.ModuleName, accounts.ModuleName, authtypes.ModuleName, banktypes.ModuleName, @@ -516,7 +516,7 @@ func NewSimApp( group.ModuleName, upgradetypes.ModuleName, vestingtypes.ModuleName, - consensusparamtypes.ModuleName, + consensustypes.ModuleName, circuittypes.ModuleName, pooltypes.ModuleName, epochstypes.ModuleName, diff --git a/simapp/v2/app_di.go b/simapp/v2/app_di.go index 7cde4042f3c8..4e87bcc305df 100644 --- a/simapp/v2/app_di.go +++ b/simapp/v2/app_di.go @@ -12,7 +12,6 @@ import ( "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/runtime/v2" - serverv2 "cosmossdk.io/server/v2" "cosmossdk.io/x/accounts" authkeeper "cosmossdk.io/x/auth/keeper" authzkeeper "cosmossdk.io/x/authz/keeper" @@ -92,7 +91,6 @@ func NewSimApp[T transaction.Tx]( logger log.Logger, viper *viper.Viper, ) *SimApp[T] { - viper.Set(serverv2.FlagHome, DefaultNodeHome) // TODO possibly set earlier when viper is created var ( app = &SimApp[T]{} appBuilder *runtime.AppBuilder[T] diff --git a/simapp/v2/app_test.go b/simapp/v2/app_test.go new file mode 100644 index 000000000000..a2ffdcee4ef5 --- /dev/null +++ b/simapp/v2/app_test.go @@ -0,0 +1,155 @@ +package simapp + +import ( + "context" + "crypto/sha256" + "encoding/json" + "testing" + "time" + + "github.com/cometbft/cometbft/types" + "github.com/spf13/viper" + "github.com/stretchr/testify/require" + + app2 "cosmossdk.io/core/app" + "cosmossdk.io/core/comet" + context2 "cosmossdk.io/core/context" + "cosmossdk.io/core/store" + "cosmossdk.io/core/transaction" + "cosmossdk.io/log" + sdkmath "cosmossdk.io/math" + serverv2 "cosmossdk.io/server/v2" + comettypes "cosmossdk.io/server/v2/cometbft/types" + "cosmossdk.io/store/v2/db" + authtypes "cosmossdk.io/x/auth/types" + banktypes "cosmossdk.io/x/bank/types" + + "github.com/cosmos/cosmos-sdk/crypto/keys/secp256k1" + "github.com/cosmos/cosmos-sdk/testutil/mock" + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func NewTestApp(t *testing.T) (*SimApp[transaction.Tx], context.Context) { + t.Helper() + + logger := log.NewTestLogger(t) + + vp := viper.New() + vp.Set("store.app-db-backend", string(db.DBTypeGoLevelDB)) + vp.Set(serverv2.FlagHome, t.TempDir()) + + app := NewSimApp[transaction.Tx](logger, vp) + genesis := app.ModuleManager().DefaultGenesis() + + privVal := mock.NewPV() + pubKey, err := privVal.GetPubKey() + require.NoError(t, err) + + // create validator set with single validator + validator := types.NewValidator(pubKey, 1) + valSet := types.NewValidatorSet([]*types.Validator{validator}) + + // generate genesis account + senderPrivKey := secp256k1.GenPrivKey() + acc := authtypes.NewBaseAccount(senderPrivKey.PubKey().Address().Bytes(), senderPrivKey.PubKey(), 0, 0) + balance := banktypes.Balance{ + Address: acc.GetAddress().String(), + Coins: sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdkmath.NewInt(100000000000000))), + } + + genesis, err = simtestutil.GenesisStateWithValSet( + app.AppCodec(), + genesis, + valSet, + []authtypes.GenesisAccount{acc}, + balance, + ) + require.NoError(t, err) + + genesisBytes, err := json.Marshal(genesis) + require.NoError(t, err) + + st := app.GetStore().(comettypes.Store) + ci, err := st.LastCommitID() + require.NoError(t, err) + + bz := sha256.Sum256([]byte{}) + + ctx := context.Background() + + _, newState, err := app.InitGenesis( + ctx, + &app2.BlockRequest[transaction.Tx]{ + Time: time.Now(), + Hash: bz[:], + ChainId: "theChain", + AppHash: ci.Hash, + IsGenesis: true, + }, + genesisBytes, + nil, + ) + require.NoError(t, err) + + changes, err := newState.GetStateChanges() + require.NoError(t, err) + + _, err = st.Commit(&store.Changeset{Changes: changes}) + require.NoError(t, err) + + return app, ctx +} + +func MoveNextBlock(t *testing.T, app *SimApp[transaction.Tx], ctx context.Context) { + t.Helper() + + bz := sha256.Sum256([]byte{}) + + st := app.GetStore().(comettypes.Store) + ci, err := st.LastCommitID() + require.NoError(t, err) + + height, err := app.LoadLatestHeight() + require.NoError(t, err) + + // TODO: this is a hack to set the comet info in the context for distribution module dependency. + ctx = context.WithValue(ctx, context2.CometInfoKey, comet.Info{ + Evidence: nil, + ValidatorsHash: nil, + ProposerAddress: nil, + LastCommit: comet.CommitInfo{}, + }) + + _, newState, err := app.DeliverBlock( + ctx, + &app2.BlockRequest[transaction.Tx]{ + Height: height + 1, + Time: time.Now(), + Hash: bz[:], + AppHash: ci.Hash, + }) + require.NoError(t, err) + + changes, err := newState.GetStateChanges() + require.NoError(t, err) + + _, err = st.Commit(&store.Changeset{Changes: changes}) + require.NoError(t, err) +} + +func TestSimAppExportAndBlockedAddrs_WithOneBlockProduced(t *testing.T) { + app, ctx := NewTestApp(t) + + MoveNextBlock(t, app, ctx) + + _, err := app.ExportAppStateAndValidators(nil) + require.NoError(t, err) +} + +func TestSimAppExportAndBlockedAddrs_NoBlocksProduced(t *testing.T) { + app, _ := NewTestApp(t) + + _, err := app.ExportAppStateAndValidators(nil) + require.NoError(t, err) +} diff --git a/simapp/v2/export.go b/simapp/v2/export.go index 41b8d94e9e7a..5a1757b16535 100644 --- a/simapp/v2/export.go +++ b/simapp/v2/export.go @@ -1,10 +1,29 @@ package simapp import ( - servertypes "github.com/cosmos/cosmos-sdk/server/types" + "context" + + v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2" ) -// ExportAppStateAndValidators exports the state of the application for a genesis file. -func (app *SimApp[T]) ExportAppStateAndValidators(forZeroHeight bool, jailAllowedAddrs, modulesToExport []string) (servertypes.ExportedApp, error) { - panic("not implemented") +// ExportAppStateAndValidators exports the state of the application for a genesis +// file. +func (app *SimApp[T]) ExportAppStateAndValidators(jailAllowedAddrs []string) (v2.ExportedApp, error) { + // as if they could withdraw from the start of the next block + ctx := context.Background() + + latestHeight, err := app.LoadLatestHeight() + if err != nil { + return v2.ExportedApp{}, err + } + + genesis, err := app.ExportGenesis(ctx, latestHeight) + if err != nil { + return v2.ExportedApp{}, err + } + + return v2.ExportedApp{ + AppState: genesis, + Height: int64(latestHeight), + }, nil } diff --git a/simapp/v2/go.mod b/simapp/v2/go.mod index 3fc21e00a28c..ab93f8dcf17a 100644 --- a/simapp/v2/go.mod +++ b/simapp/v2/go.mod @@ -10,10 +10,10 @@ require ( cosmossdk.io/depinject v1.0.0 cosmossdk.io/log v1.4.0 cosmossdk.io/math v1.3.0 - cosmossdk.io/runtime/v2 v2.0.0-20240815194237-858ec2fcb897 // main + cosmossdk.io/runtime/v2 v2.0.0-20240816111545-aeeaca64da2c // main cosmossdk.io/server/v2 v2.0.0-20240815194237-858ec2fcb897 // main cosmossdk.io/server/v2/cometbft v0.0.0-00010101000000-000000000000 - cosmossdk.io/store/v2 v2.0.0-20240815194237-858ec2fcb897 // indirect; main + cosmossdk.io/store/v2 v2.0.0-20240815194237-858ec2fcb897 // main cosmossdk.io/tools/confix v0.0.0-00010101000000-000000000000 cosmossdk.io/x/accounts v0.0.0-20240226161501-23359a0b6d91 cosmossdk.io/x/auth v0.0.0-00010101000000-000000000000 @@ -33,7 +33,7 @@ require ( cosmossdk.io/x/staking v0.0.0-00010101000000-000000000000 cosmossdk.io/x/upgrade v0.0.0-20230613133644-0a778132a60f github.com/cometbft/cometbft v1.0.0-rc1 - github.com/cosmos/cosmos-db v1.0.2 + github.com/cosmos/cosmos-db v1.0.2 // indirect // this version is not used as it is always replaced by the latest Cosmos SDK version github.com/cosmos/cosmos-sdk v0.53.0 github.com/spf13/cobra v1.8.1 @@ -56,7 +56,7 @@ require ( cosmossdk.io/errors v1.0.1 // indirect cosmossdk.io/errors/v2 v2.0.0-20240731132947-df72853b3ca5 // indirect cosmossdk.io/schema v0.1.1 // indirect - cosmossdk.io/server/v2/appmanager v0.0.0-20240815194237-858ec2fcb897 // indirect; main + cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c // indirect; main cosmossdk.io/server/v2/stf v0.0.0-20240815194237-858ec2fcb897 // indirect; main cosmossdk.io/store v1.1.1-0.20240815194237-858ec2fcb897 // indirect; main cosmossdk.io/x/accounts/defaults/lockup v0.0.0-20240417181816-5e7aae0db1f5 // indirect diff --git a/simapp/v2/go.sum b/simapp/v2/go.sum index 0a96cf2f3af2..7afb0a5bd268 100644 --- a/simapp/v2/go.sum +++ b/simapp/v2/go.sum @@ -210,14 +210,14 @@ cosmossdk.io/log v1.4.0 h1:Ttt9d6fQ0GlktwhcysOeNiIjixW7l0rYBocmoXOb11k= cosmossdk.io/log v1.4.0/go.mod h1:k08v0Pyq+gCP6phvdI6RCGhLf/r425UT6Rk/m+o74rU= cosmossdk.io/math v1.3.0 h1:RC+jryuKeytIiictDslBP9i1fhkVm6ZDmZEoNP316zE= cosmossdk.io/math v1.3.0/go.mod h1:vnRTxewy+M7BtXBNFybkuhSH4WfedVAAnERHgVFhp3k= -cosmossdk.io/runtime/v2 v2.0.0-20240815194237-858ec2fcb897 h1:FoBilDe/aYTPd4SuM8DWCsUM6mfv18v3RPTrNuhK9FM= -cosmossdk.io/runtime/v2 v2.0.0-20240815194237-858ec2fcb897/go.mod h1:bFme7eCFsnWvMRYR23kheaWpSuZGJmx7ucnEE9Bo9PU= +cosmossdk.io/runtime/v2 v2.0.0-20240816111545-aeeaca64da2c h1:G1ZYl1rCI/8aGES3KZBXBBvoBEr3mLdTMATgDQHJ9a4= +cosmossdk.io/runtime/v2 v2.0.0-20240816111545-aeeaca64da2c/go.mod h1:bFme7eCFsnWvMRYR23kheaWpSuZGJmx7ucnEE9Bo9PU= cosmossdk.io/schema v0.1.1 h1:I0M6pgI7R10nq+/HCQfbO6BsGBZA8sQy+duR1Y3aKcA= cosmossdk.io/schema v0.1.1/go.mod h1:RDAhxIeNB4bYqAlF4NBJwRrgtnciMcyyg0DOKnhNZQQ= cosmossdk.io/server/v2 v2.0.0-20240815194237-858ec2fcb897 h1:0+G0h2TUKqZdtr36Xse+HABj6clPQjYCB6afAefc5BA= cosmossdk.io/server/v2 v2.0.0-20240815194237-858ec2fcb897/go.mod h1:fVFP3ER/Wwg69A2YzGyBLwBD/xNJLrjtaoJhW+WIjAI= -cosmossdk.io/server/v2/appmanager v0.0.0-20240815194237-858ec2fcb897 h1:6nIswqM7uuETXuQXijp65zkn7Z1qBqlscPcSc8pM6UY= -cosmossdk.io/server/v2/appmanager v0.0.0-20240815194237-858ec2fcb897/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20= +cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c h1:sxMoOFQvf5g1Wl1D2HidVtLpQhK1YCVq0YiDeT6qTNQ= +cosmossdk.io/server/v2/appmanager v0.0.0-20240816111545-aeeaca64da2c/go.mod h1:fJDDnWJCBRxLLIyu2byqtf3KTRYIVS4OxKwdZozJi20= cosmossdk.io/server/v2/stf v0.0.0-20240815194237-858ec2fcb897 h1:wI05I4dFEGpzyiq50Sl3Wh0Nqo0A/bg2OFIljGEa7ME= cosmossdk.io/server/v2/stf v0.0.0-20240815194237-858ec2fcb897/go.mod h1:jkbBZd+xq+SjX8L65GjvToWq1MQ0fjvQFp2dwVbhnk0= cosmossdk.io/store v1.0.0-rc.0.0.20240815194237-858ec2fcb897 h1:o024zaPHYtmUGL2BCX1ns9rfZmMc19U4hQ2CAPt2Xgg= diff --git a/simapp/v2/simdv2/cmd/commands.go b/simapp/v2/simdv2/cmd/commands.go index ec9998f5c8f2..b4d13aa7a78c 100644 --- a/simapp/v2/simdv2/cmd/commands.go +++ b/simapp/v2/simdv2/cmd/commands.go @@ -3,9 +3,7 @@ package cmd import ( "errors" "fmt" - "io" - dbm "github.com/cosmos/cosmos-db" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -26,17 +24,21 @@ import ( "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/server" - servertypes "github.com/cosmos/cosmos-sdk/server/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/genutil" genutilcli "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + genutilv2 "github.com/cosmos/cosmos-sdk/x/genutil/v2" + v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2/cli" ) func newApp[T transaction.Tx]( logger log.Logger, viper *viper.Viper, ) serverv2.AppI[T] { - return serverv2.AppI[T](simapp.NewSimApp[T](logger, viper)) + viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) + + return serverv2.AppI[T]( + simapp.NewSimApp[T](logger, viper)) } func initRootCmd[T transaction.Tx]( @@ -84,25 +86,11 @@ func initRootCmd[T transaction.Tx]( // genesisCommand builds genesis-related `simd genesis` command. Users may provide application specific commands as a parameter func genesisCommand[T transaction.Tx]( moduleManager *runtimev2.MM[T], - appExport func(logger log.Logger, - height int64, - forZeroHeight bool, - jailAllowedAddrs []string, - viper *viper.Viper, - modulesToExport []string, - ) (servertypes.ExportedApp, error), + appExport genutilv2.AppExporter, cmds ...*cobra.Command, ) *cobra.Command { - compatAppExporter := func(logger log.Logger, db dbm.DB, traceWriter io.Writer, height int64, forZeroHeight bool, jailAllowedAddrs []string, appOpts servertypes.AppOptions, modulesToExport []string) (servertypes.ExportedApp, error) { - viperAppOpts, ok := appOpts.(*viper.Viper) - if !ok { - return servertypes.ExportedApp{}, errors.New("appOpts is not viper.Viper") - } - - return appExport(logger, height, forZeroHeight, jailAllowedAddrs, viperAppOpts, modulesToExport) - } + cmd := v2.Commands(moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), moduleManager, appExport) - cmd := genutilcli.Commands(moduleManager.Modules()[genutiltypes.ModuleName].(genutil.AppModule), moduleManager, compatAppExporter) for _, subCmd := range cmds { cmd.AddCommand(subCmd) } @@ -159,26 +147,25 @@ func txCommand() *cobra.Command { func appExport[T transaction.Tx]( logger log.Logger, height int64, - forZeroHeight bool, jailAllowedAddrs []string, viper *viper.Viper, - modulesToExport []string, -) (servertypes.ExportedApp, error) { +) (genutilv2.ExportedApp, error) { // overwrite the FlagInvCheckPeriod viper.Set(server.FlagInvCheckPeriod, 1) + viper.Set(serverv2.FlagHome, simapp.DefaultNodeHome) var simApp *simapp.SimApp[T] if height != -1 { simApp = simapp.NewSimApp[T](logger, viper) if err := simApp.LoadHeight(uint64(height)); err != nil { - return servertypes.ExportedApp{}, err + return genutilv2.ExportedApp{}, err } } else { simApp = simapp.NewSimApp[T](logger, viper) } - return simApp.ExportAppStateAndValidators(forZeroHeight, jailAllowedAddrs, modulesToExport) + return simApp.ExportAppStateAndValidators(jailAllowedAddrs) } var _ transaction.Codec[transaction.Tx] = &genericTxDecoder[transaction.Tx]{} diff --git a/x/genutil/v2/cli/commands.go b/x/genutil/v2/cli/commands.go new file mode 100644 index 000000000000..93052d1e4907 --- /dev/null +++ b/x/genutil/v2/cli/commands.go @@ -0,0 +1,47 @@ +package cli + +import ( + "encoding/json" + + "github.com/spf13/cobra" + + banktypes "cosmossdk.io/x/bank/types" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/genutil/client/cli" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2" +) + +type genesisMM interface { + DefaultGenesis() map[string]json.RawMessage + ValidateGenesis(genesisData map[string]json.RawMessage) error +} + +// Commands adds core sdk's sub-commands into genesis command. +func Commands(genutilModule genutil.AppModule, genMM genesisMM, appExport v2.AppExporter) *cobra.Command { + return CommandsWithCustomMigrationMap(genutilModule, genMM, appExport, genutiltypes.MigrationMap{}) +} + +// CommandsWithCustomMigrationMap adds core sdk's sub-commands into genesis command with custom migration map. +// This custom migration map can be used by the application to add its own migration map. +func CommandsWithCustomMigrationMap(genutilModule genutil.AppModule, genMM genesisMM, appExport v2.AppExporter, migrationMap genutiltypes.MigrationMap) *cobra.Command { + cmd := &cobra.Command{ + Use: "genesis", + Short: "Application's genesis-related subcommands", + DisableFlagParsing: false, + SuggestionsMinimumDistance: 2, + RunE: client.ValidateCmd, + } + cmd.AddCommand( + cli.GenTxCmd(genMM, banktypes.GenesisBalancesIterator{}), + cli.MigrateGenesisCmd(migrationMap), + cli.CollectGenTxsCmd(genutilModule.GenTxValidator()), + cli.ValidateGenesisCmd(genMM), + cli.AddGenesisAccountCmd(), + ExportCmd(appExport), + ) + + return cmd +} diff --git a/x/genutil/v2/cli/export.go b/x/genutil/v2/cli/export.go new file mode 100644 index 000000000000..c19a02f870e3 --- /dev/null +++ b/x/genutil/v2/cli/export.go @@ -0,0 +1,106 @@ +package cli + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "os" + + "github.com/spf13/cobra" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/version" + genutiltypes "github.com/cosmos/cosmos-sdk/x/genutil/types" + v2 "github.com/cosmos/cosmos-sdk/x/genutil/v2" +) + +const ( + flagHeight = "height" + flagJailAllowedAddrs = "jail-allowed-addrs" +) + +// ExportCmd dumps app state to JSON. +func ExportCmd(appExporter v2.AppExporter) *cobra.Command { + cmd := &cobra.Command{ + Use: "export", + Short: "Export state to JSON", + Args: cobra.NoArgs, + RunE: func(cmd *cobra.Command, _ []string) error { + config := client.GetConfigFromCmd(cmd) + viper := client.GetViperFromCmd(cmd) + logger := client.GetLoggerFromCmd(cmd) + + if _, err := os.Stat(config.GenesisFile()); os.IsNotExist(err) { + return err + } + + if appExporter == nil { + if _, err := fmt.Fprintln(cmd.ErrOrStderr(), "WARNING: App exporter not defined. Returning genesis file."); err != nil { + return err + } + + // Open file in read-only mode so we can copy it to stdout. + // It is possible that the genesis file is large, + // so we don't need to read it all into memory + // before we stream it out. + f, err := os.OpenFile(config.GenesisFile(), os.O_RDONLY, 0) + if err != nil { + return err + } + defer f.Close() + + if _, err := io.Copy(cmd.OutOrStdout(), f); err != nil { + return err + } + + return nil + } + + height, _ := cmd.Flags().GetInt64(flagHeight) + jailAllowedAddrs, _ := cmd.Flags().GetStringSlice(flagJailAllowedAddrs) + outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument) + + exported, err := appExporter(logger, height, jailAllowedAddrs, viper) + if err != nil { + return fmt.Errorf("error exporting state: %w", err) + } + + appGenesis, err := genutiltypes.AppGenesisFromFile(config.GenesisFile()) + if err != nil { + return err + } + + // set current binary version + appGenesis.AppName = version.AppName + appGenesis.AppVersion = version.Version + + appGenesis.AppState = exported.AppState + appGenesis.InitialHeight = exported.Height + + out, err := json.Marshal(appGenesis) + if err != nil { + return err + } + + if outputDocument == "" { + // Copy the entire genesis file to stdout. + _, err := io.Copy(cmd.OutOrStdout(), bytes.NewReader(out)) + return err + } + + if err = appGenesis.SaveAs(outputDocument); err != nil { + return err + } + + return nil + }, + } + + cmd.Flags().Int64(flagHeight, -1, "Export state from a particular height (-1 means latest height)") + cmd.Flags().StringSlice(flagJailAllowedAddrs, []string{}, "Comma-separated list of operator addresses of jailed validators to unjail") + cmd.Flags().String(flags.FlagOutputDocument, "", "Exported state is written to the given file instead of STDOUT") + + return cmd +} diff --git a/x/genutil/v2/types.go b/x/genutil/v2/types.go new file mode 100644 index 000000000000..1b94c8bbc9be --- /dev/null +++ b/x/genutil/v2/types.go @@ -0,0 +1,27 @@ +package v2 + +import ( + "encoding/json" + + "github.com/spf13/viper" + + "cosmossdk.io/log" +) + +// AppExporter is a function that dumps all app state to +// JSON-serializable structure and returns the current validator set. +type AppExporter func( + logger log.Logger, + height int64, + jailAllowedAddrs []string, + viper *viper.Viper, +) (ExportedApp, error) + +// ExportedApp represents an exported app state, along with +// validators, consensus params and latest app height. +type ExportedApp struct { + // AppState is the application state as JSON. + AppState json.RawMessage + // Height is the app's latest block height. + Height int64 +} diff --git a/x/staking/genesis.go b/x/staking/genesis.go index edb7548fc7fd..fcd758952e0d 100644 --- a/x/staking/genesis.go +++ b/x/staking/genesis.go @@ -1,6 +1,7 @@ package staking import ( + "context" "fmt" cmttypes "github.com/cometbft/cometbft/types" @@ -14,7 +15,7 @@ import ( ) // WriteValidators returns a slice of bonded genesis validators. -func WriteValidators(ctx sdk.Context, keeper *keeper.Keeper) (vals []cmttypes.GenesisValidator, returnErr error) { +func WriteValidators(ctx context.Context, keeper *keeper.Keeper) (vals []cmttypes.GenesisValidator, returnErr error) { err := keeper.LastValidatorPower.Walk(ctx, nil, func(key []byte, _ gogotypes.Int64Value) (bool, error) { validator, err := keeper.GetValidator(ctx, key) if err != nil {