diff --git a/CHANGELOG.md b/CHANGELOG.md index ff4b4cad4d04..ee3952e90791 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -152,6 +152,7 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa * (client/flags) [\#6632](https://github.com/cosmos/cosmos-sdk/pull/6632) Remove NewCompletionCmd(), the function is now available in tendermint. * (crypto) [\#6780](https://github.com/cosmos/cosmos-sdk/issues/6780) Move ledger code to its own package. * (modules) [\#6834](https://github.com/cosmos/cosmos-sdk/issues/6834) Add `RegisterInterfaces` method to `AppModuleBasic` to support registration of protobuf interface types. +* (modules) [\#6734](https://github.com/cosmos/cosmos-sdk/issues/6834) Add `TxEncodingConfig` parameter to `AppModuleBasic.ValidateGenesis` command to support JSON tx decoding in `genutil`. ### Features diff --git a/client/tx_generator.go b/client/tx_generator.go index 76a5eb98a75f..2452b45ddebf 100644 --- a/client/tx_generator.go +++ b/client/tx_generator.go @@ -7,18 +7,24 @@ import ( ) type ( + // TxEncodingConfig defines an interface that contains transaction + // encoders and decoders + TxEncodingConfig interface { + TxEncoder() sdk.TxEncoder + TxDecoder() sdk.TxDecoder + TxJSONEncoder() sdk.TxEncoder + TxJSONDecoder() sdk.TxDecoder + } + // TxConfig defines an interface a client can utilize to generate an // application-defined concrete transaction type. The type returned must // implement TxBuilder. TxConfig interface { + TxEncodingConfig + NewTxBuilder() TxBuilder WrapTxBuilder(sdk.Tx) (TxBuilder, error) SignModeHandler() signing.SignModeHandler - - TxEncoder() sdk.TxEncoder - TxDecoder() sdk.TxDecoder - TxJSONEncoder() sdk.TxEncoder - TxJSONDecoder() sdk.TxDecoder } // TxBuilder defines an interface which an application-defined concrete transaction diff --git a/simapp/app.go b/simapp/app.go index e9fa79ee7b80..a5cfa4079df0 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -289,7 +289,10 @@ func NewSimApp( // NOTE: Any module instantiated in the module manager that is later modified // must be passed by reference here. app.mm = module.NewManager( - genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx), + genutil.NewAppModule( + app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx, + encodingConfig.TxConfig, + ), auth.NewAppModule(appCodec, app.AccountKeeper), bank.NewAppModule(appCodec, app.BankKeeper, app.AccountKeeper), capability.NewAppModule(appCodec, *app.CapabilityKeeper), diff --git a/simapp/params/proto.go b/simapp/params/proto.go index 012361d1dc51..a5c859ada421 100644 --- a/simapp/params/proto.go +++ b/simapp/params/proto.go @@ -15,7 +15,7 @@ func MakeEncodingConfig() EncodingConfig { cdc := codec.New() interfaceRegistry := types.NewInterfaceRegistry() marshaler := codec.NewHybridCodec(cdc, interfaceRegistry) - txGen := tx.NewTxConfig(marshaler, std.DefaultPublicKeyCodec{}, tx.DefaultSignModeHandler()) + txGen := tx.NewTxConfig(interfaceRegistry, std.DefaultPublicKeyCodec{}, tx.DefaultSignModeHandler()) return EncodingConfig{ InterfaceRegistry: interfaceRegistry, diff --git a/simapp/simd/cmd/root.go b/simapp/simd/cmd/root.go index c3260b1ff06d..48695b04f480 100644 --- a/simapp/simd/cmd/root.go +++ b/simapp/simd/cmd/root.go @@ -78,8 +78,8 @@ func init() { genutilcli.InitCmd(simapp.ModuleBasics, simapp.DefaultNodeHome), genutilcli.CollectGenTxsCmd(banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), genutilcli.MigrateGenesisCmd(), - genutilcli.GenTxCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), - genutilcli.ValidateGenesisCmd(simapp.ModuleBasics), + genutilcli.GenTxCmd(simapp.ModuleBasics, encodingConfig.TxConfig, banktypes.GenesisBalancesIterator{}, simapp.DefaultNodeHome), + genutilcli.ValidateGenesisCmd(simapp.ModuleBasics, encodingConfig.TxConfig), AddGenesisAccountCmd(simapp.DefaultNodeHome), cli.NewCompletionCmd(rootCmd, true), testnetCmd(simapp.ModuleBasics, banktypes.GenesisBalancesIterator{}), diff --git a/simapp/simd/cmd/testnet.go b/simapp/simd/cmd/testnet.go index f7b8cf4ef946..bdb329177187 100644 --- a/simapp/simd/cmd/testnet.go +++ b/simapp/simd/cmd/testnet.go @@ -74,7 +74,7 @@ Example: numValidators, _ := cmd.Flags().GetInt(flagNumValidators) return InitTestnet( - cmd, config, cdc, mbm, genBalIterator, outputDir, chainID, minGasPrices, + cmd, config, cdc, clientCtx.TxConfig, mbm, genBalIterator, outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome, nodeCLIHome, startingIPAddress, keyringBackend, numValidators, ) }, @@ -97,7 +97,8 @@ const nodeDirPerm = 0755 // Initialize the testnet func InitTestnet( - cmd *cobra.Command, config *tmconfig.Config, cdc codec.JSONMarshaler, + cmd *cobra.Command, nodeConfig *tmconfig.Config, cdc codec.JSONMarshaler, + txEncodingConfig client.TxEncodingConfig, mbm module.BasicManager, genBalIterator banktypes.GenesisBalancesIterator, outputDir, chainID, minGasPrices, nodeDirPrefix, nodeDaemonHome, nodeCLIHome, startingIPAddress, keyringBackend string, numValidators int, @@ -132,8 +133,8 @@ func InitTestnet( clientDir := filepath.Join(outputDir, nodeDirName, nodeCLIHome) gentxsDir := filepath.Join(outputDir, "gentxs") - config.SetRoot(nodeDir) - config.RPC.ListenAddress = "tcp://0.0.0.0:26657" + nodeConfig.SetRoot(nodeDir) + nodeConfig.RPC.ListenAddress = "tcp://0.0.0.0:26657" if err := os.MkdirAll(filepath.Join(nodeDir, "config"), nodeDirPerm); err != nil { _ = os.RemoveAll(outputDir) @@ -145,7 +146,7 @@ func InitTestnet( return err } - config.Moniker = nodeDirName + nodeConfig.Moniker = nodeDirName ip, err := getIP(i, startingIPAddress) if err != nil { @@ -153,14 +154,14 @@ func InitTestnet( return err } - nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(config) + nodeIDs[i], valPubKeys[i], err = genutil.InitializeNodeValidatorFiles(nodeConfig) if err != nil { _ = os.RemoveAll(outputDir) return err } memo := fmt.Sprintf("%s@%s:26656", nodeIDs[i], ip) - genFiles = append(genFiles, config.GenesisFile()) + genFiles = append(genFiles, nodeConfig.GenesisFile()) kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientDir, inBuf) if err != nil { @@ -240,7 +241,7 @@ func InitTestnet( } err := collectGenFiles( - cdc, config, chainID, nodeIDs, valPubKeys, numValidators, + cdc, txEncodingConfig, nodeConfig, chainID, nodeIDs, valPubKeys, numValidators, outputDir, nodeDirPrefix, nodeDaemonHome, genBalIterator, ) if err != nil { @@ -294,7 +295,8 @@ func initGenFiles( } func collectGenFiles( - cdc codec.JSONMarshaler, config *tmconfig.Config, chainID string, + cdc codec.JSONMarshaler, txEncodingConfig client.TxEncodingConfig, + nodeConfig *tmconfig.Config, chainID string, nodeIDs []string, valPubKeys []crypto.PubKey, numValidators int, outputDir, nodeDirPrefix, nodeDaemonHome string, genBalIterator banktypes.GenesisBalancesIterator, @@ -307,19 +309,19 @@ func collectGenFiles( nodeDirName := fmt.Sprintf("%s%d", nodeDirPrefix, i) nodeDir := filepath.Join(outputDir, nodeDirName, nodeDaemonHome) gentxsDir := filepath.Join(outputDir, "gentxs") - config.Moniker = nodeDirName + nodeConfig.Moniker = nodeDirName - config.SetRoot(nodeDir) + nodeConfig.SetRoot(nodeDir) nodeID, valPubKey := nodeIDs[i], valPubKeys[i] initCfg := genutiltypes.NewInitConfig(chainID, gentxsDir, nodeID, valPubKey) - genDoc, err := types.GenesisDocFromFile(config.GenesisFile()) + genDoc, err := types.GenesisDocFromFile(nodeConfig.GenesisFile()) if err != nil { return err } - nodeAppState, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genBalIterator) + nodeAppState, err := genutil.GenAppStateFromConfig(cdc, txEncodingConfig, nodeConfig, initCfg, *genDoc, genBalIterator) if err != nil { return err } @@ -329,7 +331,7 @@ func collectGenFiles( appState = nodeAppState } - genFile := config.GenesisFile() + genFile := nodeConfig.GenesisFile() // overwrite each validator's genesis file to have a canonical genesis time if err := genutil.ExportGenesisFileWithTime(genFile, chainID, nil, appState, genTime); err != nil { diff --git a/tests/mocks/types_module_module.go b/tests/mocks/types_module_module.go index 0b2051053d50..737959ae0270 100644 --- a/tests/mocks/types_module_module.go +++ b/tests/mocks/types_module_module.go @@ -95,17 +95,17 @@ func (mr *MockAppModuleBasicMockRecorder) DefaultGenesis(arg0 interface{}) *gomo } // ValidateGenesis mocks base method -func (m *MockAppModuleBasic) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { +func (m *MockAppModuleBasic) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleBasicMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAppModuleBasicMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).ValidateGenesis), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleBasic)(nil).ValidateGenesis), arg0, arg1, arg2) } // RegisterRESTRoutes mocks base method @@ -224,17 +224,17 @@ func (mr *MockAppModuleGenesisMockRecorder) DefaultGenesis(arg0 interface{}) *go } // ValidateGenesis mocks base method -func (m *MockAppModuleGenesis) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { +func (m *MockAppModuleGenesis) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleGenesisMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAppModuleGenesisMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ValidateGenesis), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModuleGenesis)(nil).ValidateGenesis), arg0, arg1, arg2) } // RegisterRESTRoutes mocks base method @@ -381,17 +381,17 @@ func (mr *MockAppModuleMockRecorder) DefaultGenesis(arg0 interface{}) *gomock.Ca } // ValidateGenesis mocks base method -func (m *MockAppModule) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 json.RawMessage) error { +func (m *MockAppModule) ValidateGenesis(arg0 codec.JSONMarshaler, arg1 client.TxEncodingConfig, arg2 json.RawMessage) error { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1) + ret := m.ctrl.Call(m, "ValidateGenesis", arg0, arg1, arg2) ret0, _ := ret[0].(error) return ret0 } // ValidateGenesis indicates an expected call of ValidateGenesis -func (mr *MockAppModuleMockRecorder) ValidateGenesis(arg0, arg1 interface{}) *gomock.Call { +func (mr *MockAppModuleMockRecorder) ValidateGenesis(arg0, arg1, arg2 interface{}) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModule)(nil).ValidateGenesis), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateGenesis", reflect.TypeOf((*MockAppModule)(nil).ValidateGenesis), arg0, arg1, arg2) } // RegisterRESTRoutes mocks base method diff --git a/testutil/network/network.go b/testutil/network/network.go index 9c6621bc0f3d..af561b79f48f 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -13,6 +13,8 @@ import ( "testing" "time" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/stretchr/testify/require" tmcfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tendermint/crypto" @@ -278,16 +280,21 @@ func New(t *testing.T, cfg Config) *Network { require.NoError(t, err) memo := fmt.Sprintf("%s@%s:%s", nodeIDs[i], p2pURL.Hostname(), p2pURL.Port()) - tx := authtypes.NewStdTx([]sdk.Msg{createValMsg}, authtypes.StdFee{}, []authtypes.StdSignature{}, memo) //nolint:staticcheck // SA1019: authtypes.StdFee is deprecated - txBldr := authtypes.TxBuilder{}. + txBuilder := cfg.TxConfig.NewTxBuilder() + require.NoError(t, txBuilder.SetMsgs(createValMsg)) + txBuilder.SetMemo(memo) + + txFactory := tx.Factory{} + txFactory = txFactory. WithChainID(cfg.ChainID). WithMemo(memo). - WithKeybase(kb) + WithKeybase(kb). + WithTxConfig(cfg.TxConfig) - signedTx, err := txBldr.SignStdTx(nodeDirName, tx, false) + err = tx.Sign(txFactory, nodeDirName, txBuilder) require.NoError(t, err) - txBz, err := cfg.Codec.MarshalJSON(signedTx) + txBz, err := cfg.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) require.NoError(t, err) require.NoError(t, writeFile(fmt.Sprintf("%v.json", nodeDirName), gentxsDir, txBz)) diff --git a/testutil/network/util.go b/testutil/network/util.go index cb8262c8a77a..86bed50eb34e 100644 --- a/testutil/network/util.go +++ b/testutil/network/util.go @@ -105,7 +105,8 @@ func collectGenFiles(cfg Config, vals []*Validator, outputDir string) error { return err } - appState, err := genutil.GenAppStateFromConfig(cfg.Codec, tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}) + appState, err := genutil.GenAppStateFromConfig(cfg.Codec, cfg.TxConfig, + tmCfg, initCfg, *genDoc, banktypes.GenesisBalancesIterator{}) if err != nil { return err } diff --git a/types/module/module.go b/types/module/module.go index d0dc558bd51f..98ebc0bfa550 100644 --- a/types/module/module.go +++ b/types/module/module.go @@ -52,7 +52,7 @@ type AppModuleBasic interface { RegisterInterfaces(codectypes.InterfaceRegistry) DefaultGenesis(codec.JSONMarshaler) json.RawMessage - ValidateGenesis(codec.JSONMarshaler, json.RawMessage) error + ValidateGenesis(codec.JSONMarshaler, client.TxEncodingConfig, json.RawMessage) error // client functionality RegisterRESTRoutes(client.Context, *mux.Router) @@ -97,9 +97,9 @@ func (bm BasicManager) DefaultGenesis(cdc codec.JSONMarshaler) map[string]json.R } // ValidateGenesis performs genesis state validation for all modules -func (bm BasicManager) ValidateGenesis(cdc codec.JSONMarshaler, genesis map[string]json.RawMessage) error { +func (bm BasicManager) ValidateGenesis(cdc codec.JSONMarshaler, txEncCfg client.TxEncodingConfig, genesis map[string]json.RawMessage) error { for _, b := range bm { - if err := b.ValidateGenesis(cdc, genesis[b.Name()]); err != nil { + if err := b.ValidateGenesis(cdc, txEncCfg, genesis[b.Name()]); err != nil { return err } } diff --git a/types/module/module_test.go b/types/module/module_test.go index 51a772987228..1c1ab3d4d9e4 100644 --- a/types/module/module_test.go +++ b/types/module/module_test.go @@ -35,7 +35,7 @@ func TestBasicManager(t *testing.T) { mockAppModuleBasic1.EXPECT().Name().AnyTimes().Return("mockAppModuleBasic1") mockAppModuleBasic1.EXPECT().DefaultGenesis(gomock.Eq(cdc)).Times(1).Return(json.RawMessage(``)) - mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) + mockAppModuleBasic1.EXPECT().ValidateGenesis(gomock.Eq(cdc), gomock.Eq(nil), gomock.Eq(wantDefaultGenesis["mockAppModuleBasic1"])).Times(1).Return(errFoo) mockAppModuleBasic1.EXPECT().RegisterRESTRoutes(gomock.Eq(client.Context{}), gomock.Eq(&mux.Router{})).Times(1) mockAppModuleBasic1.EXPECT().RegisterCodec(gomock.Eq(cdc)).Times(1) mockAppModuleBasic1.EXPECT().RegisterInterfaces(gomock.Eq(interfaceRegistry)).Times(1) @@ -53,7 +53,7 @@ func TestBasicManager(t *testing.T) { var data map[string]string require.Equal(t, map[string]string(nil), data) - require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, wantDefaultGenesis))) + require.True(t, errors.Is(errFoo, mm.ValidateGenesis(cdc, nil, wantDefaultGenesis))) mm.RegisterRESTRoutes(client.Context{}, &mux.Router{}) @@ -63,7 +63,7 @@ func TestBasicManager(t *testing.T) { mm.AddQueryCommands(mockCmd) // validate genesis returns nil - require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, wantDefaultGenesis)) + require.Nil(t, module.NewBasicManager().ValidateGenesis(cdc, nil, wantDefaultGenesis)) } func TestGenesisOnlyAppModule(t *testing.T) { diff --git a/x/auth/module.go b/x/auth/module.go index aaef555b7275..6f6bdceab3ea 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -50,7 +50,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the auth module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/auth/tx/builder.go b/x/auth/tx/builder.go index 7df625aa7515..857d34a08a5f 100644 --- a/x/auth/tx/builder.go +++ b/x/auth/tx/builder.go @@ -3,6 +3,8 @@ package tx import ( "fmt" + "github.com/gogo/protobuf/proto" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/x/auth/signing/direct" @@ -16,7 +18,6 @@ import ( "github.com/tendermint/tendermint/crypto" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" @@ -37,7 +38,6 @@ type builder struct { // or decoded from AuthInfo when GetPubKey's was called pubKeys []crypto.PubKey - marshaler codec.Marshaler pubkeyCodec types.PublicKeyCodec } @@ -47,7 +47,7 @@ var ( _ direct.ProtoTx = &builder{} ) -func newBuilder(marshaler codec.Marshaler, pubkeyCodec types.PublicKeyCodec) *builder { +func newBuilder(pubkeyCodec types.PublicKeyCodec) *builder { return &builder{ tx: &tx.Tx{ Body: &tx.TxBody{}, @@ -55,7 +55,6 @@ func newBuilder(marshaler codec.Marshaler, pubkeyCodec types.PublicKeyCodec) *bu Fee: &tx.Fee{}, }, }, - marshaler: marshaler, pubkeyCodec: pubkeyCodec, } } @@ -131,7 +130,11 @@ func (t *builder) GetBodyBytes() []byte { // this method should always return the correct bytes. Note that after // decoding bodyBz is derived from TxRaw so that it matches what was // transmitted over the wire - t.bodyBz = t.marshaler.MustMarshalBinaryBare(t.tx.Body) + var err error + t.bodyBz, err = proto.Marshal(t.tx.Body) + if err != nil { + panic(err) + } } return t.bodyBz } @@ -143,7 +146,11 @@ func (t *builder) GetAuthInfoBytes() []byte { // this method should always return the correct bytes. Note that after // decoding authInfoBz is derived from TxRaw so that it matches what was // transmitted over the wire - t.authInfoBz = t.marshaler.MustMarshalBinaryBare(t.tx.AuthInfo) + var err error + t.authInfoBz, err = proto.Marshal(t.tx.AuthInfo) + if err != nil { + panic(err) + } } return t.authInfoBz } diff --git a/x/auth/tx/builder_test.go b/x/auth/tx/builder_test.go index 136078fa762d..c115f474ac83 100644 --- a/x/auth/tx/builder_test.go +++ b/x/auth/tx/builder_test.go @@ -22,7 +22,7 @@ func TestTxBuilder(t *testing.T) { _, pubkey, addr := testdata.KeyTestPubAddr() marshaler := codec.NewHybridCodec(codec.New(), codectypes.NewInterfaceRegistry()) - tx := newBuilder(marshaler, std.DefaultPublicKeyCodec{}) + tx := newBuilder(std.DefaultPublicKeyCodec{}) cdc := std.DefaultPublicKeyCodec{} @@ -125,8 +125,7 @@ func TestBuilderValidateBasic(t *testing.T) { // require to fail validation upon invalid fee badFeeAmount := testdata.NewTestFeeAmount() badFeeAmount[0].Amount = sdk.NewInt(-5) - marshaler := codec.NewHybridCodec(codec.New(), codectypes.NewInterfaceRegistry()) - bldr := newBuilder(marshaler, std.DefaultPublicKeyCodec{}) + bldr := newBuilder(std.DefaultPublicKeyCodec{}) var sig1, sig2 signing.SignatureV2 sig1 = signing.SignatureV2{ diff --git a/x/auth/tx/decoder.go b/x/auth/tx/decoder.go index 8ce3b06fa66e..e229c1f35b85 100644 --- a/x/auth/tx/decoder.go +++ b/x/auth/tx/decoder.go @@ -3,15 +3,18 @@ package tx import ( "github.com/tendermint/tendermint/crypto" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/types/tx" - "github.com/cosmos/cosmos-sdk/codec" cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" ) // DefaultTxDecoder returns a default protobuf TxDecoder using the provided Marshaler and PublicKeyCodec -func DefaultTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder { +func DefaultTxDecoder(anyUnpacker types.AnyUnpacker, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder { + cdc := codec.NewProtoCodec(anyUnpacker) return func(txBytes []byte) (sdk.Tx, error) { var raw tx.TxRaw err := cdc.UnmarshalBinaryBare(txBytes, &raw) @@ -35,14 +38,14 @@ func DefaultTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCodec) bodyBz: raw.BodyBytes, authInfoBz: raw.AuthInfoBytes, pubKeys: pks, - marshaler: cdc, pubkeyCodec: keyCodec, }, nil } } // DefaultTxDecoder returns a default protobuf JSON TxDecoder using the provided Marshaler and PublicKeyCodec -func DefaultJSONTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder { +func DefaultJSONTxDecoder(anyUnpacker types.AnyUnpacker, keyCodec cryptotypes.PublicKeyCodec) sdk.TxDecoder { + cdc := codec.NewProtoCodec(anyUnpacker) return func(txBytes []byte) (sdk.Tx, error) { var theTx tx.Tx err := cdc.UnmarshalJSON(txBytes, &theTx) @@ -58,7 +61,6 @@ func DefaultJSONTxDecoder(cdc codec.Marshaler, keyCodec cryptotypes.PublicKeyCod return &builder{ tx: &theTx, pubKeys: pks, - marshaler: cdc, pubkeyCodec: keyCodec, }, nil } diff --git a/x/auth/tx/encoder.go b/x/auth/tx/encoder.go index 3c39a20a61fd..004728a3e132 100644 --- a/x/auth/tx/encoder.go +++ b/x/auth/tx/encoder.go @@ -3,13 +3,15 @@ package tx import ( "fmt" + "github.com/gogo/protobuf/proto" + "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/types" txtypes "github.com/cosmos/cosmos-sdk/types/tx" ) // DefaultTxEncoder returns a default protobuf TxEncoder using the provided Marshaler -func DefaultTxEncoder(marshaler codec.Marshaler) types.TxEncoder { +func DefaultTxEncoder() types.TxEncoder { return func(tx types.Tx) ([]byte, error) { wrapper, ok := tx.(*builder) if !ok { @@ -22,18 +24,18 @@ func DefaultTxEncoder(marshaler codec.Marshaler) types.TxEncoder { Signatures: wrapper.tx.Signatures, } - return marshaler.MarshalBinaryBare(raw) + return proto.Marshal(raw) } } // DefaultTxEncoder returns a default protobuf JSON TxEncoder using the provided Marshaler -func DefaultJSONTxEncoder(marshaler codec.Marshaler) types.TxEncoder { +func DefaultJSONTxEncoder() types.TxEncoder { return func(tx types.Tx) ([]byte, error) { wrapper, ok := tx.(*builder) if !ok { return nil, fmt.Errorf("expected %T, got %T", &builder{}, tx) } - return marshaler.MarshalJSON(wrapper.tx) + return codec.ProtoMarshalJSON(wrapper.tx) } } diff --git a/x/auth/tx/generator.go b/x/auth/tx/generator.go index c61d4377e332..f70ddaafca7f 100644 --- a/x/auth/tx/generator.go +++ b/x/auth/tx/generator.go @@ -4,14 +4,13 @@ import ( "fmt" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/crypto/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/signing" ) type generator struct { - marshaler codec.Marshaler pubkeyCodec types.PublicKeyCodec handler signing.SignModeHandler decoder sdk.TxDecoder @@ -21,20 +20,19 @@ type generator struct { } // NewTxConfig returns a new protobuf TxConfig using the provided Marshaler, PublicKeyCodec and SignModeHandler. -func NewTxConfig(marshaler codec.Marshaler, pubkeyCodec types.PublicKeyCodec, signModeHandler signing.SignModeHandler) client.TxConfig { +func NewTxConfig(anyUnpacker codectypes.AnyUnpacker, pubkeyCodec types.PublicKeyCodec, signModeHandler signing.SignModeHandler) client.TxConfig { return &generator{ - marshaler: marshaler, pubkeyCodec: pubkeyCodec, handler: signModeHandler, - decoder: DefaultTxDecoder(marshaler, pubkeyCodec), - encoder: DefaultTxEncoder(marshaler), - jsonDecoder: DefaultJSONTxDecoder(marshaler, pubkeyCodec), - jsonEncoder: DefaultJSONTxEncoder(marshaler), + decoder: DefaultTxDecoder(anyUnpacker, pubkeyCodec), + encoder: DefaultTxEncoder(), + jsonDecoder: DefaultJSONTxDecoder(anyUnpacker, pubkeyCodec), + jsonEncoder: DefaultJSONTxEncoder(), } } func (g generator) NewTxBuilder() client.TxBuilder { - return newBuilder(g.marshaler, g.pubkeyCodec) + return newBuilder(g.pubkeyCodec) } // WrapTxBuilder returns a builder from provided transaction diff --git a/x/bank/module.go b/x/bank/module.go index 5af44af91963..c8a1985988ec 100644 --- a/x/bank/module.go +++ b/x/bank/module.go @@ -47,7 +47,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the bank module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) @@ -126,6 +126,7 @@ func (am AppModule) LegacyQuerierHandler(legacyQuerierCdc codec.JSONMarshaler) s // no validator updates. func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState + cdc.MustUnmarshalJSON(data, &genesisState) am.keeper.InitGenesis(ctx, genesisState) return []abci.ValidatorUpdate{} diff --git a/x/capability/module.go b/x/capability/module.go index 109e0292579d..76dd16d52667 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -60,7 +60,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the capability module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var genState types.GenesisState if err := cdc.UnmarshalJSON(bz, &genState); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/crisis/module.go b/x/crisis/module.go index adb5c918cd43..cc0922b37a3f 100644 --- a/x/crisis/module.go +++ b/x/crisis/module.go @@ -44,7 +44,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the crisis module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/distribution/module.go b/x/distribution/module.go index b0bc8563e310..cd91fad11cae 100644 --- a/x/distribution/module.go +++ b/x/distribution/module.go @@ -53,7 +53,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the distribution module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config sdkclient.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/evidence/module.go b/x/evidence/module.go index 1e9035c4af1a..d20b8dca7fe8 100644 --- a/x/evidence/module.go +++ b/x/evidence/module.go @@ -64,7 +64,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the evidence module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/genutil/client/cli/collect.go b/x/genutil/client/cli/collect.go index 912f994a6d11..1fefbe382a87 100644 --- a/x/genutil/client/cli/collect.go +++ b/x/genutil/client/cli/collect.go @@ -50,7 +50,9 @@ func CollectGenTxsCmd(genBalIterator types.GenesisBalancesIterator, defaultNodeH toPrint := newPrintInfo(config.Moniker, genDoc.ChainID, nodeID, genTxsDir, json.RawMessage("")) initCfg := types.NewInitConfig(genDoc.ChainID, genTxsDir, nodeID, valPubKey) - appMessage, err := genutil.GenAppStateFromConfig(cdc, config, initCfg, *genDoc, genBalIterator) + appMessage, err := genutil.GenAppStateFromConfig(cdc, + clientCtx.TxConfig, + config, initCfg, *genDoc, genBalIterator) if err != nil { return errors.Wrap(err, "failed to get genesis app state from config") } diff --git a/x/genutil/client/cli/gentx.go b/x/genutil/client/cli/gentx.go index 749defcd40a4..328f0815d1f3 100644 --- a/x/genutil/client/cli/gentx.go +++ b/x/genutil/client/cli/gentx.go @@ -31,7 +31,7 @@ import ( ) // GenTxCmd builds the application's gentx command. -func GenTxCmd(mbm module.BasicManager, genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command { +func GenTxCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfig, genBalIterator types.GenesisBalancesIterator, defaultNodeHome string) *cobra.Command { ipDefault, _ := server.ExternalIP() fsCreateValidator, defaultsDesc := cli.CreateValidatorMsgFlagSet(ipDefault) @@ -93,7 +93,7 @@ $ %s gentx my-key-name --home=/path/to/home/dir --keyring-backend=os --chain-id= return errors.Wrap(err, "failed to unmarshal genesis state") } - if err = mbm.ValidateGenesis(cdc, genesisState); err != nil { + if err = mbm.ValidateGenesis(cdc, txEncCfg, genesisState); err != nil { return errors.Wrap(err, "failed to validate genesis state") } diff --git a/x/genutil/client/cli/validate_genesis.go b/x/genutil/client/cli/validate_genesis.go index 8d4dce3a2793..756b06a26ea4 100644 --- a/x/genutil/client/cli/validate_genesis.go +++ b/x/genutil/client/cli/validate_genesis.go @@ -14,7 +14,7 @@ import ( ) // Validate genesis command takes -func ValidateGenesisCmd(mbm module.BasicManager) *cobra.Command { +func ValidateGenesisCmd(mbm module.BasicManager, txEncCfg client.TxEncodingConfig) *cobra.Command { return &cobra.Command{ Use: "validate-genesis [file]", Args: cobra.RangeArgs(0, 1), @@ -45,7 +45,7 @@ func ValidateGenesisCmd(mbm module.BasicManager) *cobra.Command { return fmt.Errorf("error unmarshalling genesis doc %s: %s", genesis, err.Error()) } - if err = mbm.ValidateGenesis(cdc, genState); err != nil { + if err = mbm.ValidateGenesis(cdc, txEncCfg, genState); err != nil { return fmt.Errorf("error validating genesis file %s: %s", genesis, err.Error()) } diff --git a/x/genutil/collect.go b/x/genutil/collect.go index 82ebb2a10285..d1d69c8d9902 100644 --- a/x/genutil/collect.go +++ b/x/genutil/collect.go @@ -15,22 +15,22 @@ import ( cfg "github.com/tendermint/tendermint/config" tmtypes "github.com/tendermint/tendermint/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) // GenAppStateFromConfig gets the genesis app state from the config -func GenAppStateFromConfig(cdc codec.JSONMarshaler, config *cfg.Config, - initCfg types.InitConfig, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, +func GenAppStateFromConfig(cdc codec.JSONMarshaler, txEncodingConfig client.TxEncodingConfig, + config *cfg.Config, initCfg types.InitConfig, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, ) (appState json.RawMessage, err error) { // process genesis transactions, else create default genesis.json - appGenTxs, persistentPeers, err := CollectStdTxs( - cdc, config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, + appGenTxs, persistentPeers, err := CollectTxs( + cdc, txEncodingConfig.TxJSONDecoder(), config.Moniker, initCfg.GenTxsDir, genDoc, genBalIterator, ) if err != nil { return appState, err @@ -50,7 +50,7 @@ func GenAppStateFromConfig(cdc codec.JSONMarshaler, config *cfg.Config, return appState, err } - appGenesisState, err = SetGenTxsInAppGenesisState(cdc, appGenesisState, appGenTxs) + appGenesisState, err = SetGenTxsInAppGenesisState(cdc, txEncodingConfig.TxJSONEncoder(), appGenesisState, appGenTxs) if err != nil { return appState, err } @@ -66,11 +66,11 @@ func GenAppStateFromConfig(cdc codec.JSONMarshaler, config *cfg.Config, return appState, err } -// CollectStdTxs processes and validates application's genesis StdTxs and returns +// CollectTxs processes and validates application's genesis Txs and returns // the list of appGenTxs, and persistent peers required to generate genesis.json. -func CollectStdTxs(cdc codec.JSONMarshaler, moniker, genTxsDir string, +func CollectTxs(cdc codec.JSONMarshaler, txJSONDecoder sdk.TxDecoder, moniker, genTxsDir string, genDoc tmtypes.GenesisDoc, genBalIterator types.GenesisBalancesIterator, -) (appGenTxs []authtypes.StdTx, persistentPeers string, err error) { +) (appGenTxs []sdk.Tx, persistentPeers string, err error) { var fos []os.FileInfo fos, err = ioutil.ReadDir(genTxsDir) @@ -104,30 +104,35 @@ func CollectStdTxs(cdc codec.JSONMarshaler, moniker, genTxsDir string, continue } - // get the genStdTx + // get the genTx var jsonRawTx []byte if jsonRawTx, err = ioutil.ReadFile(filename); err != nil { return appGenTxs, persistentPeers, err } - var genStdTx authtypes.StdTx - if err = cdc.UnmarshalJSON(jsonRawTx, &genStdTx); err != nil { + var genTx sdk.Tx + if genTx, err = txJSONDecoder(jsonRawTx); err != nil { return appGenTxs, persistentPeers, err } - appGenTxs = append(appGenTxs, genStdTx) + appGenTxs = append(appGenTxs, genTx) // 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() + + memoTx, ok := genTx.(sdk.TxWithMemo) + if !ok { + return appGenTxs, persistentPeers, fmt.Errorf("expected TxWithMemo, got %T", genTx) + } + nodeAddrIP := memoTx.GetMemo() if len(nodeAddrIP) == 0 { return appGenTxs, persistentPeers, fmt.Errorf("failed to find node's address and IP in %s", fo.Name()) } // genesis transactions must be single-message - msgs := genStdTx.GetMsgs() + msgs := genTx.GetMsgs() if len(msgs) != 1 { return appGenTxs, persistentPeers, errors.New("each genesis transaction must provide a single genesis message") } diff --git a/x/genutil/genesis.go b/x/genutil/genesis.go index 335712a33031..9a155cfa1e25 100644 --- a/x/genutil/genesis.go +++ b/x/genutil/genesis.go @@ -3,20 +3,21 @@ package genutil import ( abci "github.com/tendermint/tendermint/abci/types" - "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/client" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/genutil/types" ) // InitGenesis - initialize accounts and deliver genesis transactions func InitGenesis( - ctx sdk.Context, cdc *codec.Codec, stakingKeeper types.StakingKeeper, + ctx sdk.Context, stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, genesisState types.GenesisState, + txEncodingConfig client.TxEncodingConfig, ) []abci.ValidatorUpdate { var validators []abci.ValidatorUpdate if len(genesisState.GenTxs) > 0 { - validators = DeliverGenTxs(ctx, cdc, genesisState.GenTxs, stakingKeeper, deliverTx) + validators = DeliverGenTxs(ctx, genesisState.GenTxs, stakingKeeper, deliverTx, txEncodingConfig) } return validators diff --git a/x/genutil/gentx.go b/x/genutil/gentx.go index dea85012e142..10849bde78c2 100644 --- a/x/genutil/gentx.go +++ b/x/genutil/gentx.go @@ -1,16 +1,14 @@ package genutil -// DONTCOVER - import ( "encoding/json" "fmt" abci "github.com/tendermint/tendermint/abci/types" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" bankexported "github.com/cosmos/cosmos-sdk/x/bank/exported" "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" @@ -18,14 +16,14 @@ import ( // SetGenTxsInAppGenesisState - sets the genesis transactions in the app genesis state func SetGenTxsInAppGenesisState( - cdc codec.JSONMarshaler, appGenesisState map[string]json.RawMessage, genTxs []authtypes.StdTx, + cdc codec.JSONMarshaler, txJSONEncoder sdk.TxEncoder, appGenesisState map[string]json.RawMessage, genTxs []sdk.Tx, ) (map[string]json.RawMessage, error) { genesisState := types.GetGenesisStateFromAppState(cdc, appGenesisState) genTxsBz := make([]json.RawMessage, 0, len(genTxs)) for _, genTx := range genTxs { - txBz, err := cdc.MarshalJSON(genTx) + txBz, err := txJSONEncoder(genTx) if err != nil { return appGenesisState, err } @@ -90,19 +88,25 @@ func ValidateAccountInGenesis( type deliverTxfn func(abci.RequestDeliverTx) abci.ResponseDeliverTx -// DeliverGenTxs iterates over all genesis txs, decodes each into a StdTx and -// invokes the provided deliverTxfn with the decoded StdTx. It returns the result +// DeliverGenTxs iterates over all genesis txs, decodes each into a Tx and +// invokes the provided deliverTxfn with the decoded Tx. It returns the result // of the staking module's ApplyAndReturnValidatorSetUpdates. func DeliverGenTxs( - ctx sdk.Context, cdc *codec.Codec, genTxs []json.RawMessage, + ctx sdk.Context, genTxs []json.RawMessage, stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, + txEncodingConfig client.TxEncodingConfig, ) []abci.ValidatorUpdate { for _, genTx := range genTxs { - var tx authtypes.StdTx - cdc.MustUnmarshalJSON(genTx, &tx) + tx, err := txEncodingConfig.TxJSONDecoder()(genTx) + if err != nil { + panic(err) + } - bz := cdc.MustMarshalBinaryBare(tx) + bz, err := txEncodingConfig.TxEncoder()(tx) + if err != nil { + panic(err) + } res := deliverTx(abci.RequestDeliverTx{Tx: bz}) if !res.IsOK() { diff --git a/x/genutil/gentx_test.go b/x/genutil/gentx_test.go index ea03ce733ce9..42b9e7c3eb10 100644 --- a/x/genutil/gentx_test.go +++ b/x/genutil/gentx_test.go @@ -1,14 +1,280 @@ -package genutil +package genutil_test -import "testing" +import ( + "encoding/json" + "fmt" + "testing" -func TestGenTx(t *testing.T) { + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/helpers" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + sdk "github.com/cosmos/cosmos-sdk/types" - // 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 + "github.com/stretchr/testify/suite" + abci "github.com/tendermint/tendermint/abci/types" + "github.com/tendermint/tendermint/crypto/secp256k1" - // 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 + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/genutil/types" + staking "github.com/cosmos/cosmos-sdk/x/staking" + stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" +) + +var ( + priv1 = secp256k1.GenPrivKey() + priv2 = secp256k1.GenPrivKey() + pk1 = priv1.PubKey() + pk2 = priv2.PubKey() + addr1 = sdk.AccAddress(pk1.Address()) + addr2 = sdk.AccAddress(pk2.Address()) + desc = stakingtypes.NewDescription("testname", "", "", "", "") + comm = stakingtypes.CommissionRates{} + msg1 = stakingtypes.NewMsgCreateValidator(sdk.ValAddress(pk1.Address()), pk1, + sdk.NewInt64Coin(sdk.DefaultBondDenom, 50), desc, comm, sdk.OneInt()) + msg2 = stakingtypes.NewMsgCreateValidator(sdk.ValAddress(pk2.Address()), pk1, + sdk.NewInt64Coin(sdk.DefaultBondDenom, 50), desc, comm, sdk.OneInt()) +) + +// GenTxTestSuite is a test suite to be used with gentx tests. +type GenTxTestSuite struct { + suite.Suite + + ctx sdk.Context + app *simapp.SimApp + encodingConfig simappparams.EncodingConfig +} + +func (suite *GenTxTestSuite) SetupTest() { + checkTx := false + app := simapp.Setup(checkTx) + suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{}) + suite.app = app + + suite.encodingConfig = simapp.MakeEncodingConfig() +} + +func (suite *GenTxTestSuite) setAccountBalance(addr sdk.AccAddress, amount int64) json.RawMessage { + acc := suite.app.AccountKeeper.NewAccountWithAddress(suite.ctx, addr) + suite.app.AccountKeeper.SetAccount(suite.ctx, acc) + + err := suite.app.BankKeeper.SetBalances( + suite.ctx, addr, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 25)}, + ) + suite.Require().NoError(err) + + bankGenesisState := suite.app.BankKeeper.ExportGenesis(suite.ctx) + bankGenesis, err := suite.encodingConfig.Amino.MarshalJSON(bankGenesisState) // TODO switch this to use Marshaler + suite.Require().NoError(err) + + return bankGenesis +} + +func (suite *GenTxTestSuite) TestSetGenTxsInAppGenesisState() { + var ( + txBuilder = suite.encodingConfig.TxConfig.NewTxBuilder() + genTxs []sdk.Tx + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "one genesis transaction", + func() { + err := txBuilder.SetMsgs(msg1) + suite.Require().NoError(err) + tx := txBuilder.GetTx() + genTxs = []sdk.Tx{tx} + }, + true, + }, + { + "two genesis transactions", + func() { + err := txBuilder.SetMsgs(msg1, msg2) + suite.Require().NoError(err) + tx := txBuilder.GetTx() + genTxs = []sdk.Tx{tx} + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() + cdc := suite.encodingConfig.Marshaler + txJSONEncoder := suite.encodingConfig.TxConfig.TxJSONEncoder() + + tc.malleate() + appGenesisState, err := genutil.SetGenTxsInAppGenesisState(cdc, txJSONEncoder, make(map[string]json.RawMessage), genTxs) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().NotNil(appGenesisState[types.ModuleName]) + + var genesisState types.GenesisState + err := cdc.UnmarshalJSON(appGenesisState[types.ModuleName], &genesisState) + suite.Require().NoError(err) + suite.Require().NotNil(genesisState.GenTxs) + } else { + suite.Require().Error(err) + } + }) + } +} + +func (suite *GenTxTestSuite) TestValidateAccountInGenesis() { + var ( + appGenesisState = make(map[string]json.RawMessage) + coins sdk.Coins + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "no accounts", + func() { + coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)} + }, + false, + }, + { + "account without balance in the genesis state", + func() { + coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 0)} + appGenesisState[banktypes.ModuleName] = suite.setAccountBalance(addr2, 50) + }, + false, + }, + { + "account without enough funds of default bond denom", + func() { + coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 50)} + appGenesisState[banktypes.ModuleName] = suite.setAccountBalance(addr1, 25) + }, + false, + }, + { + "account with enough funds of default bond denom", + func() { + coins = sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)} + appGenesisState[banktypes.ModuleName] = suite.setAccountBalance(addr1, 25) + }, + true, + }, + } + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() + cdc := suite.encodingConfig.Marshaler + + suite.app.StakingKeeper.SetParams(suite.ctx, stakingtypes.DefaultParams()) + stakingGenesisState := staking.ExportGenesis(suite.ctx, suite.app.StakingKeeper) + suite.Require().Equal(stakingGenesisState.Params, stakingtypes.DefaultParams()) + stakingGenesis, err := cdc.MarshalJSON(stakingGenesisState) // TODO switch this to use Marshaler + suite.Require().NoError(err) + appGenesisState[stakingtypes.ModuleName] = stakingGenesis + + tc.malleate() + err = genutil.ValidateAccountInGenesis( + appGenesisState, banktypes.GenesisBalancesIterator{}, + addr1, coins, cdc, + ) + + if tc.expPass { + suite.Require().NoError(err) + } else { + suite.Require().Error(err) + } + + }) + } +} + +func (suite *GenTxTestSuite) TestDeliverGenTxs() { + var ( + genTxs []json.RawMessage + txBuilder = suite.encodingConfig.TxConfig.NewTxBuilder() + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "no signature supplied", + func() { + err := txBuilder.SetMsgs(msg1) + suite.Require().NoError(err) + + genTxs = make([]json.RawMessage, 1) + tx, err := suite.encodingConfig.TxConfig.TxJSONEncoder()(txBuilder.GetTx()) + suite.Require().NoError(err) + genTxs[0] = tx + }, + false, + }, + { + "success", + func() { + _ = suite.setAccountBalance(addr1, 50) + _ = suite.setAccountBalance(addr2, 0) + + msg := banktypes.NewMsgSend(addr1, addr2, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 1)}) + tx, err := helpers.GenTx( + suite.encodingConfig.TxConfig, + []sdk.Msg{msg}, + sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 10)}, + helpers.DefaultGenTxGas, + suite.ctx.ChainID(), + []uint64{0}, + []uint64{0}, + priv1, + ) + suite.Require().NoError(err) + + genTxs = make([]json.RawMessage, 1) + genTx, err := suite.encodingConfig.TxConfig.TxJSONEncoder()(tx) + suite.Require().NoError(err) + genTxs[0] = genTx + }, + true, + }, + } + + for _, tc := range testCases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() + + tc.malleate() + + if tc.expPass { + suite.Require().NotPanics(func() { + genutil.DeliverGenTxs( + suite.ctx, genTxs, suite.app.StakingKeeper, suite.app.BaseApp.DeliverTx, + suite.encodingConfig.TxConfig, + ) + }) + } else { + suite.Require().Panics(func() { + genutil.DeliverGenTxs( + suite.ctx, genTxs, suite.app.StakingKeeper, suite.app.BaseApp.DeliverTx, + suite.encodingConfig.TxConfig, + ) + }) + } + }) + } +} + +func TestGenTxTestSuite(t *testing.T) { + suite.Run(t, new(GenTxTestSuite)) } diff --git a/x/genutil/module.go b/x/genutil/module.go index 06f16c93d2e5..dc7bd72e57c6 100644 --- a/x/genutil/module.go +++ b/x/genutil/module.go @@ -43,13 +43,13 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the genutil module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (b AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, txEncodingConfig client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) } - return types.ValidateGenesis(data) + return types.ValidateGenesis(data, txEncodingConfig.TxJSONDecoder()) } // RegisterRESTRoutes registers the REST routes for the genutil module. @@ -67,20 +67,24 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { return nil } type AppModule struct { AppModuleBasic - accountKeeper types.AccountKeeper - stakingKeeper types.StakingKeeper - deliverTx deliverTxfn + accountKeeper types.AccountKeeper + stakingKeeper types.StakingKeeper + deliverTx deliverTxfn + txEncodingConfig client.TxEncodingConfig } // NewAppModule creates a new AppModule object func NewAppModule(accountKeeper types.AccountKeeper, - stakingKeeper types.StakingKeeper, deliverTx deliverTxfn) module.AppModule { + stakingKeeper types.StakingKeeper, deliverTx deliverTxfn, + txEncodingConfig client.TxEncodingConfig, +) module.AppModule { return module.NewGenesisOnlyAppModule(AppModule{ - AppModuleBasic: AppModuleBasic{}, - accountKeeper: accountKeeper, - stakingKeeper: stakingKeeper, - deliverTx: deliverTx, + AppModuleBasic: AppModuleBasic{}, + accountKeeper: accountKeeper, + stakingKeeper: stakingKeeper, + deliverTx: deliverTx, + txEncodingConfig: txEncodingConfig, }) } @@ -89,7 +93,7 @@ func NewAppModule(accountKeeper types.AccountKeeper, func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState types.GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - return InitGenesis(ctx, types.ModuleCdc, am.stakingKeeper, am.deliverTx, genesisState) + return InitGenesis(ctx, am.stakingKeeper, am.deliverTx, genesisState, am.txEncodingConfig) } // ExportGenesis returns the exported genesis state as raw bytes for the genutil diff --git a/x/genutil/types/genesis_state.go b/x/genutil/types/genesis_state.go index ef74b3590441..034f6737795a 100644 --- a/x/genutil/types/genesis_state.go +++ b/x/genutil/types/genesis_state.go @@ -9,7 +9,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + sdk "github.com/cosmos/cosmos-sdk/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -36,9 +36,9 @@ func DefaultGenesisState() GenesisState { } } -// NewGenesisStateFromStdTx creates a new GenesisState object +// NewGenesisStateFromTx creates a new GenesisState object // from auth transactions -func NewGenesisStateFromStdTx(genTxs []authtypes.StdTx) GenesisState { +func NewGenesisStateFromTx(genTxs []sdk.Tx) GenesisState { genTxsBz := make([]json.RawMessage, len(genTxs)) for i, genTx := range genTxs { genTxsBz[i] = ModuleCdc.MustMarshalJSON(genTx) @@ -98,17 +98,18 @@ func GenesisStateFromGenFile(cdc codec.JSONMarshaler, genFile string) (genesisSt } // ValidateGenesis validates GenTx transactions -func ValidateGenesis(genesisState GenesisState) error { +func ValidateGenesis(genesisState GenesisState, txJSONDecoder sdk.TxDecoder) error { for i, genTx := range genesisState.GenTxs { - var tx authtypes.StdTx - if err := ModuleCdc.UnmarshalJSON(genTx, &tx); err != nil { + var tx sdk.Tx + tx, err := txJSONDecoder(genTx) + if err != nil { return err } msgs := tx.GetMsgs() if len(msgs) != 1 { return errors.New( - "must provide genesis StdTx with exactly 1 CreateValidator message") + "must provide genesis Tx with exactly 1 CreateValidator message") } // TODO: abstract back to staking diff --git a/x/genutil/types/genesis_state_test.go b/x/genutil/types/genesis_state_test.go index b82a89b98a13..3be955e610d4 100644 --- a/x/genutil/types/genesis_state_test.go +++ b/x/genutil/types/genesis_state_test.go @@ -1,4 +1,4 @@ -package types +package types_test import ( "encoding/json" @@ -8,8 +8,10 @@ import ( "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/simapp/params" sdk "github.com/cosmos/cosmos-sdk/types" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/cosmos/cosmos-sdk/x/genutil/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" ) @@ -19,10 +21,10 @@ var ( ) func TestNetGenesisState(t *testing.T) { - gen := NewGenesisState(nil) + gen := types.NewGenesisState(nil) assert.NotNil(t, gen.GenTxs) // https://github.com/cosmos/cosmos-sdk/issues/5086 - gen = NewGenesisState( + gen = types.NewGenesisState( []json.RawMessage{ []byte(`{"foo":"bar"}`), }, @@ -31,7 +33,6 @@ func TestNetGenesisState(t *testing.T) { } func TestValidateGenesisMultipleMessages(t *testing.T) { - desc := stakingtypes.NewDescription("testname", "", "", "", "") comm := stakingtypes.CommissionRates{} @@ -41,10 +42,15 @@ func TestValidateGenesisMultipleMessages(t *testing.T) { msg2 := stakingtypes.NewMsgCreateValidator(sdk.ValAddress(pk2.Address()), pk2, sdk.NewInt64Coin(sdk.DefaultBondDenom, 50), desc, comm, sdk.OneInt()) - genTxs := authtypes.NewStdTx([]sdk.Msg{msg1, msg2}, authtypes.StdFee{}, nil, "") - genesisState := NewGenesisStateFromStdTx([]authtypes.StdTx{genTxs}) + txGen := params.MakeEncodingConfig().TxConfig + txBuilder := txGen.NewTxBuilder() + err := txBuilder.SetMsgs(msg1, msg2) + require.NoError(t, err) + + tx := txBuilder.GetTx() + genesisState := types.NewGenesisStateFromTx([]sdk.Tx{tx}) - err := ValidateGenesis(genesisState) + err = types.ValidateGenesis(genesisState, simapp.MakeEncodingConfig().TxConfig.TxJSONDecoder()) require.Error(t, err) } @@ -53,9 +59,14 @@ func TestValidateGenesisBadMessage(t *testing.T) { msg1 := stakingtypes.NewMsgEditValidator(sdk.ValAddress(pk1.Address()), desc, nil, nil) - genTxs := authtypes.NewStdTx([]sdk.Msg{msg1}, authtypes.StdFee{}, nil, "") - genesisState := NewGenesisStateFromStdTx([]authtypes.StdTx{genTxs}) + txGen := params.MakeEncodingConfig().TxConfig + txBuilder := txGen.NewTxBuilder() + err := txBuilder.SetMsgs(msg1) + require.NoError(t, err) + + tx := txBuilder.GetTx() + genesisState := types.NewGenesisStateFromTx([]sdk.Tx{tx}) - err := ValidateGenesis(genesisState) + err = types.ValidateGenesis(genesisState, simapp.MakeEncodingConfig().TxConfig.TxJSONDecoder()) require.Error(t, err) } diff --git a/x/gov/module.go b/x/gov/module.go index ab2745fffa81..17c9265dc50f 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -64,7 +64,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the gov module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/ibc-transfer/module.go b/x/ibc-transfer/module.go index 09698fee50ba..1b1b72da2929 100644 --- a/x/ibc-transfer/module.go +++ b/x/ibc-transfer/module.go @@ -56,7 +56,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the ibc transfer module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/ibc/module.go b/x/ibc/module.go index d27a883597c7..4c85ac062821 100644 --- a/x/ibc/module.go +++ b/x/ibc/module.go @@ -54,7 +54,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the ibc module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var gs types.GenesisState if err := cdc.UnmarshalJSON(bz, &gs); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", host.ModuleName, err) diff --git a/x/mint/module.go b/x/mint/module.go index 28e5b5c695d5..99375854da62 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -54,7 +54,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the mint module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/params/module.go b/x/params/module.go index 662adea4a356..49fc15a98092 100644 --- a/x/params/module.go +++ b/x/params/module.go @@ -47,7 +47,9 @@ func (AppModuleBasic) RegisterCodec(cdc *codec.Codec) { func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { return nil } // ValidateGenesis performs genesis state validation for the params module. -func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { return nil } +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, config client.TxEncodingConfig, _ json.RawMessage) error { + return nil +} // RegisterRESTRoutes registers the REST routes for the params module. func (AppModuleBasic) RegisterRESTRoutes(_ client.Context, _ *mux.Router) {} diff --git a/x/slashing/module.go b/x/slashing/module.go index db802965db72..038416ffa9fa 100644 --- a/x/slashing/module.go +++ b/x/slashing/module.go @@ -61,7 +61,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the slashing module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/staking/module.go b/x/staking/module.go index 1cc38aef612a..84dc2c582613 100644 --- a/x/staking/module.go +++ b/x/staking/module.go @@ -59,7 +59,7 @@ func (AppModuleBasic) DefaultGenesis(cdc codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis performs genesis state validation for the staking module. -func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, bz json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(cdc codec.JSONMarshaler, config client.TxEncodingConfig, bz json.RawMessage) error { var data types.GenesisState if err := cdc.UnmarshalJSON(bz, &data); err != nil { return fmt.Errorf("failed to unmarshal %s genesis state: %w", types.ModuleName, err) diff --git a/x/upgrade/module.go b/x/upgrade/module.go index 314c5c9b7dc7..f5f2ab22d42e 100644 --- a/x/upgrade/module.go +++ b/x/upgrade/module.go @@ -110,7 +110,7 @@ func (AppModuleBasic) DefaultGenesis(_ codec.JSONMarshaler) json.RawMessage { } // ValidateGenesis is always successful, as we ignore the value -func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, _ json.RawMessage) error { +func (AppModuleBasic) ValidateGenesis(_ codec.JSONMarshaler, config client.TxEncodingConfig, _ json.RawMessage) error { return nil }