From e4549046b57cce680fb2fc495112b663efedaad1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Fri, 1 Jul 2022 21:59:16 +0200 Subject: [PATCH 1/2] fix: ensure JSON serialization compatibility Because Tendermint encodes ints as strings, and expects strings while decoding, Optimint has to encode int values as strings as well. Resolves #463. --- rpc/json/handler.go | 9 ++++++++- rpc/json/service_test.go | 4 ++-- rpc/json/types.go | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/rpc/json/handler.go b/rpc/json/handler.go index 82cc801b9c..fcb6b8a6d5 100644 --- a/rpc/json/handler.go +++ b/rpc/json/handler.go @@ -10,6 +10,8 @@ import ( "reflect" "strconv" + tmjson "github.com/tendermint/tendermint/libs/json" + "github.com/celestiaorg/optimint/log" "github.com/gorilla/rpc/v2" "github.com/gorilla/rpc/v2/json2" @@ -176,7 +178,12 @@ func (h *handler) encodeAndWriteResponse(w http.ResponseWriter, result interface if errResult != nil { resp.Error = &json2.Error{Code: json2.ErrorCode(statusCode), Data: errResult.Error()} } else { - resp.Result = result + bytes, err := tmjson.Marshal(result) + if err != nil { + resp.Error = &json2.Error{Code: json2.ErrorCode(json2.E_INTERNAL), Data: err.Error()} + } else { + resp.Result = bytes + } } encoder := json.NewEncoder(w) diff --git a/rpc/json/service_test.go b/rpc/json/service_test.go index d901591f78..6bab66fdc8 100644 --- a/rpc/json/service_test.go +++ b/rpc/json/service_test.go @@ -68,13 +68,13 @@ func TestREST(t *testing.T) { {"invalid/malformed request", "/block?so{}wrong!", http.StatusOK, int(json2.E_INVALID_REQ), ``}, {"invalid/missing param", "/block", http.StatusOK, int(json2.E_INVALID_REQ), `missing param 'height'`}, - {"valid/no params", "/abci_info", http.StatusOK, -1, `"last_block_height":345`}, + {"valid/no params", "/abci_info", http.StatusOK, -1, `"last_block_height":"345"`}, // to keep test simple, allow returning application error in following case {"valid/int param", "/block?height=321", http.StatusOK, int(json2.E_INTERNAL), `"key not found"`}, {"invalid/int param", "/block?height=foo", http.StatusOK, int(json2.E_PARSE), "failed to parse param 'height'"}, {"valid/bool int string params", "/tx_search?" + txSearchParams.Encode(), - http.StatusOK, -1, `"total_count":0`}, + http.StatusOK, -1, `"total_count":"0"`}, {"invalid/bool int string params", "/tx_search?" + strings.Replace(txSearchParams.Encode(), "true", "blue", 1), http.StatusOK, int(json2.E_PARSE), "failed to parse param 'prove'"}, diff --git a/rpc/json/types.go b/rpc/json/types.go index 5f8c5c0f88..226f637c52 100644 --- a/rpc/json/types.go +++ b/rpc/json/types.go @@ -161,7 +161,7 @@ func unmarshalStrInt64(b []byte, s *StrInt64) error { type response struct { Version string `json:"jsonrpc"` - Result interface{} `json:"result,omitempty"` + Result json.RawMessage `json:"result,omitempty"` Error *json2.Error `json:"error,omitempty"` Id json.RawMessage `json:"id"` } From 27d3eae7441a96fa870030c7fcc7e276287eb507 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Zdyba=C5=82?= Date: Mon, 4 Jul 2022 16:14:53 +0200 Subject: [PATCH 2/2] fix: use Tendermint JSON serlization for JSON RPC results --- rpc/json/handler.go | 8 +++++++- rpc/json/service_test.go | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rpc/json/handler.go b/rpc/json/handler.go index fcb6b8a6d5..a98038687a 100644 --- a/rpc/json/handler.go +++ b/rpc/json/handler.go @@ -103,7 +103,13 @@ func (h *handler) serveJSONRPCforWS(w http.ResponseWriter, r *http.Request, wsCo // Encode the response. if errResult == nil { - codecReq.WriteResponse(w, rets[0].Interface()) + var raw json.RawMessage + raw, err = tmjson.Marshal(rets[0].Interface()) + if err != nil { + codecReq.WriteError(w, http.StatusInternalServerError, err) + return + } + codecReq.WriteResponse(w, raw) } else { codecReq.WriteError(w, statusCode, errResult) } diff --git a/rpc/json/service_test.go b/rpc/json/service_test.go index 6bab66fdc8..4094632ed4 100644 --- a/rpc/json/service_test.go +++ b/rpc/json/service_test.go @@ -134,7 +134,7 @@ func TestStringyRequest(t *testing.T) { // `starport chain faucet ...` generates broken JSON (ints are "quoted" as strings) brokenJSON := `{"jsonrpc":"2.0","id":0,"method":"tx_search","params":{"order_by":"","page":"1","per_page":"1000","prove":true,"query":"message.sender='cosmos1njr26e02fjcq3schxstv458a3w5szp678h23dh' AND transfer.recipient='cosmos1e0ajth0s847kqcu2ssnhut32fsrptf94fqnfzx'"}}` - respJson := `{"jsonrpc":"2.0","result":{"txs":[],"total_count":0},"id":0}` + "\n" + respJson := `{"jsonrpc":"2.0","result":{"txs":[],"total_count":"0"},"id":0}` + "\n" req := httptest.NewRequest(http.MethodGet, "/", strings.NewReader(brokenJSON)) resp := httptest.NewRecorder()