Skip to content

Commit

Permalink
Fix legacy querying tx ("unregistered type" bug) (cosmos#7992)
Browse files Browse the repository at this point in the history
* Add tests for query txs

* Add test for IBC

* Refactor checkSignModeError

* Fix lint

* Add successful IBC test

* Remove logs

* break

* Remove known errors

* Update error message

* Better comments

* Revert variable renaming

* Fix lint

* Add mention of gRPC as TODO
  • Loading branch information
amaury1093 authored Nov 25, 2020
1 parent 9c47612 commit a9dd334
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 87 deletions.
5 changes: 5 additions & 0 deletions docs/migrations/rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Some important information concerning all legacy REST endpoints:

| Legacy REST Endpoint | Description | Breaking Change |
| ------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST /txs` | Query tx by hash | Endpoint will error when trying to broadcast transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs/{hash}` | Query tx by hash | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /txs` | Query tx by events | Endpoint will error when trying to output transactions that don't support Amino serialization (e.g. IBC txs)<sup>1</sup>. |
| `GET /staking/validators` | Get all validators | BondStatus is now a protobuf enum instead of an int32, and JSON serialized using its protobuf name, so expect query parameters like `?status=BOND_STATUS_{BONDED,UNBONDED,UNBONDING}` as opposed to `?status={bonded,unbonded,unbonding}`. |
Expand Down Expand Up @@ -87,3 +88,7 @@ Some modules expose legacy `POST` endpoints to generate unsigned transactions fo
| `POST /upgrade/*` | Create unsigned `Msg`s for upgrade | N/A, use Protobuf directly |
| `GET /upgrade/current` | Get the current plan | `GET /cosmos/upgrade/v1beta1/current_plan` |
| `GET /upgrade/applied_plan/{name}` | Get a previously applied plan | `GET /cosmos/upgrade/v1beta1/applied/{name}` |

## Migrating to gRPC

Instead of hitting REST endpoints as described in the previous paragraph, the SDK also exposes a gRPC server. Any client can use gRPC instead of REST to interact with the node. An overview of different ways to communicate with a node can be found [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657), and a concrete tutorial for setting up a gRPC client [here (TODO)](https://github.com/cosmos/cosmos-sdk/issues/7657).
5 changes: 3 additions & 2 deletions x/auth/client/rest/decode.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,10 @@ func DecodeTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {

response := DecodeResp(stdTx)

err = checkSignModeError(w, clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
err = checkSignModeError(clientCtx, response, "/cosmos/tx/v1beta1/txs/decode")
if err != nil {
// Error is already returned by checkSignModeError.
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

return
}

Expand Down
32 changes: 18 additions & 14 deletions x/auth/client/rest/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import (
genutilrest "github.com/cosmos/cosmos-sdk/x/genutil/client/rest"
)

const unRegisteredConcreteTypeErr = "unregistered concrete type"

// QueryAccountRequestHandlerFn is the query accountREST Handler.
func QueryAccountRequestHandlerFn(storeName string, clientCtx client.Context) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -110,9 +108,10 @@ func QueryTxsRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
packStdTxResponse(w, clientCtx, txRes)
}

err = checkSignModeError(w, clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
err = checkSignModeError(clientCtx, searchResult, "/cosmos/tx/v1beta1/txs")
if err != nil {
// Error is already returned by checkSignModeError.
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

return
}

Expand Down Expand Up @@ -152,9 +151,10 @@ func QueryTxRequestHandlerFn(clientCtx client.Context) http.HandlerFunc {
rest.WriteErrorResponse(w, http.StatusNotFound, fmt.Sprintf("no transaction found with hash %s", hashHexStr))
}

err = checkSignModeError(w, clientCtx, output, "/cosmos/tx/v1beta1/tx/{txhash}")
err = checkSignModeError(clientCtx, output, "/cosmos/tx/v1beta1/tx/{txhash}")
if err != nil {
// Error is already returned by checkSignModeError.
rest.WriteErrorResponse(w, http.StatusInternalServerError, err.Error())

return
}

Expand Down Expand Up @@ -198,18 +198,22 @@ func packStdTxResponse(w http.ResponseWriter, clientCtx client.Context, txRes *s
return nil
}

func checkSignModeError(w http.ResponseWriter, ctx client.Context, resp interface{}, grpcEndPoint string) error {
// checkSignModeError checks if there are errors with marshalling non-amino
// txs with amino.
func checkSignModeError(ctx client.Context, resp interface{}, grpcEndPoint string) error {
// LegacyAmino used intentionally here to handle the SignMode errors
marshaler := ctx.LegacyAmino

_, err := marshaler.MarshalJSON(resp)
if err != nil && strings.Contains(err.Error(), unRegisteredConcreteTypeErr) {
rest.WriteErrorResponse(w, http.StatusInternalServerError,
"This transaction was created with the new SIGN_MODE_DIRECT signing method, and therefore cannot be displayed"+
" via legacy REST handlers, please use CLI or directly query the Tendermint RPC endpoint to query"+
" this transaction. gRPC gateway endpoint is "+grpcEndPoint+". Please also see the REST endpoints migration"+
" guide at "+clientrest.DeprecationURL+".")
return err
if err != nil {

// If there's an unmarshalling error, we assume that it's because we're
// using amino to unmarshal a non-amino tx.
return fmt.Errorf("this transaction cannot be displayed via legacy REST endpoints, because it does not support"+
" Amino serialization. Please either use CLI, gRPC, gRPC-gateway, or directly query the Tendermint RPC"+
" endpoint to query this transaction. The new REST endpoint (via gRPC-gateway) is %s. Please also see the"+
"REST endpoints migration guide at %s for more info", grpcEndPoint, clientrest.DeprecationURL)

}

return nil
Expand Down
Loading

0 comments on commit a9dd334

Please sign in to comment.