diff --git a/client/test_helpers.go b/client/test_helpers.go new file mode 100644 index 000000000000..4c16ce63bfbc --- /dev/null +++ b/client/test_helpers.go @@ -0,0 +1,36 @@ +package client + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// TestAccountRetriever is an AccountRetriever that can be used in unit tests +type TestAccountRetriever struct { + Accounts map[string]struct { + Address sdk.AccAddress + Num uint64 + Seq uint64 + } +} + +var _ AccountRetriever = TestAccountRetriever{} + +// EnsureExists implements AccountRetriever.EnsureExists +func (t TestAccountRetriever) EnsureExists(_ NodeQuerier, addr sdk.AccAddress) error { + _, ok := t.Accounts[addr.String()] + if !ok { + return fmt.Errorf("account %s not found", addr) + } + return nil +} + +// GetAccountNumberSequence implements AccountRetriever.GetAccountNumberSequence +func (t TestAccountRetriever) GetAccountNumberSequence(_ NodeQuerier, addr sdk.AccAddress) (accNum uint64, accSeq uint64, err error) { + acc, ok := t.Accounts[addr.String()] + if !ok { + return 0, 0, fmt.Errorf("account %s not found", addr) + } + return acc.Num, acc.Seq, nil +} diff --git a/client/tx/tx.go b/client/tx/tx.go index ea9563f3a63c..384093852a9b 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -114,7 +114,7 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { return err } - txBytes, err := clientCtx.TxGenerator.MarshalTx(tx.GetTx()) + txBytes, err := clientCtx.TxGenerator.TxEncoder()(tx.GetTx()) if err != nil { return err } @@ -244,7 +244,7 @@ func BuildSimTx(txf Factory, msgs ...sdk.Msg) ([]byte, error) { return nil, err } - return txf.txGenerator.MarshalTx(tx.GetTx()) + return txf.txGenerator.TxEncoder()(tx.GetTx()) } // CalculateGas simulates the execution of a transaction and returns the diff --git a/client/tx_generator.go b/client/tx_generator.go index b7c4c1666120..70b2d3368ce4 100644 --- a/client/tx_generator.go +++ b/client/tx_generator.go @@ -13,7 +13,11 @@ type ( TxGenerator interface { NewTxBuilder() TxBuilder SignModeHandler() signing.SignModeHandler - MarshalTx(tx sdk.Tx) ([]byte, error) + + 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/codec/testdata/test_helper.go b/codec/testdata/test_helper.go index b19d06fa96b6..4703a556e50b 100644 --- a/codec/testdata/test_helper.go +++ b/codec/testdata/test_helper.go @@ -1,8 +1,9 @@ package testdata import ( - "github.com/cosmos/cosmos-sdk/codec/types" "github.com/tendermint/go-amino" + + "github.com/cosmos/cosmos-sdk/codec/types" ) func NewTestInterfaceRegistry() types.InterfaceRegistry { diff --git a/simapp/app.go b/simapp/app.go index c93e4ba8ee0b..d142f9a6a138 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -13,7 +13,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/rpc" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/codec/testdata" - "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/server/api" "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" @@ -130,7 +129,7 @@ var _ App = (*SimApp)(nil) type SimApp struct { *baseapp.BaseApp cdc *codec.Codec - appCodec *std.Codec + appCodec codec.Marshaler invCheckPeriod uint @@ -401,13 +400,9 @@ func NewSimApp( // MakeCodecs constructs the *std.Codec and *codec.Codec instances used by // simapp. It is useful for tests and clients who do not want to construct the // full simapp -func MakeCodecs() (*std.Codec, *codec.Codec) { - cdc := std.MakeCodec(ModuleBasics) - interfaceRegistry := types.NewInterfaceRegistry() - std.RegisterInterfaces(interfaceRegistry) - ModuleBasics.RegisterInterfaceModules(interfaceRegistry) - appCodec := std.NewAppCodec(cdc, interfaceRegistry) - return appCodec, cdc +func MakeCodecs() (codec.Marshaler, *codec.Codec) { + config := MakeEncodingConfig() + return config.Marshaler, config.Amino } // Name returns the name of the App @@ -468,7 +463,7 @@ func (app *SimApp) Codec() *codec.Codec { // // NOTE: This is solely to be used for testing purposes as it may be desirable // for modules to register their own custom testing types. -func (app *SimApp) AppCodec() *std.Codec { +func (app *SimApp) AppCodec() codec.Marshaler { return app.appCodec } diff --git a/simapp/cmd/simcli/main.go b/simapp/cmd/simcli/main.go index b7df816140fe..1b3eae7194c9 100644 --- a/simapp/cmd/simcli/main.go +++ b/simapp/cmd/simcli/main.go @@ -5,6 +5,8 @@ import ( "os" "path" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" @@ -13,7 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/flags" "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/rpc" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -23,11 +24,11 @@ import ( ) var ( - appCodec, cdc = simapp.MakeCodecs() + encodingConfig = simapp.MakeEncodingConfig() ) func init() { - authclient.Codec = appCodec + authclient.Codec = encodingConfig.Marshaler } func main() { @@ -60,8 +61,8 @@ func main() { rootCmd.AddCommand( rpc.StatusCommand(), client.ConfigCmd(simapp.DefaultCLIHome), - queryCmd(cdc), - txCmd(cdc), + queryCmd(encodingConfig), + txCmd(encodingConfig), flags.LineBreak, flags.LineBreak, keys.Commands(), @@ -79,7 +80,7 @@ func main() { } } -func queryCmd(cdc *codec.Codec) *cobra.Command { +func queryCmd(config simappparams.EncodingConfig) *cobra.Command { queryCmd := &cobra.Command{ Use: "query", Aliases: []string{"q"}, @@ -89,6 +90,8 @@ func queryCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } + cdc := config.Amino + queryCmd.AddCommand( authcmd.GetAccountCmd(cdc), flags.LineBreak, @@ -102,14 +105,14 @@ func queryCmd(cdc *codec.Codec) *cobra.Command { // add modules' query commands clientCtx := client.Context{} clientCtx = clientCtx. - WithJSONMarshaler(appCodec). + WithJSONMarshaler(config.Marshaler). WithCodec(cdc) simapp.ModuleBasics.AddQueryCommands(queryCmd, clientCtx) return queryCmd } -func txCmd(cdc *codec.Codec) *cobra.Command { +func txCmd(config simappparams.EncodingConfig) *cobra.Command { txCmd := &cobra.Command{ Use: "tx", Short: "Transactions subcommands", @@ -118,24 +121,25 @@ func txCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } + cdc := config.Amino clientCtx := client.Context{} clientCtx = clientCtx. - WithJSONMarshaler(appCodec). - WithTxGenerator(types.StdTxGenerator{Cdc: cdc}). - WithAccountRetriever(types.NewAccountRetriever(appCodec)). + WithJSONMarshaler(config.Marshaler). + WithTxGenerator(config.TxGenerator). + WithAccountRetriever(types.NewAccountRetriever(config.Marshaler)). WithCodec(cdc) txCmd.AddCommand( bankcmd.NewSendTxCmd(clientCtx), flags.LineBreak, - authcmd.GetSignCommand(cdc), + authcmd.GetSignCommand(clientCtx), authcmd.GetSignBatchCommand(cdc), - authcmd.GetMultiSignCommand(cdc), - authcmd.GetValidateSignaturesCommand(cdc), + authcmd.GetMultiSignCommand(clientCtx), + authcmd.GetValidateSignaturesCommand(clientCtx), flags.LineBreak, - authcmd.GetBroadcastCommand(cdc), - authcmd.GetEncodeCommand(cdc), - authcmd.GetDecodeCommand(cdc), + authcmd.GetBroadcastCommand(clientCtx), + authcmd.GetEncodeCommand(clientCtx), + authcmd.GetDecodeCommand(clientCtx), flags.LineBreak, ) diff --git a/simapp/cmd/simd/genaccounts.go b/simapp/cmd/simd/genaccounts.go index ff85f80009c4..8042f9591312 100644 --- a/simapp/cmd/simd/genaccounts.go +++ b/simapp/cmd/simd/genaccounts.go @@ -7,8 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/std" - "github.com/spf13/cobra" "github.com/spf13/viper" @@ -34,7 +32,7 @@ const ( // AddGenesisAccountCmd returns add-genesis-account cobra Command. func AddGenesisAccountCmd( - ctx *server.Context, depCdc codec.JSONMarshaler, cdc *std.Codec, defaultNodeHome, defaultClientHome string, + ctx *server.Context, depCdc codec.JSONMarshaler, cdc codec.Marshaler, defaultNodeHome, defaultClientHome string, ) *cobra.Command { cmd := &cobra.Command{ diff --git a/simapp/encoding.go b/simapp/encoding.go new file mode 100644 index 000000000000..58f899edd7a5 --- /dev/null +++ b/simapp/encoding.go @@ -0,0 +1,18 @@ +package simapp + +import ( + "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/std" +) + +// MakeEncodingConfig creates an EncodingConfig for an amino based test configuration. +// +// TODO: this file should add a "+build test_amino" flag for #6190 and a proto.go file with a protobuf configuration +func MakeEncodingConfig() params.EncodingConfig { + encodingConfig := params.MakeEncodingConfig() + std.RegisterCodec(encodingConfig.Amino) + std.RegisterInterfaces(encodingConfig.InterfaceRegistry) + ModuleBasics.RegisterCodec(encodingConfig.Amino) + ModuleBasics.RegisterInterfaceModules(encodingConfig.InterfaceRegistry) + return encodingConfig +} diff --git a/simapp/params/amino.go b/simapp/params/amino.go new file mode 100644 index 000000000000..f16dda4c67fb --- /dev/null +++ b/simapp/params/amino.go @@ -0,0 +1,23 @@ +package params + +import ( + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// MakeEncodingConfig creates an EncodingConfig for an amino based test configuration. +// +// TODO: this file should add a "+build test_amino" flag for #6190 and a proto.go file with a protobuf configuration +func MakeEncodingConfig() EncodingConfig { + cdc := codec.New() + interfaceRegistry := types.NewInterfaceRegistry() + marshaler := codec.NewHybridCodec(cdc, interfaceRegistry) + + return EncodingConfig{ + InterfaceRegistry: interfaceRegistry, + Marshaler: marshaler, + TxGenerator: authtypes.StdTxGenerator{Cdc: cdc}, + Amino: cdc, + } +} diff --git a/simapp/params/encoding.go b/simapp/params/encoding.go new file mode 100644 index 000000000000..bb63e6002237 --- /dev/null +++ b/simapp/params/encoding.go @@ -0,0 +1,16 @@ +package params + +import ( + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/codec/types" +) + +// EncodingConfig specifies the concrete encoding types to use for a given app. +// This is provided for compatibility between protobuf and amino implementations. +type EncodingConfig struct { + InterfaceRegistry types.InterfaceRegistry + Marshaler codec.Marshaler + TxGenerator client.TxGenerator + Amino *codec.Codec +} diff --git a/std/codec.go b/std/codec.go index ce9ded25a9c0..80f6072a5fac 100644 --- a/std/codec.go +++ b/std/codec.go @@ -9,22 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/x/auth/vesting" ) -// Codec defines the application-level codec. This codec contains all the -// required module-specific codecs that are to be provided upon initialization. -type Codec struct { - codec.Marshaler - - // Keep reference to the amino codec to allow backwards compatibility along - // with type, and interface registration. - amino *codec.Codec - - anyUnpacker types.AnyUnpacker -} - -func NewAppCodec(amino *codec.Codec, anyUnpacker types.AnyUnpacker) *Codec { - return &Codec{Marshaler: codec.NewHybridCodec(amino, anyUnpacker), amino: amino, anyUnpacker: anyUnpacker} -} - // ---------------------------------------------------------------------------- // necessary types and interfaces registered. This codec is provided to all the // modules the application depends on. @@ -35,11 +19,15 @@ func MakeCodec(bm module.BasicManager) *codec.Codec { cdc := codec.New() bm.RegisterCodec(cdc) + RegisterCodec(cdc) + + return cdc +} + +func RegisterCodec(cdc *codec.Codec) { vesting.RegisterCodec(cdc) sdk.RegisterCodec(cdc) cryptocodec.RegisterCrypto(cdc) - - return cdc } // RegisterInterfaces registers Interfaces from sdk/types and vesting diff --git a/tests/cli/fixtures.go b/tests/cli/fixtures.go index 564514ddc114..b5837f5c9ae3 100644 --- a/tests/cli/fixtures.go +++ b/tests/cli/fixtures.go @@ -7,33 +7,30 @@ import ( "testing" "github.com/stretchr/testify/require" - tmtypes "github.com/tendermint/tendermint/types" - "github.com/cosmos/cosmos-sdk/std" + tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/simapp" -) - -var ( - cdc = std.MakeCodec(simapp.ModuleBasics) + "github.com/cosmos/cosmos-sdk/simapp/params" ) // Fixtures is used to setup the testing environment type Fixtures struct { - BuildDir string - RootDir string - SimdBinary string - SimcliBinary string - ChainID string - RPCAddr string - Port string - SimdHome string - SimcliHome string - P2PAddr string - Cdc *codec.Codec - T *testing.T + BuildDir string + RootDir string + SimdBinary string + SimcliBinary string + ChainID string + RPCAddr string + Port string + SimdHome string + SimcliHome string + P2PAddr string + Cdc *codec.Codec + EncodingConfig params.EncodingConfig + T *testing.T } // NewFixtures creates a new instance of Fixtures with many vars set @@ -52,18 +49,21 @@ func NewFixtures(t *testing.T) *Fixtures { t.Skip("builddir is empty, skipping") } + encodingConfig := simapp.MakeEncodingConfig() + return &Fixtures{ - T: t, - BuildDir: buildDir, - RootDir: tmpDir, - SimdBinary: filepath.Join(buildDir, "simd"), - SimcliBinary: filepath.Join(buildDir, "simcli"), - SimdHome: filepath.Join(tmpDir, ".simd"), - SimcliHome: filepath.Join(tmpDir, ".simcli"), - RPCAddr: servAddr, - P2PAddr: p2pAddr, - Cdc: cdc, - Port: port, + T: t, + BuildDir: buildDir, + RootDir: tmpDir, + SimdBinary: filepath.Join(buildDir, "simd"), + SimcliBinary: filepath.Join(buildDir, "simcli"), + SimdHome: filepath.Join(tmpDir, ".simd"), + SimcliHome: filepath.Join(tmpDir, ".simcli"), + RPCAddr: servAddr, + P2PAddr: p2pAddr, + Cdc: encodingConfig.Amino, + EncodingConfig: encodingConfig, + Port: port, } } diff --git a/tests/cli/simd_test.go b/tests/cli/simd_test.go index b1cabadeb864..329127925bc9 100644 --- a/tests/cli/simd_test.go +++ b/tests/cli/simd_test.go @@ -11,8 +11,6 @@ import ( "github.com/stretchr/testify/require" tmtypes "github.com/tendermint/tendermint/types" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - "github.com/cosmos/cosmos-sdk/std" "github.com/cosmos/cosmos-sdk/tests/cli" sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -99,8 +97,7 @@ func TestCLISimdAddGenesisAccount(t *testing.T) { genesisState := f.GenesisState() - interfaceRegistry := codectypes.NewInterfaceRegistry() - appCodec := std.NewAppCodec(f.Cdc, interfaceRegistry) + appCodec := f.EncodingConfig.Marshaler accounts := authtypes.GetGenesisStateFromAppState(appCodec, genesisState).Accounts balances := banktypes.GetGenesisStateFromAppState(f.Cdc, genesisState).Balances diff --git a/x/auth/client/cli/broadcast.go b/x/auth/client/cli/broadcast.go index 61567b3e06bd..0802219867ad 100644 --- a/x/auth/client/cli/broadcast.go +++ b/x/auth/client/cli/broadcast.go @@ -8,12 +8,11 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" ) // GetBroadcastCommand returns the tx broadcast command. -func GetBroadcastCommand(cdc *codec.Codec) *cobra.Command { +func GetBroadcastCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "broadcast [file_path]", Short: "Broadcast transactions generated offline", @@ -26,18 +25,18 @@ $ tx broadcast ./mytxn.json `), Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - clientCtx := client.NewContext().WithCodec(cdc).WithJSONMarshaler(cdc) + clientCtx = clientCtx.Init() if clientCtx.Offline { return errors.New("cannot broadcast tx during offline mode") } - stdTx, err := authclient.ReadStdTxFromFile(clientCtx.Codec, args[0]) + stdTx, err := authclient.ReadTxFromFile(clientCtx, args[0]) if err != nil { return err } - txBytes, err := clientCtx.Codec.MarshalBinaryBare(stdTx) + txBytes, err := clientCtx.TxGenerator.TxEncoder()(stdTx) if err != nil { return err } diff --git a/x/auth/client/cli/broadcast_test.go b/x/auth/client/cli/broadcast_test.go index 11d41df89e51..2aa881bb0bcc 100644 --- a/x/auth/client/cli/broadcast_test.go +++ b/x/auth/client/cli/broadcast_test.go @@ -5,17 +5,20 @@ import ( "path/filepath" "testing" + "github.com/cosmos/cosmos-sdk/client" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/spf13/viper" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/tests" ) func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { - cdc := codec.New() - cmd := GetBroadcastCommand(cdc) + clientCtx := client.Context{} + clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) + cmd := GetBroadcastCommand(clientCtx) viper.Set(flags.FlagOffline, true) @@ -24,8 +27,9 @@ func TestGetBroadcastCommand_OfflineFlag(t *testing.T) { } func TestGetBroadcastCommand_WithoutOfflineFlag(t *testing.T) { - cdc := codec.New() - cmd := GetBroadcastCommand(cdc) + clientCtx := client.Context{} + clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) + cmd := GetBroadcastCommand(clientCtx) viper.Set(flags.FlagOffline, false) diff --git a/x/auth/client/cli/cli_test.go b/x/auth/client/cli/cli_test.go index 0bb8d2c3eae1..c09915a30b49 100644 --- a/x/auth/client/cli/cli_test.go +++ b/x/auth/client/cli/cli_test.go @@ -3,7 +3,6 @@ package cli_test import ( - "encoding/base64" "fmt" "strings" "testing" @@ -15,7 +14,6 @@ import ( "github.com/cosmos/cosmos-sdk/tests/cli" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/client/testutil" - "github.com/cosmos/cosmos-sdk/x/auth/types" bankcli "github.com/cosmos/cosmos-sdk/x/bank/client/testutil" ) @@ -298,18 +296,13 @@ func TestCLIEncode(t *testing.T) { jsonTxFile, cleanup := tests.WriteToNewTempFile(t, stdout) t.Cleanup(cleanup) - // Run the encode command, and trim the extras from the stdout capture + // Run the encode command success, base64Encoded, _ := testutil.TxEncode(f, jsonTxFile.Name()) require.True(t, success) trimmedBase64 := strings.Trim(base64Encoded, "\"\n") - - // Decode the base64 - decodedBytes, err := base64.StdEncoding.DecodeString(trimmedBase64) - require.Nil(t, err) - - // Check that the transaction decodes as epxceted - var decodedTx types.StdTx - require.Nil(t, f.Cdc.UnmarshalBinaryBare(decodedBytes, &decodedTx)) + // Check that the transaction decodes as expected + success, stdout, stderr = testutil.TxDecode(f, trimmedBase64) + decodedTx := cli.UnmarshalStdTx(t, f.Cdc, stdout) require.Equal(t, "deadbeef", decodedTx.Memo) } diff --git a/x/auth/client/cli/decode.go b/x/auth/client/cli/decode.go index a5b8b46a4cb2..2fde4790a39c 100644 --- a/x/auth/client/cli/decode.go +++ b/x/auth/client/cli/decode.go @@ -9,29 +9,27 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) const flagHex = "hex" -// GetDecodeCommand returns the decode command to take Amino-serialized bytes +// GetDecodeCommand returns the decode command to take serialized bytes // and turn it into a JSONified transaction. -func GetDecodeCommand(codec *codec.Codec) *cobra.Command { +func GetDecodeCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "decode [amino-byte-string]", - Short: "Decode an amino-encoded transaction string.", + Short: "Decode an binary encoded transaction string.", Args: cobra.ExactArgs(1), - RunE: runDecodeTxString(codec), + RunE: runDecodeTxString(clientCtx), } cmd.Flags().BoolP(flagHex, "x", false, "Treat input as hexadecimal instead of base64") return flags.PostCommands(cmd)[0] } -func runDecodeTxString(cdc *codec.Codec) func(cmd *cobra.Command, args []string) (err error) { +func runDecodeTxString(clientCtx client.Context) func(cmd *cobra.Command, args []string) (err error) { return func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.NewContext().WithCodec(cdc).WithOutput(cmd.OutOrStdout()).WithJSONMarshaler(cdc) + clientCtx = clientCtx.Init().WithOutput(cmd.OutOrStdout()) var txBytes []byte if viper.GetBool(flagHex) { @@ -43,12 +41,11 @@ func runDecodeTxString(cdc *codec.Codec) func(cmd *cobra.Command, args []string) return err } - var stdTx authtypes.StdTx - err = clientCtx.Codec.UnmarshalBinaryBare(txBytes, &stdTx) + tx, err := clientCtx.TxGenerator.TxDecoder()(txBytes) if err != nil { return err } - return clientCtx.PrintOutput(stdTx) + return clientCtx.PrintOutput(tx) } } diff --git a/x/auth/client/cli/encode.go b/x/auth/client/cli/encode.go index 3a0726729907..3ca0b46b3aed 100644 --- a/x/auth/client/cli/encode.go +++ b/x/auth/client/cli/encode.go @@ -7,7 +7,6 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" ) @@ -20,7 +19,7 @@ func (txr txEncodeRespStr) String() string { // GetEncodeCommand returns the encode command to take a JSONified transaction and turn it into // Amino-serialized bytes -func GetEncodeCommand(cdc *codec.Codec) *cobra.Command { +func GetEncodeCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "encode [file]", Short: "Encode transactions generated offline", @@ -28,16 +27,16 @@ func GetEncodeCommand(cdc *codec.Codec) *cobra.Command { Read a transaction from , serialize it to the Amino wire protocol, and output it as base64. If you supply a dash (-) argument in place of an input filename, the command reads from standard input.`, Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, args []string) (err error) { - clientCtx := client.NewContext().WithCodec(cdc).WithJSONMarshaler(cdc) + RunE: func(cmd *cobra.Command, args []string) error { + cliCtx := clientCtx.Init() - stdTx, err := authclient.ReadStdTxFromFile(clientCtx.Codec, args[0]) + tx, err := authclient.ReadTxFromFile(cliCtx, args[0]) if err != nil { - return + return err } - // re-encode it via the Amino wire protocol - txBytes, err := clientCtx.Codec.MarshalBinaryBare(stdTx) + // re-encode it + txBytes, err := cliCtx.TxGenerator.TxEncoder()(tx) if err != nil { return err } diff --git a/x/auth/client/cli/encode_test.go b/x/auth/client/cli/encode_test.go new file mode 100644 index 000000000000..296160325405 --- /dev/null +++ b/x/auth/client/cli/encode_test.go @@ -0,0 +1,71 @@ +package cli + +import ( + "encoding/base64" + "testing" + + "github.com/cosmos/cosmos-sdk/client" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + "github.com/cosmos/cosmos-sdk/tests" + sdk "github.com/cosmos/cosmos-sdk/types" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + "github.com/stretchr/testify/require" +) + +func TestGetCommandEncode(t *testing.T) { + encodingConfig := simappparams.MakeEncodingConfig() + clientCtx := client.Context{} + clientCtx = clientCtx. + WithTxGenerator(encodingConfig.TxGenerator). + WithJSONMarshaler(encodingConfig.Marshaler) + + cmd := GetEncodeCommand(clientCtx) + authtypes.RegisterCodec(encodingConfig.Amino) + sdk.RegisterCodec(encodingConfig.Amino) + + txGen := encodingConfig.TxGenerator + + // Build a test transaction + fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) + stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo") + JSONEncoded, err := txGen.TxJSONEncoder()(stdTx) + require.NoError(t, err) + + txFile, cleanup := tests.WriteToNewTempFile(t, string(JSONEncoded)) + txFileName := txFile.Name() + t.Cleanup(cleanup) + + err = cmd.RunE(cmd, []string{txFileName}) + require.NoError(t, err) +} + +func TestGetCommandDecode(t *testing.T) { + encodingConfig := simappparams.MakeEncodingConfig() + + clientCtx := client.Context{} + clientCtx = clientCtx. + WithTxGenerator(encodingConfig.TxGenerator). + WithJSONMarshaler(encodingConfig.Marshaler) + + cmd := GetDecodeCommand(clientCtx) + + sdk.RegisterCodec(encodingConfig.Amino) + + txGen := encodingConfig.TxGenerator + clientCtx = clientCtx.WithTxGenerator(txGen) + + // Build a test transaction + fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) + stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo") + + // Encode transaction + txBytes, err := clientCtx.TxGenerator.TxEncoder()(stdTx) + require.NoError(t, err) + + // Convert the transaction into base64 encoded string + base64Encoded := base64.StdEncoding.EncodeToString(txBytes) + + // Execute the command + err = runDecodeTxString(clientCtx)(cmd, []string{base64Encoded}) + require.NoError(t, err) +} diff --git a/x/auth/client/cli/tx.go b/x/auth/client/cli/tx.go index 132d61ed3080..9bc30f396ec0 100644 --- a/x/auth/client/cli/tx.go +++ b/x/auth/client/cli/tx.go @@ -4,12 +4,11 @@ import ( "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/x/auth/types" ) // GetTxCmd returns the transaction commands for this module -func GetTxCmd(cdc *codec.Codec) *cobra.Command { +func GetTxCmd(clientCtx client.Context) *cobra.Command { txCmd := &cobra.Command{ Use: types.ModuleName, Short: "Auth transaction subcommands", @@ -18,10 +17,10 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { RunE: client.ValidateCmd, } txCmd.AddCommand( - GetMultiSignCommand(cdc), - GetSignCommand(cdc), - GetValidateSignaturesCommand(cdc), - GetSignBatchCommand(cdc), + GetMultiSignCommand(clientCtx), + GetSignCommand(clientCtx), + GetValidateSignaturesCommand(clientCtx), + GetSignBatchCommand(clientCtx.Codec), ) return txCmd } diff --git a/x/auth/client/cli/tx_multisign.go b/x/auth/client/cli/tx_multisign.go index c0af04548fb5..dd707f4468d4 100644 --- a/x/auth/client/cli/tx_multisign.go +++ b/x/auth/client/cli/tx_multisign.go @@ -22,7 +22,7 @@ import ( ) // GetSignCommand returns the sign command -func GetMultiSignCommand(cdc *codec.Codec) *cobra.Command { +func GetMultiSignCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "multisign [file] [name] [[signature]...]", Short: "Generate multisig signatures for transactions generated offline", @@ -45,7 +45,7 @@ recommended to set such parameters manually. version.ClientName, ), ), - RunE: makeMultiSignCmd(cdc), + RunE: makeMultiSignCmd(clientCtx), Args: cobra.MinimumNArgs(3), } @@ -56,9 +56,12 @@ recommended to set such parameters manually. return flags.PostCommands(cmd)[0] } -func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { +func makeMultiSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) (err error) { - stdTx, err := authclient.ReadStdTxFromFile(cdc, args[0]) + clientCtx = clientCtx.Init() + cdc := clientCtx.Codec + tx, err := authclient.ReadTxFromFile(clientCtx, args[0]) + stdTx := tx.(types.StdTx) if err != nil { return } @@ -80,7 +83,6 @@ func makeMultiSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) multisigPub := multisigInfo.GetPubKey().(multisig.PubKeyMultisigThreshold) multisigSig := multisig.NewMultisig(len(multisigPub.PubKeys)) - clientCtx := client.NewContextWithInput(inBuf).WithCodec(cdc) txBldr := types.NewTxBuilderFromCLI(inBuf) if !clientCtx.Offline { diff --git a/x/auth/client/cli/tx_sign.go b/x/auth/client/cli/tx_sign.go index dbeabf05600a..43341469e2ef 100644 --- a/x/auth/client/cli/tx_sign.go +++ b/x/auth/client/cli/tx_sign.go @@ -150,7 +150,7 @@ func setOutputFile(cmd *cobra.Command) (func(), error) { } // GetSignCommand returns the transaction sign command. -func GetSignCommand(codec *codec.Codec) *cobra.Command { +func GetSignCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "sign [file]", Short: "Sign transactions generated offline", @@ -170,7 +170,7 @@ key. It implies --signature-only. Full multisig signed transactions may eventual be generated via the 'multisign' command. `, PreRun: preSignCmd, - RunE: makeSignCmd(codec), + RunE: makeSignCmd(clientCtx), Args: cobra.ExactArgs(1), } @@ -199,12 +199,13 @@ func preSignCmd(cmd *cobra.Command, _ []string) { } } -func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { +func makeSignCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - clientCtx, txBldr, stdTx, err := readStdTxAndInitContexts(cdc, cmd, args[0]) + clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) if err != nil { return err } + stdTx := tx.(types.StdTx) // if --signature-only is on, then override --append var newTx types.StdTx @@ -231,7 +232,7 @@ func makeSignCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error return err } - json, err := getSignatureJSON(cdc, newTx, clientCtx.Indent, generateSignatureOnly) + json, err := getSignatureJSON(clientCtx.Codec, newTx, clientCtx.Indent, generateSignatureOnly) if err != nil { return err } diff --git a/x/auth/client/cli/validate_sigs.go b/x/auth/client/cli/validate_sigs.go index 630085da1297..e961f98bbc8b 100644 --- a/x/auth/client/cli/validate_sigs.go +++ b/x/auth/client/cli/validate_sigs.go @@ -9,14 +9,13 @@ import ( "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/crypto/types/multisig" sdk "github.com/cosmos/cosmos-sdk/types" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/auth/types" ) -func GetValidateSignaturesCommand(codec *codec.Codec) *cobra.Command { +func GetValidateSignaturesCommand(clientCtx client.Context) *cobra.Command { cmd := &cobra.Command{ Use: "validate-signatures [file]", Short: "Validate transactions signatures", @@ -29,19 +28,20 @@ given transaction. If the --offline flag is also set, signature validation over transaction will be not be performed as that will require RPC communication with a full node. `, PreRun: preSignCmd, - RunE: makeValidateSignaturesCmd(codec), + RunE: makeValidateSignaturesCmd(clientCtx), Args: cobra.ExactArgs(1), } return flags.PostCommands(cmd)[0] } -func makeValidateSignaturesCmd(cdc *codec.Codec) func(cmd *cobra.Command, args []string) error { +func makeValidateSignaturesCmd(clientCtx client.Context) func(cmd *cobra.Command, args []string) error { return func(cmd *cobra.Command, args []string) error { - clientCtx, txBldr, stdTx, err := readStdTxAndInitContexts(cdc, cmd, args[0]) + clientCtx, txBldr, tx, err := readStdTxAndInitContexts(clientCtx, cmd, args[0]) if err != nil { return err } + stdTx := tx.(types.StdTx) if !printAndValidateSigs(cmd, clientCtx, txBldr.ChainID(), stdTx, clientCtx.Offline) { return fmt.Errorf("signatures validation failed") @@ -133,16 +133,16 @@ func printAndValidateSigs( return success } -func readStdTxAndInitContexts(cdc *codec.Codec, cmd *cobra.Command, filename string) ( - client.Context, types.TxBuilder, types.StdTx, error, +func readStdTxAndInitContexts(clientCtx client.Context, cmd *cobra.Command, filename string) ( + client.Context, types.TxBuilder, sdk.Tx, error, ) { - stdTx, err := authclient.ReadStdTxFromFile(cdc, filename) + stdTx, err := authclient.ReadTxFromFile(clientCtx, filename) if err != nil { return client.Context{}, types.TxBuilder{}, types.StdTx{}, err } inBuf := bufio.NewReader(cmd.InOrStdin()) - clientCtx := client.NewContextWithInput(inBuf).WithCodec(cdc) + clientCtx = clientCtx.InitWithInput(inBuf) txBldr := types.NewTxBuilderFromCLI(inBuf) return clientCtx, txBldr, stdTx, nil diff --git a/x/auth/client/testutil/helpers.go b/x/auth/client/testutil/helpers.go index d04c51b9dbd8..23aa367cf27c 100644 --- a/x/auth/client/testutil/helpers.go +++ b/x/auth/client/testutil/helpers.go @@ -51,4 +51,10 @@ func TxSignBatch(f *cli.Fixtures, signer, fileName string, flags ...string) (boo return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) } +// TxDecode is simcli tx decode +func TxDecode(f *cli.Fixtures, encodedTx string, flags ...string) (bool, string, string) { + cmd := fmt.Sprintf("%s tx decode %v %v", f.SimcliBinary, f.Flags(), encodedTx) + return cli.ExecuteWriteRetStdStreams(f.T, cli.AddFlags(cmd, flags), clientkeys.DefaultKeyPass) +} + // DONTCOVER diff --git a/x/auth/client/tx.go b/x/auth/client/tx.go index a6932aa50a8a..a2bad734a4d2 100644 --- a/x/auth/client/tx.go +++ b/x/auth/client/tx.go @@ -231,7 +231,7 @@ func SignStdTxWithSignerAddress( } // Read and decode a StdTx from the given filename. Can pass "-" to read from stdin. -func ReadStdTxFromFile(cdc *codec.Codec, filename string) (stdTx authtypes.StdTx, err error) { +func ReadTxFromFile(ctx client.Context, filename string) (tx sdk.Tx, err error) { var bytes []byte if filename == "-" { @@ -244,11 +244,7 @@ func ReadStdTxFromFile(cdc *codec.Codec, filename string) (stdTx authtypes.StdTx return } - if err = cdc.UnmarshalJSON(bytes, &stdTx); err != nil { - return - } - - return + return ctx.TxGenerator.TxJSONDecoder()(bytes) } // NewBatchScanner returns a new BatchScanner to read newline-delimited StdTx transactions from r. @@ -289,7 +285,7 @@ func populateAccountFromState( txBldr authtypes.TxBuilder, clientCtx client.Context, addr sdk.AccAddress, ) (authtypes.TxBuilder, error) { - num, seq, err := authtypes.NewAccountRetriever(Codec).GetAccountNumberSequence(clientCtx, addr) + num, seq, err := clientCtx.AccountRetriever.GetAccountNumberSequence(clientCtx, addr) if err != nil { return txBldr, err } @@ -335,8 +331,7 @@ func parseQueryResponse(bz []byte) (sdk.SimulationResponse, error) { // PrepareTxBuilder populates a TxBuilder in preparation for the build of a Tx. func PrepareTxBuilder(txBldr authtypes.TxBuilder, clientCtx client.Context) (authtypes.TxBuilder, error) { from := clientCtx.GetFromAddress() - - accGetter := authtypes.NewAccountRetriever(Codec) + accGetter := clientCtx.AccountRetriever if err := accGetter.EnsureExists(clientCtx, from); err != nil { return txBldr, err } @@ -345,7 +340,7 @@ func PrepareTxBuilder(txBldr authtypes.TxBuilder, clientCtx client.Context) (aut // TODO: (ref #1903) Allow for user supplied account number without // automatically doing a manual lookup. if txbldrAccNum == 0 || txbldrAccSeq == 0 { - num, seq, err := authtypes.NewAccountRetriever(Codec).GetAccountNumberSequence(clientCtx, from) + num, seq, err := accGetter.GetAccountNumberSequence(clientCtx, from) if err != nil { return txBldr, err } diff --git a/x/auth/client/tx_test.go b/x/auth/client/tx_test.go index 3e4bd6adec79..ed09f31580ba 100644 --- a/x/auth/client/tx_test.go +++ b/x/auth/client/tx_test.go @@ -8,6 +8,10 @@ import ( "strings" "testing" + simappparams "github.com/cosmos/cosmos-sdk/simapp/params" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/stretchr/testify/require" "github.com/tendermint/tendermint/crypto/ed25519" @@ -118,22 +122,28 @@ func TestConfiguredTxEncoder(t *testing.T) { func TestReadStdTxFromFile(t *testing.T) { t.Parallel() - cdc := codec.New() - sdk.RegisterCodec(cdc) + + encodingConfig := simappparams.MakeEncodingConfig() + sdk.RegisterCodec(encodingConfig.Amino) + + txGen := encodingConfig.TxGenerator + clientCtx := client.Context{} + clientCtx = clientCtx.WithTxGenerator(txGen) // Build a test transaction fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) stdTx := authtypes.NewStdTx([]sdk.Msg{}, fee, []authtypes.StdSignature{}, "foomemo") // Write it to the file - encodedTx, _ := cdc.MarshalJSON(stdTx) + encodedTx, err := txGen.TxJSONEncoder()(stdTx) + require.NoError(t, err) jsonTxFile := writeToNewTempFile(t, string(encodedTx)) defer os.Remove(jsonTxFile.Name()) // Read it back - decodedTx, err := ReadStdTxFromFile(cdc, jsonTxFile.Name()) + decodedTx, err := ReadTxFromFile(clientCtx, jsonTxFile.Name()) require.NoError(t, err) - require.Equal(t, decodedTx.Memo, "foomemo") + require.Equal(t, decodedTx.(authtypes.StdTx).Memo, "foomemo") } func TestBatchScanner_Scan(t *testing.T) { @@ -195,6 +205,48 @@ func compareEncoders(t *testing.T, expected sdk.TxEncoder, actual sdk.TxEncoder) require.Equal(t, defaultEncoderBytes, encoderBytes) } +func TestPrepareTxBuilder(t *testing.T) { + cdc := makeCodec() + + encodingConfig := simappparams.MakeEncodingConfig() + sdk.RegisterCodec(encodingConfig.Amino) + + fromAddr := sdk.AccAddress("test-addr0000000000") + fromAddrStr := fromAddr.String() + + var accNum uint64 = 10 + var accSeq uint64 = 17 + + txGen := encodingConfig.TxGenerator + clientCtx := client.Context{} + clientCtx = clientCtx. + WithTxGenerator(txGen). + WithJSONMarshaler(encodingConfig.Marshaler). + WithAccountRetriever(client.TestAccountRetriever{Accounts: map[string]struct { + Address sdk.AccAddress + Num uint64 + Seq uint64 + }{ + fromAddrStr: { + Address: fromAddr, + Num: accNum, + Seq: accSeq, + }, + }}). + WithFromAddress(fromAddr) + + bldr := authtypes.NewTxBuilder( + authtypes.DefaultTxEncoder(cdc), 0, 0, + 200000, 1.1, false, "test-chain", + "test-builder", sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))), + sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, sdk.NewDecWithPrec(10000, sdk.Precision))}) + + bldr, err := PrepareTxBuilder(bldr, clientCtx) + require.NoError(t, err) + require.Equal(t, accNum, bldr.AccountNumber()) + require.Equal(t, accSeq, bldr.Sequence()) +} + func writeToNewTempFile(t *testing.T, data string) *os.File { fp, err := ioutil.TempFile(os.TempDir(), "client_tx_test") require.NoError(t, err) diff --git a/x/auth/keeper/keeper_test.go b/x/auth/keeper/keeper_test.go index 505502a021b9..72bc070450ad 100644 --- a/x/auth/keeper/keeper_test.go +++ b/x/auth/keeper/keeper_test.go @@ -5,9 +5,7 @@ import ( "github.com/stretchr/testify/require" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" "github.com/cosmos/cosmos-sdk/simapp" - "github.com/cosmos/cosmos-sdk/std" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/keeper" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -108,9 +106,9 @@ func TestSupply_ValidatePermissions(t *testing.T) { maccPerms[multiPerm] = []string{types.Burner, types.Minter, types.Staking} maccPerms[randomPerm] = []string{"random"} - appCodec := std.NewAppCodec(app.Codec(), codectypes.NewInterfaceRegistry()) + cdc, _ := simapp.MakeCodecs() keeper := keeper.NewAccountKeeper( - appCodec, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), + cdc, app.GetKey(types.StoreKey), app.GetSubspace(types.ModuleName), types.ProtoBaseAccount, maccPerms, ) diff --git a/x/auth/module.go b/x/auth/module.go index fb360e0e78ce..7ef1a83a2493 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -67,7 +67,7 @@ func (AppModuleBasic) RegisterRESTRoutes(clientCtx client.Context, rtr *mux.Rout // GetTxCmd returns the root tx command for the auth module. func (AppModuleBasic) GetTxCmd(clientCtx client.Context) *cobra.Command { - return cli.GetTxCmd(clientCtx.Codec) + return cli.GetTxCmd(clientCtx) } // GetQueryCmd returns the root query command for the auth module. diff --git a/x/auth/types/client_tx.go b/x/auth/types/client_tx.go index d314b4f3b408..dc42613d4db8 100644 --- a/x/auth/types/client_tx.go +++ b/x/auth/types/client_tx.go @@ -87,8 +87,22 @@ func (s StdTxGenerator) NewTxBuilder() client.TxBuilder { } // MarshalTx implements TxGenerator.MarshalTx -func (s StdTxGenerator) MarshalTx(tx sdk.Tx) ([]byte, error) { - return DefaultTxEncoder(s.Cdc)(tx) +func (s StdTxGenerator) TxEncoder() sdk.TxEncoder { + return DefaultTxEncoder(s.Cdc) +} + +func (s StdTxGenerator) TxDecoder() sdk.TxDecoder { + return DefaultTxDecoder(s.Cdc) +} + +func (s StdTxGenerator) TxJSONEncoder() sdk.TxEncoder { + return func(tx sdk.Tx) ([]byte, error) { + return s.Cdc.MarshalJSON(tx) + } +} + +func (s StdTxGenerator) TxJSONDecoder() sdk.TxDecoder { + return DefaultJSONTxDecoder(s.Cdc) } func (s StdTxGenerator) SignModeHandler() authsigning.SignModeHandler { diff --git a/x/auth/types/client_tx_test.go b/x/auth/types/client_tx_test.go new file mode 100644 index 000000000000..8e1888da9126 --- /dev/null +++ b/x/auth/types/client_tx_test.go @@ -0,0 +1,34 @@ +package types_test + +import ( + "github.com/cosmos/cosmos-sdk/client" + simappparams "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/stretchr/testify/require" + "testing" +) + +func TestTxEncoder(t *testing.T) { + clientCtx := client.Context{} + clientCtx = clientCtx.WithTxGenerator(simappparams.MakeEncodingConfig().TxGenerator) + + encodingConfig := simappparams.MakeEncodingConfig() + sdk.RegisterCodec(encodingConfig.Amino) + + txGen := encodingConfig.TxGenerator + clientCtx = clientCtx.WithTxGenerator(txGen) + + // Build a test transaction + fee := authtypes.NewStdFee(50000, sdk.Coins{sdk.NewInt64Coin("atom", 150)}) + stdTx := authtypes.NewStdTx([]sdk.Msg{nil}, fee, []authtypes.StdSignature{}, "foomemo") + + // Encode transaction + txBytes, err := clientCtx.TxGenerator.TxEncoder()(stdTx) + require.NoError(t, err) + require.NotNil(t, txBytes) + + tx, err := clientCtx.TxGenerator.TxDecoder()(txBytes) + require.NoError(t, err) + require.Equal(t, []sdk.Msg{nil}, tx.GetMsgs()) +} diff --git a/x/auth/types/stdtx.go b/x/auth/types/stdtx.go index 8fda1652994b..1667a9499833 100644 --- a/x/auth/types/stdtx.go +++ b/x/auth/types/stdtx.go @@ -342,6 +342,25 @@ func DefaultTxDecoder(cdc *codec.Codec) sdk.TxDecoder { } } +func DefaultJSONTxDecoder(cdc *codec.Codec) sdk.TxDecoder { + return func(txBytes []byte) (sdk.Tx, error) { + var tx = StdTx{} + + if len(txBytes) == 0 { + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, "tx bytes are empty") + } + + // StdTx.Msg is an interface. The concrete types + // are registered by MakeTxCodec + err := cdc.UnmarshalJSON(txBytes, &tx) + if err != nil { + return nil, sdkerrors.Wrap(sdkerrors.ErrTxDecode, err.Error()) + } + + return tx, nil + } +} + // DefaultTxEncoder logic for standard transaction encoding func DefaultTxEncoder(cdc *codec.Codec) sdk.TxEncoder { return func(tx sdk.Tx) ([]byte, error) { diff --git a/x/evidence/keeper/querier_test.go b/x/evidence/keeper/querier_test.go index 7433f099a074..24dcb1d1c019 100644 --- a/x/evidence/keeper/querier_test.go +++ b/x/evidence/keeper/querier_test.go @@ -3,9 +3,7 @@ package keeper_test import ( "strings" - codectypes "github.com/cosmos/cosmos-sdk/codec/types" - - "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/simapp" "github.com/cosmos/cosmos-sdk/x/evidence/exported" "github.com/cosmos/cosmos-sdk/x/evidence/types" @@ -20,7 +18,7 @@ const ( func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { ctx := suite.ctx.WithIsCheckTx(false) numEvidence := 100 - cdc := std.NewAppCodec(suite.app.Codec(), codectypes.NewInterfaceRegistry()) + cdc, _ := simapp.MakeCodecs() evidence := suite.populateEvidence(ctx, numEvidence) query := abci.RequestQuery{ @@ -39,7 +37,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_Existing() { func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := std.NewAppCodec(suite.app.Codec(), codectypes.NewInterfaceRegistry()) + cdc, _ := simapp.MakeCodecs() numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -55,7 +53,7 @@ func (suite *KeeperTestSuite) TestQueryEvidence_NonExisting() { func (suite *KeeperTestSuite) TestQueryAllEvidence() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := std.NewAppCodec(suite.app.Codec(), codectypes.NewInterfaceRegistry()) + cdc, _ := simapp.MakeCodecs() numEvidence := 100 suite.populateEvidence(ctx, numEvidence) @@ -75,7 +73,7 @@ func (suite *KeeperTestSuite) TestQueryAllEvidence() { func (suite *KeeperTestSuite) TestQueryAllEvidence_InvalidPagination() { ctx := suite.ctx.WithIsCheckTx(false) - cdc := std.NewAppCodec(suite.app.Codec(), codectypes.NewInterfaceRegistry()) + cdc, _ := simapp.MakeCodecs() numEvidence := 100 suite.populateEvidence(ctx, numEvidence)