diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cd1c260d3a..8b40ffa02f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -113,6 +113,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * (appModule) Remove `Route`, `QuerierRoute` and `LegacyQuerierHandler` from AppModule Interface. * (x/modules) Remove all LegacyQueries and related code from modules * (store) [#11825](https://github.com/cosmos/cosmos-sdk/pull/11825) Make extension snapshotter interface safer to use, renamed the util function `WriteExtensionItem` to `WriteExtensionPayload`. +* (x/genutil)[#12956](https://github.com/cosmos/cosmos-sdk/pull/12956) `genutil.AppModuleBasic` has a new attribute: genesis transaction validation function. The existing validation logic is implemented in `genutiltypes.DefaultMessageValidator`. Use `genutil.NewAppModuleBasic` to create a new genutil Module Basic. * (codec) [#12964](https://github.com/cosmos/cosmos-sdk/pull/12964) `ProtoCodec.MarshalInterface` now returns an error when serializing unregistered types and a subsequent `ProtoCodec.UnmarshalInterface` would fail. * (x/staking) [#12973](https://github.com/cosmos/cosmos-sdk/pull/12973) Removed `stakingkeeper.RandomValidator`. Use `testutil.RandSliceElem(r, sk.GetAllValidators(ctx))` instead. diff --git a/simapp/app.go b/simapp/app.go index bba59c45e31..88dcbdc7e67 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -97,7 +97,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{}, diff --git a/simapp/app_legacy.go b/simapp/app_legacy.go index c386814195a..440bcd108ae 100644 --- a/simapp/app_legacy.go +++ b/simapp/app_legacy.go @@ -107,7 +107,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{}, diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 88a3b6690ed..568a1fe3505 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -35,7 +35,9 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/types" banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" "github.com/cosmos/cosmos-sdk/x/crisis" + "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" ) // NewRootCmd creates a new root command for simd. It is called once in the @@ -165,12 +167,15 @@ lru_size = 0` func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { cfg := sdk.GetConfig() cfg.Seal() + gentxModule := simapp.ModuleBasics[genutiltypes.ModuleName].(genutil.AppModuleBasic) rootCmd.AddCommand( genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), + genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome, + gentxModule.GenTxValidator), genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), + genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, + banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), AddGenesisAccountCmd(simapp.DefaultNodeHome), tmcli.NewCompletionCmd(rootCmd, true), diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index 52c7b3e261d..ec7b2f4242c 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -421,7 +421,7 @@ func collectGenFiles( return err } - nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator) + nodeAppState, err := genutil.GenAppStateFromConfig(clientCtx.Codec, clientCtx.TxConfig, nodeConfig, initCfg, *genDoc, genBalIterator, genutiltypes.DefaultMessageValidator) if err != nil { return err } diff --git a/testutil/network/util.go b/testutil/network/util.go index faa6c077c92..55af382dd12 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -136,7 +136,7 @@ func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error { } appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig, - tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}) + tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}, genutiltypes.DefaultMessageValidator) if err != nil { return err } diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index 2a727ca8fba..df6d9511363 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -18,7 +18,7 @@ import ( const flagGenTxDir = "gentx-dir" // CollectGenTxsCmd - return the cobra command to collect genesis transactions -func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command { +func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeHome string, validator types.MessageValidator) *cobra.Command { cmd := &cobra.Command{ Use: "collect-gentxs", Short: "Collect genesis txs and output a genesis.json file", @@ -52,7 +52,7 @@ func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeH appMessage, err := genutil.GenAppStateFromConfig(cdc, clientCtx.TxConfig, - config, initCfg, *genDoc, genBalIterator) + config, initCfg, *genDoc, genBalIterator, validator) if err != nil { return errors.Wrap(err, "failed to get genesis app state from config") } diff --git a/x/genutil/collect.go b/x/genutil/collect.go index 5ee2685159b..ed48d4174bc 100644 --- a/x/genutil/collect.go +++ b/x/genutil/collect.go @@ -26,11 +26,11 @@ import ( // GenAppStateFromConfig gets the genesis app state from the config func GenAppStateFromConfig(cdc codec.JSONCodec, txEncodingConfig client.TxEncodingConfig, config *cfg.Config, initCfg types.InitConfig, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, + validator types.MessageValidator, ) (appState json.RawMessage, err error) { // process genesis transactions, else create default genesis.json appGenTxs, persistentPeers, err := CollectTxs( - cdc, txEncodingConfig.TxJSONDecoder(), config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, - ) + cdc, txEncodingConfig.TxJSONDecoder(), config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, validator) if err != nil { return appState, err } @@ -69,6 +69,7 @@ func GenAppStateFromConfig(cdc codec.JSONCodec, txEncodingConfig client.TxEncodi // the list of appGenTxs, and persistent peers required to generate genesis.json. func CollectTxs(cdc codec.JSONCodec, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, + validator types.MessageValidator, ) (appGenTxs []sdk.Tx, persistentPeers string, err error) { // prepare a map of all balances in genesis state to then validate // against the validators addresses @@ -110,7 +111,7 @@ func CollectTxs(cdc codec.JSONCodec, txJSONDecoder sdk.TxDecoder, moniker, genTx return appGenTxs, persistentPeers, err } - genTx, err := types.ValidateAndGetGenTx(jsonRawTx, txJSONDecoder) + genTx, err := types.ValidateAndGetGenTx(jsonRawTx, txJSONDecoder, validator) if err != nil { return appGenTxs, persistentPeers, err } diff --git a/x/genutil/collect_test.go b/x/genutil/collect_test.go index c9befdd5472..e8bad2eb9ab 100644 --- a/x/genutil/collect_test.go +++ b/x/genutil/collect_test.go @@ -61,7 +61,7 @@ func TestCollectTxsHandlesDirectories(t *testing.T) { balItr := new(doNothingIterator) dnc := &doNothingUnmarshalJSON{cdc} - if _, _, err := genutil.CollectTxs(dnc, txDecoder, "foo", testDir, gdoc, balItr); err != nil { + if _, _, err := genutil.CollectTxs(dnc, txDecoder, "foo", testDir, gdoc, balItr, gtypes.DefaultMessageValidator); err != nil { t.Fatal(err) } } diff --git a/x/genutil/module.go b/x/genutil/module.go index 8c7b98dd59c..1bcf702fd4b 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -27,7 +27,15 @@ var ( ) // AppModuleBasic defines the basic application module used by the genutil module. -type AppModuleBasic struct{} +type AppModuleBasic struct { + GenTxValidator types.MessageValidator +} + +// NewAppModuleBasic creates AppModuleBasic, validator is a function used to validate genesis +// transactions. +func NewAppModuleBasic(validator types.MessageValidator) AppModuleBasic { + return AppModuleBasic{validator} +} // Name returns the genutil module's name. func (AppModuleBasic) Name() string { @@ -53,7 +61,7 @@ func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, txEncodingConfig cl return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } - return types.ValidateGenesis(&data, txEncodingConfig.TxJSONDecoder()) + return types.ValidateGenesis(&data, txEncodingConfig.TxJSONDecoder(), b.GenTxValidator) } // RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the genutil module. diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index 9a71d50aae6..ad5454bc2c0 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -93,9 +93,9 @@ func GenesisStateFromGenFile(genFile string) (genesisState map[string]json.RawMe } // ValidateGenesis validates GenTx transactions -func ValidateGenesis(genesisState *GenesisState, txJSONDecoder sdk.TxDecoder) error { +func ValidateGenesis(genesisState *GenesisState, txJSONDecoder sdk.TxDecoder, validator MessageValidator) error { for _, genTx := range genesisState.GenTxs { - _, err := ValidateAndGetGenTx(genTx, txJSONDecoder) + _, err := ValidateAndGetGenTx(genTx, txJSONDecoder, validator) if err != nil { return err } @@ -103,27 +103,29 @@ func ValidateGenesis(genesisState *GenesisState, txJSONDecoder sdk.TxDecoder) er return nil } -// ValidateAndGetGenTx validates the genesis transaction and returns GenTx if valid -// it cannot verify the signature as it is stateless validation -func ValidateAndGetGenTx(genTx json.RawMessage, txJSONDecoder sdk.TxDecoder) (sdk.Tx, error) { - tx, err := txJSONDecoder(genTx) - if err != nil { - return tx, fmt.Errorf("failed to decode gentx: %s, error: %s", genTx, err) - } +type MessageValidator func([]sdk.Msg) error - msgs := tx.GetMsgs() +func DefaultMessageValidator(msgs []sdk.Msg) error { if len(msgs) != 1 { - return tx, fmt.Errorf("unexpected number of GenTx messages; got: %d, expected: 1", len(msgs)) + return fmt.Errorf("unexpected number of GenTx messages; got: %d, expected: 1", len(msgs)) } - - // TODO: abstract back to staking if _, ok := msgs[0].(*stakingtypes.MsgCreateValidator); !ok { - return tx, fmt.Errorf("unexpected GenTx message type; expected: MsgCreateValidator, got: %T", msgs[0]) + return fmt.Errorf("unexpected GenTx message type; expected: MsgCreateValidator, got: %T", msgs[0]) } - if err := msgs[0].ValidateBasic(); err != nil { - return tx, fmt.Errorf("invalid GenTx '%s': %s", msgs[0], err) + return fmt.Errorf("invalid GenTx '%s': %w", msgs[0], err) + } + + return nil +} + +// ValidateAndGetGenTx validates the genesis transaction and returns GenTx if valid +// it cannot verify the signature as it is stateless validation +func ValidateAndGetGenTx(genTx json.RawMessage, txJSONDecoder sdk.TxDecoder, validator MessageValidator) (sdk.Tx, error) { + tx, err := txJSONDecoder(genTx) + if err != nil { + return tx, fmt.Errorf("failed to decode gentx: %s, error: %s", genTx, err) } - return tx, nil + return tx, validator(tx.GetMsgs()) } diff --git a/x/genutil/types/genesis_state_test.go b/x/genutil/types/genesis_state_test.go index 760f593ab3c..a589f5a4f95 100644 --- a/x/genutil/types/genesis_state_test.go +++ b/x/genutil/types/genesis_state_test.go @@ -55,7 +55,7 @@ func TestValidateGenesisMultipleMessages(t *testing.T) { tx := txBuilder.GetTx() genesisState := types.NewGenesisStateFromTx(txConfig.TxJSONEncoder(), []sdk.Tx{tx}) - err = types.ValidateGenesis(genesisState, txConfig.TxJSONDecoder()) + err = types.ValidateGenesis(genesisState, txConfig.TxJSONDecoder(), types.DefaultMessageValidator) require.Error(t, err) } @@ -72,7 +72,7 @@ func TestValidateGenesisBadMessage(t *testing.T) { tx := txBuilder.GetTx() genesisState := types.NewGenesisStateFromTx(txConfig.TxJSONEncoder(), []sdk.Tx{tx}) - err = types.ValidateGenesis(genesisState, txConfig.TxJSONDecoder()) + err = types.ValidateGenesis(genesisState, txConfig.TxJSONDecoder(), types.DefaultMessageValidator) require.Error(t, err) }