diff --git a/CHANGELOG.md b/CHANGELOG.md index ccb05f3128e3..f429a8c8759b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -177,6 +177,8 @@ be used to retrieve the actual proposal `Content`. Also the `NewMsgSubmitProposa ### Bug Fixes +* (x/bank) [\#6536](https://github.com/cosmos/cosmos-sdk/pull/6536) Fix bug in `WriteGeneratedTxResponse` function used by multiple +REST endpoints. Now it writes a Tx in StdTx format. * (x/staking) [\#6529](https://github.com/cosmos/cosmos-sdk/pull/6529) Export validator addresses (previously was empty). * (export) [\#6510](https://github.com/cosmos/cosmos-sdk/pull/6510/) Field TimeIotaMs now is included in genesis file while exporting. * (client) [\#6402](https://github.com/cosmos/cosmos-sdk/issues/6402) Fix `keys add` `--algo` flag which only worked for Tendermint's `secp256k1` default key signing algorithm. diff --git a/client/tx/tx.go b/client/tx/tx.go index 69b6bc380964..2093ccea9e54 100644 --- a/client/tx/tx.go +++ b/client/tx/tx.go @@ -188,7 +188,7 @@ func WriteGeneratedTxResponse( return } - output, err := ctx.JSONMarshaler.MarshalJSON(tx) + output, err := ctx.JSONMarshaler.MarshalJSON(tx.GetTx()) if rest.CheckInternalServerError(w, err) { return } diff --git a/types/rest/rest.go b/types/rest/rest.go index 24b6ad9dd50c..e9e58dfa6f37 100644 --- a/types/rest/rest.go +++ b/types/rest/rest.go @@ -3,6 +3,7 @@ package rest import ( + "bytes" "encoding/json" "errors" "fmt" @@ -442,3 +443,23 @@ func GetRequest(url string) ([]byte, error) { return body, nil } + +// PostRequest defines a wrapper around an HTTP POST request with a provided URL and data. +// An error is returned if the request or reading the body fails. +func PostRequest(url string, contentType string, data []byte) ([]byte, error) { + res, err := http.Post(url, contentType, bytes.NewBuffer(data)) // nolint:gosec + if err != nil { + return nil, fmt.Errorf("error while sending post request: %w", err) + } + + bz, err := ioutil.ReadAll(res.Body) + if err != nil { + return nil, fmt.Errorf("error reading response body: %w", err) + } + + if err = res.Body.Close(); err != nil { + return nil, err + } + + return bz, nil +} diff --git a/x/bank/client/rest/tx_test.go b/x/bank/client/rest/tx_test.go new file mode 100644 index 000000000000..17b394bec06e --- /dev/null +++ b/x/bank/client/rest/tx_test.go @@ -0,0 +1,106 @@ +package rest_test + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/testutil" + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/errors" + "github.com/cosmos/cosmos-sdk/types/rest" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + bankrest "github.com/cosmos/cosmos-sdk/x/bank/client/rest" + banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" +) + +func (s *IntegrationTestSuite) TestCoinSend() { + encodingConfig := simapp.MakeEncodingConfig() + authclient.Codec = encodingConfig.Marshaler + + val := s.network.Validators[0] + + account, err := getAccountInfo(val) + s.Require().NoError(err) + + sendReq := generateSendReq( + account, + types.Coins{types.NewCoin(s.cfg.BondDenom, types.TokensFromConsensusPower(1))}, + ) + + stdTx, err := submitSendReq(val, sendReq) + s.Require().NoError(err) + + s.Require().Nil(stdTx.Signatures) + s.Require().Equal([]types.Msg{ + &banktypes.MsgSend{ + FromAddress: account.GetAddress(), + ToAddress: account.GetAddress(), + Amount: sendReq.Amount, + }, + }, stdTx.GetMsgs()) +} + +func submitSendReq(val *testutil.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) + if err != nil { + return authtypes.StdTx{}, errors.Wrap(err, "error encoding SendReq to json") + } + + res, err := rest.PostRequest(url, "application/json", bz) + if err != nil { + return authtypes.StdTx{}, err + } + + var tx authtypes.StdTx + err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(res, &tx) + if err != nil { + return authtypes.StdTx{}, errors.Wrap(err, "error unmarshaling to StdTx SendReq response") + } + + return tx, nil +} + +func generateSendReq(from authtypes.AccountI, amount types.Coins) bankrest.SendReq { + baseReq := rest.NewBaseReq( + from.GetAddress().String(), + "someMemo", + "some-id", + "10000", + fmt.Sprintf("%f", 1.0), + from.GetAccountNumber(), + from.GetSequence(), + types.NewCoins(), + nil, + false, + ) + + return bankrest.SendReq{ + BaseReq: baseReq, + Amount: amount, + } +} + +func getAccountInfo(val *testutil.Validator) (authtypes.AccountI, error) { + url := fmt.Sprintf("%s/auth/accounts/%s", val.APIAddress, val.Address) + + resp, err := rest.GetRequest(url) + if err != nil { + return nil, err + } + + bz, err := rest.ParseResponseWithHeight(val.ClientCtx.JSONMarshaler, resp) + if err != nil { + return nil, err + } + + var acc authtypes.AccountI + err = val.ClientCtx.JSONMarshaler.UnmarshalJSON(bz, &acc) + if err != nil { + return nil, err + } + + return acc, nil +}