diff --git a/client/tx/legacy.go b/client/tx/legacy.go new file mode 100644 index 0000000000..36382b5571 --- /dev/null +++ b/client/tx/legacy.go @@ -0,0 +1,79 @@ +package tx + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/x/auth/types" +) + +// ConvertTxToStdTx converts a transaction to the legacy StdTx format +func ConvertTxToStdTx(codec *codec.Codec, tx signing.SigFeeMemoTx) (types.StdTx, error) { + if stdTx, ok := tx.(types.StdTx); ok { + return stdTx, nil + } + + aminoTxConfig := types.StdTxConfig{Cdc: codec} + builder := aminoTxConfig.NewTxBuilder() + + err := CopyTx(tx, builder) + if err != nil { + + return types.StdTx{}, err + } + + stdTx, ok := builder.GetTx().(types.StdTx) + if !ok { + return types.StdTx{}, fmt.Errorf("expected %T, got %+v", types.StdTx{}, builder.GetTx()) + } + + return stdTx, nil +} + +// CopyTx copies a SigFeeMemoTx to a new TxBuilder, allowing conversion between +// different transaction formats. +func CopyTx(tx signing.SigFeeMemoTx, builder client.TxBuilder) error { + err := builder.SetMsgs(tx.GetMsgs()...) + if err != nil { + return err + } + + sigs, err := tx.GetSignaturesV2() + if err != nil { + return err + } + + err = builder.SetSignatures(sigs...) + if err != nil { + return err + } + + builder.SetMemo(tx.GetMemo()) + builder.SetFeeAmount(tx.GetFee()) + builder.SetGasLimit(tx.GetGas()) + + return nil +} + +func ConvertAndEncodeStdTx(txConfig client.TxConfig, stdTx types.StdTx) ([]byte, error) { + builder := txConfig.NewTxBuilder() + + var theTx sdk.Tx + + // check if we need a StdTx anyway, in that case don't copy + if _, ok := builder.GetTx().(types.StdTx); ok { + theTx = stdTx + } else { + err := CopyTx(stdTx, builder) + if err != nil { + return nil, err + } + + theTx = builder.GetTx() + } + + return txConfig.TxEncoder()(theTx) +} diff --git a/client/tx/legacy_test.go b/client/tx/legacy_test.go new file mode 100644 index 0000000000..69aa088c0e --- /dev/null +++ b/client/tx/legacy_test.go @@ -0,0 +1,145 @@ +package tx_test + +import ( + "testing" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/simapp/params" + + "github.com/cosmos/cosmos-sdk/x/auth/signing" + + "github.com/stretchr/testify/require" + + tx2 "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/std" + "github.com/cosmos/cosmos-sdk/x/auth/tx" + types3 "github.com/cosmos/cosmos-sdk/x/auth/types" + + signing2 "github.com/cosmos/cosmos-sdk/types/tx/signing" + + "github.com/cosmos/cosmos-sdk/client" + "github.com/cosmos/cosmos-sdk/testutil/testdata" + "github.com/cosmos/cosmos-sdk/types" + types2 "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +const ( + memo = "waboom" + gas = uint64(10000) +) + +var ( + fee = types.NewCoins(types.NewInt64Coin("bam", 100)) + _, pub1, addr1 = testdata.KeyTestPubAddr() + _, _, addr2 = testdata.KeyTestPubAddr() + msg = types2.NewMsgSend(addr1, addr2, types.NewCoins(types.NewInt64Coin("wack", 10000))) + sig = signing2.SignatureV2{ + PubKey: pub1, + Data: &signing2.SingleSignatureData{ + SignMode: signing2.SignMode_SIGN_MODE_LEGACY_AMINO_JSON, + Signature: []byte("dummy"), + }, + } +) + +func buildTestTx(t *testing.T, builder client.TxBuilder) { + builder.SetMemo(memo) + builder.SetGasLimit(gas) + builder.SetFeeAmount(fee) + err := builder.SetMsgs(msg) + require.NoError(t, err) + err = builder.SetSignatures(sig) + require.NoError(t, err) +} + +type TestSuite struct { + suite.Suite + encCfg params.EncodingConfig + protoCfg client.TxConfig + aminoCfg client.TxConfig +} + +func (s *TestSuite) SetupSuite() { + encCfg := simapp.MakeEncodingConfig() + s.encCfg = encCfg + s.protoCfg = tx.NewTxConfig(codec.NewProtoCodec(encCfg.InterfaceRegistry), std.DefaultPublicKeyCodec{}, tx.DefaultSignModeHandler()) + s.aminoCfg = types3.StdTxConfig{Cdc: encCfg.Amino} +} + +func (s *TestSuite) TestCopyTx() { + // proto -> amino -> proto + protoBuilder := s.protoCfg.NewTxBuilder() + buildTestTx(s.T(), protoBuilder) + aminoBuilder := s.aminoCfg.NewTxBuilder() + err := tx2.CopyTx(protoBuilder.GetTx(), aminoBuilder) + s.Require().NoError(err) + protoBuilder2 := s.protoCfg.NewTxBuilder() + err = tx2.CopyTx(aminoBuilder.GetTx(), protoBuilder2) + s.Require().NoError(err) + bz, err := s.protoCfg.TxEncoder()(protoBuilder.GetTx()) + s.Require().NoError(err) + bz2, err := s.protoCfg.TxEncoder()(protoBuilder2.GetTx()) + s.Require().NoError(err) + s.Require().Equal(bz, bz2) + + // amino -> proto -> amino + aminoBuilder = s.aminoCfg.NewTxBuilder() + buildTestTx(s.T(), aminoBuilder) + protoBuilder = s.protoCfg.NewTxBuilder() + err = tx2.CopyTx(aminoBuilder.GetTx(), protoBuilder) + s.Require().NoError(err) + aminoBuilder2 := s.aminoCfg.NewTxBuilder() + err = tx2.CopyTx(protoBuilder.GetTx(), aminoBuilder2) + s.Require().NoError(err) + bz, err = s.aminoCfg.TxEncoder()(aminoBuilder.GetTx()) + s.Require().NoError(err) + bz2, err = s.aminoCfg.TxEncoder()(aminoBuilder2.GetTx()) + s.Require().NoError(err) + s.Require().Equal(bz, bz2) +} + +func (s *TestSuite) TestConvertTxToStdTx() { + // proto tx + protoBuilder := s.protoCfg.NewTxBuilder() + buildTestTx(s.T(), protoBuilder) + stdTx, err := tx2.ConvertTxToStdTx(s.encCfg.Amino, protoBuilder.GetTx()) + s.Require().NoError(err) + s.Require().Equal(memo, stdTx.Memo) + s.Require().Equal(gas, stdTx.Fee.Gas) + s.Require().Equal(fee, stdTx.Fee.Amount) + s.Require().Equal(msg, stdTx.Msgs[0]) + s.Require().Equal(sig.PubKey, stdTx.Signatures[0].PubKey) + s.Require().Equal(sig.Data.(*signing2.SingleSignatureData).Signature, stdTx.Signatures[0].Signature) + + // std tx + aminoBuilder := s.aminoCfg.NewTxBuilder() + buildTestTx(s.T(), aminoBuilder) + stdTx = aminoBuilder.GetTx().(types3.StdTx) + stdTx2, err := tx2.ConvertTxToStdTx(s.encCfg.Amino, stdTx) + s.Require().NoError(err) + s.Require().Equal(stdTx, stdTx2) +} + +func (s *TestSuite) TestConvertAndEncodeStdTx() { + // convert amino -> proto -> amino + aminoBuilder := s.aminoCfg.NewTxBuilder() + buildTestTx(s.T(), aminoBuilder) + stdTx := aminoBuilder.GetTx().(types3.StdTx) + txBz, err := tx2.ConvertAndEncodeStdTx(s.protoCfg, stdTx) + s.Require().NoError(err) + decodedTx, err := s.protoCfg.TxDecoder()(txBz) + s.Require().NoError(err) + aminoBuilder2 := s.aminoCfg.NewTxBuilder() + s.Require().NoError(tx2.CopyTx(decodedTx.(signing.SigFeeMemoTx), aminoBuilder2)) + s.Require().Equal(stdTx, aminoBuilder2.GetTx()) + + // just use amino everywhere + txBz, err = tx2.ConvertAndEncodeStdTx(s.aminoCfg, stdTx) + s.Require().NoError(err) + decodedTx, err = s.aminoCfg.TxDecoder()(txBz) + s.Require().NoError(err) + s.Require().Equal(stdTx, decodedTx) +} diff --git a/client/tx/tx.go b/client/tx/tx.go index 6047c45c08..9dbca398bd 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -138,6 +138,8 @@ func BroadcastTx(clientCtx client.Context, txf Factory, msgs ...sdk.Msg) error { // WriteGeneratedTxResponse writes a generated unsigned transaction to the // provided http.ResponseWriter. It will simulate gas costs if requested by the // BaseReq. Upon any error, the error will be written to the http.ResponseWriter. +// Note that this function returns the legacy StdTx Amino JSON format for compatibility +// with legacy clients. func WriteGeneratedTxResponse( ctx client.Context, w http.ResponseWriter, br rest.BaseReq, msgs ...sdk.Msg, ) { @@ -175,7 +177,7 @@ func WriteGeneratedTxResponse( txf = txf.WithGas(adjusted) if br.Simulate { - rest.WriteSimulationResponse(w, ctx.JSONMarshaler, txf.Gas()) + rest.WriteSimulationResponse(w, ctx.Codec, txf.Gas()) return } } @@ -185,7 +187,12 @@ func WriteGeneratedTxResponse( return } - output, err := ctx.JSONMarshaler.MarshalJSON(tx.GetTx()) + stdTx, err := ConvertTxToStdTx(ctx.Codec, tx.GetTx()) + if rest.CheckInternalServerError(w, err) { + return + } + + output, err := ctx.Codec.MarshalJSON(stdTx) if rest.CheckInternalServerError(w, err) { return } diff --git a/testutil/network/network.go b/testutil/network/network.go index e49fcc34b1..2f87aa0435 100644 --- a/testutil/network/network.go +++ b/testutil/network/network.go @@ -62,6 +62,7 @@ func NewSimApp(val Validator) servertypes.Application { // in-process local testing network. type Config struct { Codec codec.Marshaler + LegacyAmino *codec.Codec TxConfig client.TxConfig AccountRetriever client.AccountRetriever AppConstructor AppConstructor // the ABCI application constructor @@ -88,6 +89,7 @@ func DefaultConfig() Config { return Config{ Codec: encCfg.Marshaler, TxConfig: encCfg.TxConfig, + LegacyAmino: encCfg.Amino, AccountRetriever: authtypes.NewAccountRetriever(encCfg.Marshaler), AppConstructor: NewSimApp, GenesisState: simapp.ModuleBasics.DefaultGenesis(encCfg.Marshaler), @@ -312,6 +314,7 @@ func New(t *testing.T, cfg Config) *Network { WithHomeDir(tmCfg.RootDir). WithChainID(cfg.ChainID). WithJSONMarshaler(cfg.Codec). + WithCodec(cfg.LegacyAmino). WithTxConfig(cfg.TxConfig). WithAccountRetriever(cfg.AccountRetriever) diff --git a/x/auth/client/rest.go b/x/auth/client/rest.go index 1d52f0384b..a3e15d4bde 100644 --- a/x/auth/client/rest.go +++ b/x/auth/client/rest.go @@ -51,7 +51,8 @@ func WriteGenerateStdTxResponse(w http.ResponseWriter, clientCtx client.Context, return } - output, err := clientCtx.JSONMarshaler.MarshalJSON(types.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)) + // NOTE: amino is used intentionally here, don't migrate it + output, err := clientCtx.Codec.MarshalJSON(types.NewStdTx(stdMsg.Msgs, stdMsg.Fee, nil, stdMsg.Memo)) if rest.CheckInternalServerError(w, err) { return } diff --git a/x/auth/client/rest/broadcast.go b/x/auth/client/rest/broadcast.go index 4508f2e693..d689e7c69c 100644 --- a/x/auth/client/rest/broadcast.go +++ b/x/auth/client/rest/broadcast.go @@ -4,6 +4,8 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -27,11 +29,12 @@ func BroadcastTxRequest(clientCtx client.Context) http.HandlerFunc { return } - if err := clientCtx.JSONMarshaler.UnmarshalJSON(body, &req); rest.CheckBadRequestError(w, err) { + // NOTE: amino is used intentionally here, don't migrate it! + if err := clientCtx.Codec.UnmarshalJSON(body, &req); rest.CheckBadRequestError(w, err) { return } - txBytes, err := clientCtx.Codec.MarshalBinaryBare(req.Tx) + txBytes, err := tx.ConvertAndEncodeStdTx(clientCtx.TxConfig, req.Tx) if rest.CheckInternalServerError(w, err) { return } @@ -43,6 +46,8 @@ func BroadcastTxRequest(clientCtx client.Context) http.HandlerFunc { return } + // NOTE: amino is set intentionally here, don't migrate it! + clientCtx = clientCtx.WithJSONMarshaler(clientCtx.Codec) rest.PostProcessResponseBare(w, clientCtx, res) } } diff --git a/x/auth/client/rest/decode.go b/x/auth/client/rest/decode.go index dd6f23833e..da5a536691 100644 --- a/x/auth/client/rest/decode.go +++ b/x/auth/client/rest/decode.go @@ -2,10 +2,14 @@ package rest import ( "encoding/base64" + "fmt" "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/x/auth/signing" + "github.com/cosmos/cosmos-sdk/client" + clienttx "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/types/rest" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" ) @@ -32,7 +36,8 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - err = clientCtx.JSONMarshaler.UnmarshalJSON(body, &req) + // NOTE: amino is used intentionally here, don't migrate it + err = clientCtx.Codec.UnmarshalJSON(body, &req) if rest.CheckBadRequestError(w, err) { return } @@ -42,13 +47,26 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - var stdTx authtypes.StdTx - err = clientCtx.Codec.UnmarshalBinaryBare(txBytes, &stdTx) + tx, err := clientCtx.TxConfig.TxDecoder()(txBytes) + if rest.CheckBadRequestError(w, err) { + return + } + + sigFeeMemoTx, ok := tx.(signing.SigFeeMemoTx) + if !ok { + rest.WriteErrorResponse(w, http.StatusBadRequest, fmt.Sprintf("%+v is not backwards compatible with %T", tx, authtypes.StdTx{})) + return + } + + stdTx, err := clienttx.ConvertTxToStdTx(clientCtx.Codec, sigFeeMemoTx) if rest.CheckBadRequestError(w, err) { return } response := DecodeResp(stdTx) + + // NOTE: amino is set intentionally here, don't migrate it + clientCtx = clientCtx.WithJSONMarshaler(clientCtx.Codec) rest.PostProcessResponse(w, clientCtx, response) } } diff --git a/x/auth/client/rest/encode.go b/x/auth/client/rest/encode.go index 4f7c495506..7512237943 100644 --- a/x/auth/client/rest/encode.go +++ b/x/auth/client/rest/encode.go @@ -5,6 +5,8 @@ import ( "io/ioutil" "net/http" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/types/rest" "github.com/cosmos/cosmos-sdk/x/auth/types" @@ -27,13 +29,14 @@ func EncodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { return } - err = clientCtx.JSONMarshaler.UnmarshalJSON(body, &req) + // NOTE: amino is used intentionally here, don't migrate it + err = clientCtx.Codec.UnmarshalJSON(body, &req) if rest.CheckBadRequestError(w, err) { return } - // re-encode it via the Amino wire protocol - txBytes, err := clientCtx.Codec.MarshalBinaryBare(req) + // re-encode it in the chain's native binary format + txBytes, err := tx.ConvertAndEncodeStdTx(clientCtx.TxConfig, req) if rest.CheckInternalServerError(w, err) { return } @@ -42,6 +45,8 @@ func EncodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { txBytesBase64 := base64.StdEncoding.EncodeToString(txBytes) response := EncodeResp{Tx: txBytesBase64} + + // NOTE: amino is set intentionally here, don't migrate it rest.PostProcessResponseBare(w, clientCtx, response) } } diff --git a/x/auth/client/rest/rest_test.go b/x/auth/client/rest/rest_test.go new file mode 100644 index 0000000000..fa1ceca6fb --- /dev/null +++ b/x/auth/client/rest/rest_test.go @@ -0,0 +1,124 @@ +package rest_test + +import ( + "fmt" + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + rest2 "github.com/cosmos/cosmos-sdk/x/auth/client/rest" + "github.com/cosmos/cosmos-sdk/x/bank/types" + + "github.com/stretchr/testify/suite" + + "github.com/cosmos/cosmos-sdk/types/rest" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + + "github.com/cosmos/cosmos-sdk/testutil/network" +) + +type IntegrationTestSuite struct { + suite.Suite + + cfg network.Config + network *network.Network +} + +func (s *IntegrationTestSuite) SetupSuite() { + s.T().Log("setting up integration test suite") + + cfg := network.DefaultConfig() + cfg.NumValidators = 1 + + s.cfg = cfg + s.network = network.New(s.T(), cfg) + + _, err := s.network.WaitForHeight(1) + s.Require().NoError(err) +} + +func (s *IntegrationTestSuite) TearDownSuite() { + s.T().Log("tearing down integration test suite") + s.network.Cleanup() +} + +func (s *IntegrationTestSuite) TestEncodeDecode() { + val := s.network.Validators[0] + + // NOTE: this uses StdTx explicitly, don't migrate it! + stdTx := authtypes.StdTx{ + Msgs: []sdk.Msg{&types.MsgSend{}}, + Fee: authtypes.StdFee{ + Amount: sdk.Coins{sdk.NewInt64Coin("foo", 10)}, + Gas: 10000, + }, + Memo: "FOOBAR", + } + + // NOTE: this uses amino explicitly, don't migrate it! + cdc := val.ClientCtx.Codec + + bz, err := cdc.MarshalJSON(stdTx) + s.Require().NoError(err) + + res, err := rest.PostRequest(fmt.Sprintf("%s/txs/encode", val.APIAddress), "application/json", bz) + s.Require().NoError(err) + + var encodeResp rest2.EncodeResp + err = cdc.UnmarshalJSON(res, &encodeResp) + s.Require().NoError(err) + + bz, err = cdc.MarshalJSON(rest2.DecodeReq{Tx: encodeResp.Tx}) + s.Require().NoError(err) + + res, err = rest.PostRequest(fmt.Sprintf("%s/txs/decode", val.APIAddress), "application/json", bz) + s.Require().NoError(err) + + var respWithHeight rest.ResponseWithHeight + err = cdc.UnmarshalJSON(res, &respWithHeight) + s.Require().NoError(err) + var decodeResp rest2.DecodeResp + err = cdc.UnmarshalJSON(respWithHeight.Result, &decodeResp) + s.Require().NoError(err) + s.Require().Equal(stdTx, authtypes.StdTx(decodeResp)) +} + +func (s *IntegrationTestSuite) TestBroadcastTxRequest() { + // NOTE: this uses StdTx explicitly, don't migrate it! + stdTx := authtypes.StdTx{ + Msgs: []sdk.Msg{&types.MsgSend{}}, + Fee: authtypes.StdFee{ + Amount: sdk.Coins{sdk.NewInt64Coin("foo", 10)}, + Gas: 10000, + }, + Memo: "FOOBAR", + } + + // we just test with async mode because this tx will fail - all we care about is that it got encoded and broadcast correctly + res, err := s.broadcastReq(stdTx, "async") + s.Require().NoError(err) + var txRes sdk.TxResponse + // NOTE: this uses amino explicitly, don't migrate it! + s.Require().NoError(s.cfg.LegacyAmino.UnmarshalJSON(res, &txRes)) + // we just check for a non-empty TxHash here, the actual hash will depend on the underlying tx configuration + s.Require().NotEmpty(txRes.TxHash) +} + +func (s *IntegrationTestSuite) broadcastReq(stdTx authtypes.StdTx, mode string) ([]byte, error) { + val := s.network.Validators[0] + + // NOTE: this uses amino explicitly, don't migrate it! + cdc := val.ClientCtx.Codec + + req := rest2.BroadcastReq{ + Tx: stdTx, + Mode: mode, + } + bz, err := cdc.MarshalJSON(req) + s.Require().NoError(err) + + return rest.PostRequest(fmt.Sprintf("%s/txs", val.APIAddress), "application/json", bz) +} + +func TestIntegrationTestSuite(t *testing.T) { + suite.Run(t, new(IntegrationTestSuite)) +} diff --git a/x/bank/client/rest/rest.go b/x/bank/client/rest/rest.go index 9ef91b82ad..e70a946d26 100644 --- a/x/bank/client/rest/rest.go +++ b/x/bank/client/rest/rest.go @@ -14,17 +14,3 @@ func RegisterHandlers(clientCtx client.Context, r *mux.Router) { r.HandleFunc("/bank/total", totalSupplyHandlerFn(clientCtx)).Methods("GET") r.HandleFunc("/bank/total/{denom}", supplyOfHandlerFn(clientCtx)).Methods("GET") } - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// RegisterRoutes - Central function to define routes that get registered by the main application -func RegisterRoutes(clientCtx client.Context, r *mux.Router) { - r.HandleFunc("/bank/accounts/{address}/transfers", SendRequestHandlerFn(clientCtx)).Methods("POST") - r.HandleFunc("/bank/balances/{address}", QueryBalancesRequestHandlerFn(clientCtx)).Methods("GET") - r.HandleFunc("/bank/total", totalSupplyHandlerFn(clientCtx)).Methods("GET") - r.HandleFunc("/bank/total/{denom}", supplyOfHandlerFn(clientCtx)).Methods("GET") -} diff --git a/x/bank/client/rest/tx.go b/x/bank/client/rest/tx.go index 50565db3ae..a59450c3f0 100644 --- a/x/bank/client/rest/tx.go +++ b/x/bank/client/rest/tx.go @@ -9,7 +9,6 @@ import ( "github.com/cosmos/cosmos-sdk/client/tx" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/bank/types" ) @@ -50,43 +49,3 @@ func NewSendRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { tx.WriteGeneratedTxResponse(clientCtx, w, req.BaseReq, msg) } } - -// --------------------------------------------------------------------------- -// Deprecated -// -// TODO: Remove once client-side Protobuf migration has been completed. -// --------------------------------------------------------------------------- - -// SendRequestHandlerFn - http request handler to send coins to a address. -// -// TODO: Remove once client-side Protobuf migration has been completed. -// ref: https://github.com/cosmos/cosmos-sdk/issues/5864 -func SendRequestHandlerFn(clientCtx client.Context) http.HandlerFunc { - return func(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - bech32Addr := vars["address"] - - toAddr, err := sdk.AccAddressFromBech32(bech32Addr) - if rest.CheckBadRequestError(w, err) { - return - } - - var req SendReq - if !rest.ReadRESTReq(w, r, clientCtx.Codec, &req) { - return - } - - req.BaseReq = req.BaseReq.Sanitize() - if !req.BaseReq.ValidateBasic(w) { - return - } - - fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) - if rest.CheckBadRequestError(w, err) { - return - } - - msg := types.NewMsgSend(fromAddr, toAddr, req.Amount) - authclient.WriteGenerateStdTxResponse(w, clientCtx, req.BaseReq, []sdk.Msg{msg}) - } -} diff --git a/x/bank/client/rest/tx_test.go b/x/bank/client/rest/tx_test.go index d15599d634..2bc2cd4b4d 100644 --- a/x/bank/client/rest/tx_test.go +++ b/x/bank/client/rest/tx_test.go @@ -44,7 +44,8 @@ func (s *IntegrationTestSuite) TestCoinSend() { func submitSendReq(val *network.Validator, req bankrest.SendReq) (authtypes.StdTx, error) { url := fmt.Sprintf("%s/bank/accounts/%s/transfers", val.APIAddress, val.Address) - bz, err := val.ClientCtx.JSONMarshaler.MarshalJSON(req) + // NOTE: this uses amino explicitly, don't migrate it! + bz, err := val.ClientCtx.Codec.MarshalJSON(req) if err != nil { return authtypes.StdTx{}, errors.Wrap(err, "error encoding SendReq to json") } @@ -55,7 +56,8 @@ func submitSendReq(val *network.Validator, req bankrest.SendReq) (authtypes.StdT } var tx authtypes.StdTx - err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &tx) + // NOTE: this uses amino explicitly, don't migrate it! + err = val.ClientCtx.Codec.UnmarshalJSON(res, &tx) if err != nil { return authtypes.StdTx{}, errors.Wrap(err, "error unmarshaling to StdTx SendReq response") }