diff options
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/json.go | 67 | ||||
-rw-r--r-- | rpc/types.go | 115 | ||||
-rw-r--r-- | rpc/types_test.go | 95 |
3 files changed, 34 insertions, 243 deletions
diff --git a/rpc/json.go b/rpc/json.go index a7053e3f5..ac5a4acd3 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -17,6 +17,7 @@ package rpc import ( + "bytes" "encoding/json" "fmt" "io" @@ -256,8 +257,8 @@ func parseBatchRequest(incomingMsg json.RawMessage) ([]rpcRequest, bool, Error) return requests, true, nil } -// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given types. It returns the parsed -// values or an error when the parsing failed. +// ParseRequestArguments tries to parse the given params (json.RawMessage) with the given +// types. It returns the parsed values or an error when the parsing failed. func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interface{}) ([]reflect.Value, Error) { if args, ok := params.(json.RawMessage); !ok { return nil, &invalidParamsError{"Invalid params supplied"} @@ -266,42 +267,42 @@ func (c *jsonCodec) ParseRequestArguments(argTypes []reflect.Type, params interf } } -// parsePositionalArguments tries to parse the given args to an array of values with the given types. -// It returns the parsed values or an error when the args could not be parsed. Missing optional arguments -// are returned as reflect.Zero values. -func parsePositionalArguments(args json.RawMessage, callbackArgs []reflect.Type) ([]reflect.Value, Error) { - params := make([]interface{}, 0, len(callbackArgs)) - for _, t := range callbackArgs { - params = append(params, reflect.New(t).Interface()) +// parsePositionalArguments tries to parse the given args to an array of values with the +// given types. It returns the parsed values or an error when the args could not be +// parsed. Missing optional arguments are returned as reflect.Zero values. +func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, Error) { + // Read beginning of the args array. + dec := json.NewDecoder(bytes.NewReader(rawArgs)) + if tok, _ := dec.Token(); tok != json.Delim('[') { + return nil, &invalidParamsError{"non-array args"} } - - if err := json.Unmarshal(args, ¶ms); err != nil { - return nil, &invalidParamsError{err.Error()} - } - - if len(params) > len(callbackArgs) { - return nil, &invalidParamsError{fmt.Sprintf("too many params, want %d got %d", len(callbackArgs), len(params))} + // Read args. + args := make([]reflect.Value, 0, len(types)) + for i := 0; dec.More(); i++ { + if i >= len(types) { + return nil, &invalidParamsError{fmt.Sprintf("too many arguments, want at most %d", len(types))} + } + argval := reflect.New(types[i]) + if err := dec.Decode(argval.Interface()); err != nil { + return nil, &invalidParamsError{fmt.Sprintf("invalid argument %d: %v", i, err)} + } + if argval.IsNil() && types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} + } + args = append(args, argval.Elem()) } - - // assume missing params are null values - for i := len(params); i < len(callbackArgs); i++ { - params = append(params, nil) + // Read end of args array. + if _, err := dec.Token(); err != nil { + return nil, &invalidParamsError{err.Error()} } - - argValues := make([]reflect.Value, len(params)) - for i, p := range params { - // verify that JSON null values are only supplied for optional arguments (ptr types) - if p == nil && callbackArgs[i].Kind() != reflect.Ptr { - return nil, &invalidParamsError{fmt.Sprintf("invalid or missing value for params[%d]", i)} - } - if p == nil { - argValues[i] = reflect.Zero(callbackArgs[i]) - } else { // deref pointers values creates previously with reflect.New - argValues[i] = reflect.ValueOf(p).Elem() + // Set any missing args to nil. + for i := len(args); i < len(types); i++ { + if types[i].Kind() != reflect.Ptr { + return nil, &invalidParamsError{fmt.Sprintf("missing value for required argument %d", i)} } + args = append(args, reflect.Zero(types[i])) } - - return argValues, nil + return args, nil } // CreateResponse will create a JSON-RPC success response with the given id and reply as result. diff --git a/rpc/types.go b/rpc/types.go index ebe388373..01b95a170 100644 --- a/rpc/types.go +++ b/rpc/types.go @@ -17,8 +17,6 @@ package rpc import ( - "bytes" - "encoding/hex" "fmt" "math" "math/big" @@ -123,91 +121,6 @@ type ServerCodec interface { Closed() <-chan interface{} } -// HexNumber serializes a number to hex format using the "%#x" format -type HexNumber big.Int - -// NewHexNumber creates a new hex number instance which will serialize the given val with `%#x` on marshal. -func NewHexNumber(val interface{}) *HexNumber { - if val == nil { - return nil // note, this doesn't catch nil pointers, only passing nil directly! - } - - if v, ok := val.(*big.Int); ok { - if v != nil { - return (*HexNumber)(new(big.Int).Set(v)) - } - return nil - } - - rval := reflect.ValueOf(val) - - var unsigned uint64 - utype := reflect.TypeOf(unsigned) - if t := rval.Type(); t.ConvertibleTo(utype) { - hn := new(big.Int).SetUint64(rval.Convert(utype).Uint()) - return (*HexNumber)(hn) - } - - var signed int64 - stype := reflect.TypeOf(signed) - if t := rval.Type(); t.ConvertibleTo(stype) { - hn := new(big.Int).SetInt64(rval.Convert(stype).Int()) - return (*HexNumber)(hn) - } - - return nil -} - -func (h *HexNumber) UnmarshalJSON(input []byte) error { - length := len(input) - if length >= 2 && input[0] == '"' && input[length-1] == '"' { - input = input[1 : length-1] - } - - hn := (*big.Int)(h) - if _, ok := hn.SetString(string(input), 0); ok { - return nil - } - - return fmt.Errorf("Unable to parse number") -} - -// MarshalJSON serialize the hex number instance to a hex representation. -func (h *HexNumber) MarshalJSON() ([]byte, error) { - if h != nil { - hn := (*big.Int)(h) - if hn.BitLen() == 0 { - return []byte(`"0x0"`), nil - } - return []byte(fmt.Sprintf(`"0x%x"`, hn)), nil - } - return nil, nil -} - -func (h *HexNumber) Int() int { - hn := (*big.Int)(h) - return int(hn.Int64()) -} - -func (h *HexNumber) Int64() int64 { - hn := (*big.Int)(h) - return hn.Int64() -} - -func (h *HexNumber) Uint() uint { - hn := (*big.Int)(h) - return uint(hn.Uint64()) -} - -func (h *HexNumber) Uint64() uint64 { - hn := (*big.Int)(h) - return hn.Uint64() -} - -func (h *HexNumber) BigInt() *big.Int { - return (*big.Int)(h) -} - var ( pendingBlockNumber = big.NewInt(-2) latestBlockNumber = big.NewInt(-1) @@ -274,31 +187,3 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error { func (bn BlockNumber) Int64() int64 { return (int64)(bn) } - -// HexBytes JSON-encodes as hex with 0x prefix. -type HexBytes []byte - -func (b HexBytes) MarshalJSON() ([]byte, error) { - result := make([]byte, len(b)*2+4) - copy(result, `"0x`) - hex.Encode(result[3:], b) - result[len(result)-1] = '"' - return result, nil -} - -func (b *HexBytes) UnmarshalJSON(input []byte) error { - if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' { - input = input[1 : len(input)-1] - } - if !bytes.HasPrefix(input, []byte("0x")) { - return fmt.Errorf("missing 0x prefix for hex byte array") - } - input = input[2:] - if len(input) == 0 { - *b = nil - return nil - } - *b = make([]byte, len(input)/2) - _, err := hex.Decode(*b, input) - return err -} diff --git a/rpc/types_test.go b/rpc/types_test.go deleted file mode 100644 index 5482557b8..000000000 --- a/rpc/types_test.go +++ /dev/null @@ -1,95 +0,0 @@ -// Copyright 2015 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. - -package rpc - -import ( - "bytes" - "encoding/json" - "math/big" - "testing" -) - -func TestNewHexNumber(t *testing.T) { - tests := []interface{}{big.NewInt(123), int64(123), uint64(123), int8(123), uint8(123)} - - for i, v := range tests { - hn := NewHexNumber(v) - if hn == nil { - t.Fatalf("Unable to create hex number instance for tests[%d]", i) - } - if hn.Int64() != 123 { - t.Fatalf("expected %d, got %d on value tests[%d]", 123, hn.Int64(), i) - } - } - - failures := []interface{}{"", nil, []byte{1, 2, 3, 4}} - for i, v := range failures { - hn := NewHexNumber(v) - if hn != nil { - t.Fatalf("Creating a nex number instance of %T should fail (failures[%d])", failures[i], i) - } - } -} - -func TestHexNumberUnmarshalJSON(t *testing.T) { - tests := []string{`"0x4d2"`, "1234", `"1234"`} - for i, v := range tests { - var hn HexNumber - if err := json.Unmarshal([]byte(v), &hn); err != nil { - t.Fatalf("Test %d failed - %s", i, err) - } - - if hn.Int64() != 1234 { - t.Fatalf("Expected %d, got %d for test[%d]", 1234, hn.Int64(), i) - } - } -} - -func TestHexNumberMarshalJSON(t *testing.T) { - hn := NewHexNumber(1234567890) - got, err := json.Marshal(hn) - if err != nil { - t.Fatalf("Unable to marshal hex number - %s", err) - } - - exp := []byte(`"0x499602d2"`) - if bytes.Compare(exp, got) != 0 { - t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got) - } -} - -var hexBytesTests = []struct{ in, out []byte }{ - {in: []byte(`"0x"`), out: []byte{}}, - {in: []byte(`"0x00"`), out: []byte{0}}, - {in: []byte(`"0x01ff"`), out: []byte{0x01, 0xFF}}, -} - -func TestHexBytes(t *testing.T) { - for i, test := range hexBytesTests { - var dec HexBytes - if err := json.Unmarshal(test.in, &dec); err != nil { - t.Fatalf("test %d: can't decode: %v", i, err) - } - enc, _ := json.Marshal(HexBytes(test.out)) - if !bytes.Equal(dec, test.out) { - t.Errorf("test %d: wrong decoded value 0x%x", i, dec) - } - if !bytes.Equal(enc, test.in) { - t.Errorf("test %d: wrong encoded value %#q", i, enc) - } - } -} |