From 92a095f1bc7a27b215d31a392b058a061d396dfd Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 5 Aug 2022 22:19:28 +0200 Subject: [PATCH 1/6] feat(genutil): allow multiple messages in genesis txs --- x/genutil/types/genesis_state.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index 9a71d50aae6..23434a87a18 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -112,17 +112,19 @@ func ValidateAndGetGenTx(genTx json.RawMessage, txJSONDecoder sdk.TxDecoder) (sd } msgs := tx.GetMsgs() - if len(msgs) != 1 { - return tx, fmt.Errorf("unexpected number of GenTx messages; got: %d, expected: 1", len(msgs)) - } + // if len(msgs) != 1 { + // return tx, 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]) } - if err := msgs[0].ValidateBasic(); err != nil { - return tx, fmt.Errorf("invalid GenTx '%s': %s", msgs[0], err) + for i := range msgs { + if err := msgs[i].ValidateBasic(); err != nil { + return tx, fmt.Errorf("invalid GenTx msg[%d] '%s': %s", i, msgs[i], err) + } } return tx, nil From 7cc415bafa654a20a6fd3510cb9b64a1eb0fa6e7 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 12 Aug 2022 03:06:29 +0200 Subject: [PATCH 2/6] feat(genutil): make ValidateGenesis configurable --- .github/workflows/test.yml | 1 + simapp/app.go | 2 +- simapp/simd/cmd/root.go | 5 +++- simapp/simd/cmd/testnet.go | 2 +- testutil/network/util.go | 2 +- x/genutil/client/cli/collect.go | 4 ++-- x/genutil/collect.go | 7 +++--- x/genutil/module.go | 6 +++-- x/genutil/types/genesis_state.go | 40 ++++++++++++++++---------------- 9 files changed, 38 insertions(+), 31 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index c1a26183a0c..1e9c8d19fac 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,6 +6,7 @@ on: push: branches: - main + - release/** permissions: contents: read diff --git a/simapp/app.go b/simapp/app.go index 9854d15749f..e50df45e9e1 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.AppModuleBasic{GenTxValidator: genutiltypes.DefaultMessageValidator}, bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{}, diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index 88a3b6690ed..7f7d1616774 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,10 +167,11 @@ 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), genutilcli.MigrateGenesisCmd(), genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index 38e9ed4c188..ab82d9a6d96 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -422,7 +422,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 9cb8fbc2750..bc2bb5d768d 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -137,7 +137,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..c6042ea68eb 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, m genutil.AppModuleBasic) *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, m.GenTxValidator) 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 8f9fd611c76..d9ff903c32d 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/module.go b/x/genutil/module.go index 8c7b98dd59c..746f902d5d7 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -27,7 +27,9 @@ var ( ) // AppModuleBasic defines the basic application module used by the genutil module. -type AppModuleBasic struct{} +type AppModuleBasic struct { + GenTxValidator types.MessageValidator +} // Name returns the genutil module's name. func (AppModuleBasic) Name() string { @@ -53,7 +55,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 23434a87a18..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,29 +103,29 @@ func ValidateGenesis(genesisState *GenesisState, txJSONDecoder sdk.TxDecoder) er return nil } +type MessageValidator func([]sdk.Msg) error + +func DefaultMessageValidator(msgs []sdk.Msg) error { + if len(msgs) != 1 { + return fmt.Errorf("unexpected number of GenTx messages; got: %d, expected: 1", len(msgs)) + } + if _, ok := msgs[0].(*stakingtypes.MsgCreateValidator); !ok { + return fmt.Errorf("unexpected GenTx message type; expected: MsgCreateValidator, got: %T", msgs[0]) + } + if err := msgs[0].ValidateBasic(); err != nil { + 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) (sdk.Tx, error) { +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) } - msgs := tx.GetMsgs() - // if len(msgs) != 1 { - // return tx, 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]) - } - - for i := range msgs { - if err := msgs[i].ValidateBasic(); err != nil { - return tx, fmt.Errorf("invalid GenTx msg[%d] '%s': %s", i, msgs[i], err) - } - } - - return tx, nil + return tx, validator(tx.GetMsgs()) } From 3e336b0b7f1c6dc60e2a6b883de0b0133c987194 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Thu, 18 Aug 2022 13:35:51 +0200 Subject: [PATCH 3/6] update tests --- x/genutil/collect_test.go | 2 +- x/genutil/types/genesis_state_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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/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) } From 48497b895e687da1908b342d497a075aa91977fa Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 19 Aug 2022 17:11:27 +0200 Subject: [PATCH 4/6] review --- .github/workflows/test.yml | 1 - simapp/app.go | 2 +- simapp/simd/cmd/root.go | 6 ++++-- x/genutil/client/cli/collect.go | 4 ++-- x/genutil/module.go | 6 ++++++ 5 files changed, 13 insertions(+), 6 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 43f5615d69c..91c97250ad3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,7 +6,6 @@ on: push: branches: - main - - release/** permissions: contents: read diff --git a/simapp/app.go b/simapp/app.go index e50df45e9e1..1ccb6f719fc 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -97,7 +97,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{GenTxValidator: genutiltypes.DefaultMessageValidator}, + 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 7f7d1616774..568a1fe3505 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -171,9 +171,11 @@ func initRootCmd(rootCmd *cobra.Command, encodingConfig params.EncodingConfig) { rootCmd.AddCommand( genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), - genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome, gentxModule), + 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/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index c6042ea68eb..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, m genutil.AppModuleBasic) *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, m.GenTxValidator) + 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/module.go b/x/genutil/module.go index 746f902d5d7..1bcf702fd4b 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -31,6 +31,12 @@ 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 { return types.ModuleName From 99649cca6270c191d1a06e219eb46a1c401f68ec Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Fri, 19 Aug 2022 19:05:11 +0200 Subject: [PATCH 5/6] changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 33bb459967c..b65d311fef2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -109,6 +109,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. ### CLI Breaking Changes From 969d6fc83980df22cfe112a1cebdce3956a37772 Mon Sep 17 00:00:00 2001 From: Robert Zaremba Date: Mon, 22 Aug 2022 11:40:25 +0200 Subject: [PATCH 6/6] update all_legacy --- simapp/app_legacy.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/simapp/app_legacy.go b/simapp/app_legacy.go index 641dcd6641d..7e2dcbd5fe2 100644 --- a/simapp/app_legacy.go +++ b/simapp/app_legacy.go @@ -108,7 +108,7 @@ var ( // and genesis verification. ModuleBasics = module.NewBasicManager( auth.AppModuleBasic{}, - genutil.AppModuleBasic{}, + genutil.NewAppModuleBasic(genutiltypes.DefaultMessageValidator), bank.AppModuleBasic{}, capability.AppModuleBasic{}, staking.AppModuleBasic{},