From 6c60c07f16f09e0f22ab2c3825b258c6b7690b4b Mon Sep 17 00:00:00 2001 From: Ethan Frey Date: Fri, 28 Apr 2017 16:24:06 +0200 Subject: [PATCH] BROKEN: attempt to replace go-wire.JSON with json.Unmarshall in rpc --- rpc/client/httpclient.go | 4 +-- rpc/lib/client/http_client.go | 22 +++++------- rpc/lib/client/ws_client.go | 15 ++++---- rpc/lib/rpc_test.go | 67 ++++++++++++++++++++++++----------- rpc/lib/server/handlers.go | 6 ++-- rpc/lib/types/types.go | 11 ++++-- rpc/test/helpers.go | 4 +-- 7 files changed, 77 insertions(+), 52 deletions(-) diff --git a/rpc/client/httpclient.go b/rpc/client/httpclient.go index 7eecea64..662ced89 100644 --- a/rpc/client/httpclient.go +++ b/rpc/client/httpclient.go @@ -1,10 +1,10 @@ package client import ( + "encoding/json" "fmt" "github.com/pkg/errors" - wire "github.com/tendermint/go-wire" data "github.com/tendermint/go-wire/data" ctypes "github.com/tendermint/tendermint/rpc/core/types" "github.com/tendermint/tendermint/rpc/lib/client" @@ -336,7 +336,7 @@ func (w *WSEvents) eventListener() { // on the merry way to the EventSwitch func (w *WSEvents) parseEvent(data []byte) (err error) { result := new(ctypes.TMResult) - wire.ReadJSONPtr(result, data, &err) + err = json.Unmarshal(data, result) if err != nil { return err } diff --git a/rpc/lib/client/http_client.go b/rpc/lib/client/http_client.go index 45ff8b8a..55963f50 100644 --- a/rpc/lib/client/http_client.go +++ b/rpc/lib/client/http_client.go @@ -12,7 +12,6 @@ import ( "strings" "github.com/pkg/errors" - wire "github.com/tendermint/go-wire" types "github.com/tendermint/tendermint/rpc/lib/types" ) @@ -70,15 +69,15 @@ func NewJSONRPCClient(remote string) *JSONRPCClient { func (c *JSONRPCClient) Call(method string, params map[string]interface{}, result interface{}) (interface{}, error) { // we need this step because we attempt to decode values using `go-wire` // (handlers.go:176) on the server side - encodedParams := make(map[string]interface{}) - for k, v := range params { - bytes := json.RawMessage(wire.JSONBytes(v)) - encodedParams[k] = &bytes - } + // encodedParams := make(map[string]interface{}) + // for k, v := range params { + // bytes := json.RawMessage(wire.JSONBytes(v)) + // encodedParams[k] = &bytes + // } request := types.RPCRequest{ JSONRPC: "2.0", Method: method, - Params: encodedParams, + Params: params, ID: "", } requestBytes, err := json.Marshal(request) @@ -153,7 +152,7 @@ func unmarshalResponseBytes(responseBytes []byte, result interface{}) (interface return nil, errors.Errorf("Response error: %v", errorStr) } // unmarshal the RawMessage into the result - result = wire.ReadJSONPtr(result, *response.Result, &err) + err = json.Unmarshal(*response.Result, result) if err != nil { return nil, errors.Errorf("Error unmarshalling rpc response result: %v", err) } @@ -176,8 +175,6 @@ func argsToURLValues(args map[string]interface{}) (url.Values, error) { } func argsToJson(args map[string]interface{}) error { - var n int - var err error for k, v := range args { rt := reflect.TypeOf(v) isByteSlice := rt.Kind() == reflect.Slice && rt.Elem().Kind() == reflect.Uint8 @@ -188,12 +185,11 @@ func argsToJson(args map[string]interface{}) error { } // Pass everything else to go-wire - buf := new(bytes.Buffer) - wire.WriteJSON(v, buf, &n, &err) + data, err := json.Marshal(v) if err != nil { return err } - args[k] = buf.String() + args[k] = string(data) } return nil } diff --git a/rpc/lib/client/ws_client.go b/rpc/lib/client/ws_client.go index ad922dd6..8884068b 100644 --- a/rpc/lib/client/ws_client.go +++ b/rpc/lib/client/ws_client.go @@ -8,9 +8,8 @@ import ( "github.com/gorilla/websocket" "github.com/pkg/errors" - cmn "github.com/tendermint/tmlibs/common" types "github.com/tendermint/tendermint/rpc/lib/types" - wire "github.com/tendermint/go-wire" + cmn "github.com/tendermint/tmlibs/common" ) const ( @@ -157,15 +156,15 @@ func (wsc *WSClient) Unsubscribe(eventid string) error { func (wsc *WSClient) Call(method string, params map[string]interface{}) error { // we need this step because we attempt to decode values using `go-wire` // (handlers.go:470) on the server side - encodedParams := make(map[string]interface{}) - for k, v := range params { - bytes := json.RawMessage(wire.JSONBytes(v)) - encodedParams[k] = &bytes - } + // encodedParams := make(map[string]interface{}) + // for k, v := range params { + // bytes := json.RawMessage(wire.JSONBytes(v)) + // encodedParams[k] = &bytes + // } err := wsc.WriteJSON(types.RPCRequest{ JSONRPC: "2.0", Method: method, - Params: encodedParams, + Params: params, ID: "", }) return err diff --git a/rpc/lib/rpc_test.go b/rpc/lib/rpc_test.go index f42fd274..cd42f20a 100644 --- a/rpc/lib/rpc_test.go +++ b/rpc/lib/rpc_test.go @@ -3,6 +3,7 @@ package rpc import ( "bytes" crand "crypto/rand" + "encoding/json" "fmt" "math/rand" "net/http" @@ -12,7 +13,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - wire "github.com/tendermint/go-wire" + data "github.com/tendermint/go-data" client "github.com/tendermint/tendermint/rpc/lib/client" server "github.com/tendermint/tendermint/rpc/lib/server" types "github.com/tendermint/tendermint/rpc/lib/types" @@ -29,7 +30,35 @@ const ( ) // Define a type for results and register concrete versions -type Result interface{} +type ResultInner interface{} + +type Result struct { + ResultInner `json:"unwrap"` +} + +func (r Result) MarshalJSON() ([]byte, error) { + return resultMapper.ToJSON(r.ResultInner) +} + +func (r *Result) UnmarshalJSON(data []byte) (err error) { + parsed, err := resultMapper.FromJSON(data) + if err == nil && parsed != nil { + r.ResultInner = parsed.(ResultInner) + } + return +} + +func (r Result) Unwrap() ResultInner { + tmrI := r.ResultInner + for wrap, ok := tmrI.(Result); ok; wrap, ok = tmrI.(Result) { + tmrI = wrap.ResultInner + } + return tmrI +} + +func (r Result) Empty() bool { + return r.ResultInner == nil +} type ResultEcho struct { Value string @@ -39,11 +68,9 @@ type ResultEchoBytes struct { Value []byte } -var _ = wire.RegisterInterface( - struct{ Result }{}, - wire.ConcreteType{&ResultEcho{}, 0x1}, - wire.ConcreteType{&ResultEchoBytes{}, 0x2}, -) +var resultMapper = data.NewMapper(Result{}). + RegisterImplementation(&ResultEcho{}, "echo", 0x1). + RegisterImplementation(&ResultEchoBytes{}, "echo_bytes", 0x2) // Define some routes var Routes = map[string]*server.RPCFunc{ @@ -53,15 +80,15 @@ var Routes = map[string]*server.RPCFunc{ } func EchoResult(v string) (Result, error) { - return &ResultEcho{v}, nil + return Result{&ResultEcho{v}}, nil } func EchoWSResult(wsCtx types.WSRPCContext, v string) (Result, error) { - return &ResultEcho{v}, nil + return Result{&ResultEcho{v}}, nil } func EchoBytesResult(v []byte) (Result, error) { - return &ResultEchoBytes{v}, nil + return Result{&ResultEchoBytes{v}}, nil } // launch unix and tcp servers @@ -109,7 +136,7 @@ func echoViaHTTP(cl client.HTTPClient, val string) (string, error) { if _, err := cl.Call("echo", params, &result); err != nil { return "", err } - return result.(*ResultEcho).Value, nil + return result.Unwrap().(*ResultEcho).Value, nil } func echoBytesViaHTTP(cl client.HTTPClient, bytes []byte) ([]byte, error) { @@ -120,7 +147,7 @@ func echoBytesViaHTTP(cl client.HTTPClient, bytes []byte) ([]byte, error) { if _, err := cl.Call("echo_bytes", params, &result); err != nil { return []byte{}, err } - return result.(*ResultEchoBytes).Value, nil + return result.Unwrap().(*ResultEchoBytes).Value, nil } func testWithHTTPClient(t *testing.T, cl client.HTTPClient) { @@ -147,11 +174,11 @@ func echoViaWS(cl *client.WSClient, val string) (string, error) { select { case msg := <-cl.ResultsCh: result := new(Result) - wire.ReadJSONPtr(result, msg, &err) + err = json.Unmarshal(msg, result) if err != nil { return "", nil } - return (*result).(*ResultEcho).Value, nil + return result.Unwrap().(*ResultEcho).Value, nil case err := <-cl.ErrorsCh: return "", err } @@ -169,11 +196,11 @@ func echoBytesViaWS(cl *client.WSClient, bytes []byte) ([]byte, error) { select { case msg := <-cl.ResultsCh: result := new(Result) - wire.ReadJSONPtr(result, msg, &err) + err = json.Unmarshal(msg, result) if err != nil { return []byte{}, nil } - return (*result).(*ResultEchoBytes).Value, nil + return result.Unwrap().(*ResultEchoBytes).Value, nil case err := <-cl.ErrorsCh: return []byte{}, err } @@ -252,9 +279,9 @@ func TestWSNewWSRPCFunc(t *testing.T) { select { case msg := <-cl.ResultsCh: result := new(Result) - wire.ReadJSONPtr(result, msg, &err) + err = json.Unmarshal(msg, result) require.Nil(t, err) - got := (*result).(*ResultEcho).Value + got := result.Unwrap().(*ResultEcho).Value assert.Equal(t, got, val) case err := <-cl.ErrorsCh: t.Fatal(err) @@ -280,9 +307,9 @@ func TestWSHandlesArrayParams(t *testing.T) { select { case msg := <-cl.ResultsCh: result := new(Result) - wire.ReadJSONPtr(result, msg, &err) + err = json.Unmarshal(msg, result) require.Nil(t, err) - got := (*result).(*ResultEcho).Value + got := result.Unwrap().(*ResultEcho).Value assert.Equal(t, got, val) case err := <-cl.ErrorsCh: t.Fatalf("%+v", err) diff --git a/rpc/lib/server/handlers.go b/rpc/lib/server/handlers.go index d7dffd40..27451c23 100644 --- a/rpc/lib/server/handlers.go +++ b/rpc/lib/server/handlers.go @@ -280,9 +280,8 @@ func httpParamsToArgs(rpcFunc *RPCFunc, r *http.Request) ([]reflect.Value, error } func _jsonStringToArg(ty reflect.Type, arg string) (reflect.Value, error) { - var err error v := reflect.New(ty) - wire.ReadJSONPtr(v.Interface(), []byte(arg), &err) + err := json.Unmarshal([]byte(arg), v.Interface()) if err != nil { return v, err } @@ -315,9 +314,8 @@ func nonJsonToArg(ty reflect.Type, arg string) (reflect.Value, error, bool) { } if isQuotedString && expectingByteSlice { - var err error v := reflect.New(reflect.TypeOf("")) - wire.ReadJSONPtr(v.Interface(), []byte(arg), &err) + err := json.Unmarshal([]byte(arg), v.Interface()) if err != nil { return reflect.ValueOf(nil), err, false } diff --git a/rpc/lib/types/types.go b/rpc/lib/types/types.go index 9c5f2625..28ddfc0f 100644 --- a/rpc/lib/types/types.go +++ b/rpc/lib/types/types.go @@ -4,7 +4,6 @@ import ( "encoding/json" "strings" - wire "github.com/tendermint/go-wire" events "github.com/tendermint/tmlibs/events" ) @@ -52,8 +51,14 @@ type RPCResponse struct { func NewRPCResponse(id string, res interface{}, err string) RPCResponse { var raw *json.RawMessage if res != nil { - rawMsg := json.RawMessage(wire.JSONBytes(res)) - raw = &rawMsg + var js []byte + js, err2 := json.Marshal(res) + if err2 == nil { + rawMsg := json.RawMessage(js) + raw = &rawMsg + } else { + err = err2.Error() + } } return RPCResponse{ JSONRPC: "2.0", diff --git a/rpc/test/helpers.go b/rpc/test/helpers.go index 62289059..76d04f51 100644 --- a/rpc/test/helpers.go +++ b/rpc/test/helpers.go @@ -1,6 +1,7 @@ package rpctest import ( + "encoding/json" "fmt" "math/rand" "os" @@ -11,7 +12,6 @@ import ( "github.com/spf13/viper" "github.com/stretchr/testify/require" - wire "github.com/tendermint/go-wire" logger "github.com/tendermint/tmlibs/logger" abci "github.com/tendermint/abci/types" @@ -132,7 +132,7 @@ func waitForEvent(t *testing.T, wsc *client.WSClient, eventid string, dieOnTimeo select { case r := <-wsc.ResultsCh: result := new(ctypes.TMResult) - wire.ReadJSONPtr(result, r, &err) + err = json.Unmarshal(r, result) if err != nil { errCh <- err break LOOP