From 094f921e5028fc215efbc86118e3d3e5b0663055 Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Thu, 12 Mar 2015 19:07:03 -0500
Subject: Convert to proper errors

Allow returning different JSON RPC error codes depending on error type
---
 rpc/api.go      |  18 ++++----
 rpc/args.go     | 125 ++++++++++++++++++++++++++++++++++----------------------
 rpc/http.go     |  39 +++++++++++++++---
 rpc/messages.go |  99 ++++++++++++++++++++++++++------------------
 rpc/util.go     |   6 +--
 5 files changed, 183 insertions(+), 104 deletions(-)

(limited to 'rpc')

diff --git a/rpc/api.go b/rpc/api.go
index b94d2d6dc..b72a0dd60 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -578,7 +578,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		}
 		return p.Call(args, reply)
 	case "eth_flush":
-		return errNotImplemented
+		return NewNotImplementedError(req.Method)
 	case "eth_getBlockByHash":
 		args := new(GetBlockByHashArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
@@ -618,7 +618,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
-			return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
+			return NewValidationError("Index", "does not exist")
 		}
 		*reply = v.Transactions[args.Index]
 	case "eth_getTransactionByBlockNumberAndIndex":
@@ -632,7 +632,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		if args.Index > int64(len(v.Transactions)) || args.Index < 0 {
-			return NewErrorWithMessage(errDecodeArgs, "Transaction index does not exist")
+			return NewValidationError("Index", "does not exist")
 		}
 		*reply = v.Transactions[args.Index]
 	case "eth_getUncleByBlockHashAndIndex":
@@ -646,7 +646,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
-			return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
+			return NewValidationError("Index", "does not exist")
 		}
 
 		uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
@@ -665,7 +665,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		if args.Index > int64(len(v.Uncles)) || args.Index < 0 {
-			return NewErrorWithMessage(errDecodeArgs, "Uncle index does not exist")
+			return NewValidationError("Index", "does not exist")
 		}
 
 		uncle, err := p.GetBlockByHash(toHex(v.Uncles[args.Index]), false)
@@ -678,7 +678,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 	case "eth_compileSolidity":
 	case "eth_compileLLL":
 	case "eth_compileSerpent":
-		return errNotImplemented
+		return NewNotImplementedError(req.Method)
 	case "eth_newFilter":
 		args := new(FilterOptions)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
@@ -717,7 +717,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		return p.AllLogs(args, reply)
 	case "eth_getWork":
 	case "eth_submitWork":
-		return errNotImplemented
+		return NewNotImplementedError(req.Method)
 	case "db_put":
 		args := new(DbArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
@@ -746,7 +746,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		return p.HasWhisperIdentity(args.Identity, reply)
 	case "shh_newGroup":
 	case "shh_addToGroup":
-		return errNotImplemented
+		return NewNotImplementedError(req.Method)
 	case "shh_newFilter":
 		args := new(WhisperFilterArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
@@ -790,7 +790,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 	// 	}
 	// 	return p.WatchTx(args, reply)
 	default:
-		return NewErrorWithMessage(errNotImplemented, req.Method)
+		return NewNotImplementedError(req.Method)
 	}
 
 	rpclogger.DebugDetailf("Reply: %T %s", reply, reply)
diff --git a/rpc/args.go b/rpc/args.go
index faca03b63..8d4ad5967 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -11,7 +11,7 @@ import (
 func blockNumber(raw json.RawMessage, number *int64) (err error) {
 	var str string
 	if err = json.Unmarshal(raw, &str); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	switch str {
@@ -34,16 +34,16 @@ func (args *GetBlockByHashArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	argstr, ok := obj[0].(string)
 	if !ok {
-		return errDecodeArgs
+		return NewDecodeParamError("BlockHash not a string")
 	}
 	args.BlockHash = argstr
 
@@ -63,11 +63,11 @@ func (args *GetBlockByNumberArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	if v, ok := obj[0].(float64); ok {
@@ -117,7 +117,7 @@ type GetStorageArgs struct {
 
 func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
 	if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	return nil
@@ -125,7 +125,7 @@ func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (args *GetStorageArgs) requirements() error {
 	if len(args.Address) == 0 {
-		return NewErrorWithMessage(errArguments, "Address cannot be blank")
+		return NewValidationError("Address", "cannot be blank")
 	}
 	return nil
 }
@@ -139,10 +139,10 @@ type GetStorageAtArgs struct {
 func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []string
 	if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 	if len(obj) < 2 {
-		return errDecodeArgs
+		return NewInsufficientParamsError(len(obj), 2)
 	}
 
 	args.Address = obj[0]
@@ -153,11 +153,11 @@ func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (args *GetStorageAtArgs) requirements() error {
 	if len(args.Address) == 0 {
-		return NewErrorWithMessage(errArguments, "Address cannot be blank")
+		return NewValidationError("Address", "cannot be blank")
 	}
 
 	if len(args.Key) == 0 {
-		return NewErrorWithMessage(errArguments, "Key cannot be blank")
+		return NewValidationError("Key", "cannot be blank")
 	}
 	return nil
 }
@@ -169,7 +169,7 @@ type GetTxCountArgs struct {
 
 func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
 	if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	return nil
@@ -177,7 +177,7 @@ func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (args *GetTxCountArgs) requirements() error {
 	if len(args.Address) == 0 {
-		return NewErrorWithMessage(errArguments, "Address cannot be blank")
+		return NewValidationError("Address", "cannot be blank")
 	}
 	return nil
 }
@@ -191,16 +191,16 @@ func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	addstr, ok := obj[0].(string)
 	if !ok {
-		return errDecodeArgs
+		return NewDecodeParamError("Address is not a string")
 	}
 	args.Address = addstr
 
@@ -213,7 +213,7 @@ func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
 	}
 
 	// if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
-	// 	return errDecodeArgs
+	// 	return NewDecodeParamError(err.Error())
 	// }
 
 	return nil
@@ -221,7 +221,7 @@ func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (args *GetBalanceArgs) requirements() error {
 	if len(args.Address) == 0 {
-		return NewErrorWithMessage(errArguments, "Address cannot be blank")
+		return NewValidationError("Address", "cannot be blank")
 	}
 	return nil
 }
@@ -233,7 +233,7 @@ type GetDataArgs struct {
 
 func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
 	if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	return nil
@@ -241,7 +241,7 @@ func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (args *GetDataArgs) requirements() error {
 	if len(args.Address) == 0 {
-		return NewErrorWithMessage(errArguments, "Address cannot be blank")
+		return NewValidationError("Address", "cannot be blank")
 	}
 	return nil
 }
@@ -255,23 +255,23 @@ func (args *BlockNumIndexArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	arg0, ok := obj[0].(string)
 	if !ok {
-		return errDecodeArgs
+		return NewDecodeParamError("BlockNumber is not string")
 	}
 	args.BlockNumber = ethutil.Big(arg0).Int64()
 
 	if len(obj) > 1 {
 		arg1, ok := obj[1].(string)
 		if !ok {
-			return errDecodeArgs
+			return NewDecodeParamError("Index not a string")
 		}
 		args.Index = ethutil.Big(arg1).Int64()
 	}
@@ -288,23 +288,23 @@ func (args *HashIndexArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	arg0, ok := obj[0].(string)
 	if !ok {
-		return errDecodeArgs
+		return NewDecodeParamError("Hash not a string")
 	}
 	args.Hash = arg0
 
 	if len(obj) > 1 {
 		arg1, ok := obj[1].(string)
 		if !ok {
-			return errDecodeArgs
+			return NewDecodeParamError("Index not a string")
 		}
 		args.Index = ethutil.Big(arg1).Int64()
 	}
@@ -320,11 +320,11 @@ func (args *Sha3Args) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return NewErrorWithMessage(errDecodeArgs, err.Error())
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 	args.Data = obj[0].(string)
 
@@ -387,12 +387,13 @@ func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) {
 	}
 
 	if err = json.Unmarshal(b, &obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
+
 	args.Earliest = int64(ethutil.Big(obj[0].FromBlock).Int64())
 	args.Latest = int64(ethutil.Big(obj[0].ToBlock).Int64())
 	args.Max = int(ethutil.Big(obj[0].Limit).Int64())
@@ -417,11 +418,11 @@ func (args *DbArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 2 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 2)
 	}
 	args.Database = obj[0].(string)
 	args.Key = obj[1].(string)
@@ -435,10 +436,10 @@ func (args *DbArgs) UnmarshalJSON(b []byte) (err error) {
 
 func (a *DbArgs) requirements() error {
 	if len(a.Database) == 0 {
-		return NewErrorWithMessage(errArguments, "Database cannot be blank")
+		return NewValidationError("Database", "cannot be blank")
 	}
 	if len(a.Key) == 0 {
-		return NewErrorWithMessage(errArguments, "Key cannot be blank")
+		return NewValidationError("Key", "cannot be blank")
 	}
 	return nil
 }
@@ -463,11 +464,11 @@ func (args *WhisperMessageArgs) UnmarshalJSON(b []byte) (err error) {
 	}
 
 	if err = json.Unmarshal(b, &obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 	args.Payload = obj[0].Payload
 	args.To = obj[0].To
@@ -487,7 +488,7 @@ func (args *CompileArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) > 0 {
@@ -505,11 +506,11 @@ func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []string
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errDecodeArgs
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	args.Word = obj[0]
@@ -525,11 +526,11 @@ func (args *FilterIdArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []string
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errDecodeArgs
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	args.Id = int(ethutil.Big(obj[0]).Int64())
@@ -545,11 +546,11 @@ func (args *WhisperIdentityArgs) UnmarshalJSON(b []byte) (err error) {
 	var obj []string
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errDecodeArgs
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	args.Identity = obj[0]
@@ -571,11 +572,11 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
 	}
 
 	if err = json.Unmarshal(b, &obj); err != nil {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	if len(obj) < 1 {
-		return errArguments
+		return NewInsufficientParamsError(len(obj), 1)
 	}
 
 	args.To = obj[0].To
@@ -584,3 +585,31 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) {
 
 	return nil
 }
+
+// func (req *RpcRequest) ToRegisterArgs() (string, error) {
+// 	if len(req.Params) < 1 {
+// 		return "", errArguments
+// 	}
+
+// 	var args string
+// 	err := json.Unmarshal(req.Params, &args)
+// 	if err != nil {
+// 		return "", err
+// 	}
+
+// 	return args, nil
+// }
+
+// func (req *RpcRequest) ToWatchTxArgs() (string, error) {
+// 	if len(req.Params) < 1 {
+// 		return "", errArguments
+// 	}
+
+// 	var args string
+// 	err := json.Unmarshal(req.Params, &args)
+// 	if err != nil {
+// 		return "", err
+// 	}
+
+// 	return args, nil
+// }
diff --git a/rpc/http.go b/rpc/http.go
index 857cf3221..8b45319ff 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -25,22 +25,51 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 		rpchttplogger.DebugDetailln("Handling request")
 
 		if req.ContentLength > maxSizeReqLength {
-			jsonerr := &RpcErrorObject{-32700, "Error: Request too large"}
+			jsonerr := &RpcErrorObject{-32700, "Request too large"}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
 			return
 		}
 
 		reqParsed, reqerr := json.ParseRequestBody(req)
-		if reqerr != nil {
-			jsonerr := &RpcErrorObject{-32700, "Error: Could not parse request"}
+		switch reqerr.(type) {
+		case nil:
+			break
+		case *DecodeParamError:
+			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			return
+		case *InsufficientParamsError:
+			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			return
+		case *ValidationError:
+			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
+			return
+		default:
+			jsonerr := &RpcErrorObject{-32700, "Could not parse request"}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
 			return
 		}
 
 		var response interface{}
 		reserr := api.GetRequestReply(&reqParsed, &response)
-		if reserr != nil {
-			rpchttplogger.Warnln(reserr)
+		switch reserr.(type) {
+		case nil:
+			break
+		case *NotImplementedError:
+			jsonerr := &RpcErrorObject{-32601, reserr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			return
+		case *InsufficientParamsError:
+			jsonerr := &RpcErrorObject{-32602, reserr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			return
+		case *ValidationError:
+			jsonerr := &RpcErrorObject{-32602, reserr.Error()}
+			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
+			return
+		default:
 			jsonerr := &RpcErrorObject{-32603, reserr.Error()}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
 			return
diff --git a/rpc/messages.go b/rpc/messages.go
index a3ebbf330..781394196 100644
--- a/rpc/messages.go
+++ b/rpc/messages.go
@@ -18,16 +18,69 @@ package rpc
 
 import (
 	"encoding/json"
-	"errors"
 	"fmt"
 )
 
-var (
-	errArguments      = errors.New("Error: Insufficient arguments")
-	errNotImplemented = errors.New("Error: Method not implemented")
-	errUnknown        = errors.New("Error: Unknown error")
-	errDecodeArgs     = errors.New("Error: Could not decode arguments")
-)
+type InsufficientParamsError struct {
+	have int
+	want int
+}
+
+func (e *InsufficientParamsError) Error() string {
+	return fmt.Sprintf("insufficient params, want %d have %d", e.want, e.have)
+}
+
+func NewInsufficientParamsError(have int, want int) *InsufficientParamsError {
+	return &InsufficientParamsError{
+		have: have,
+		want: want,
+	}
+}
+
+type NotImplementedError struct {
+	Method string
+}
+
+func (e *NotImplementedError) Error() string {
+	return fmt.Sprintf("%s method not implemented", e.Method)
+}
+
+func NewNotImplementedError(method string) *NotImplementedError {
+	return &NotImplementedError{
+		Method: method,
+	}
+}
+
+type DecodeParamError struct {
+	err string
+}
+
+func (e *DecodeParamError) Error() string {
+	return fmt.Sprintf("could not decode, %s", e.err)
+
+}
+
+func NewDecodeParamError(errstr string) error {
+	return &DecodeParamError{
+		err: errstr,
+	}
+}
+
+type ValidationError struct {
+	ParamName string
+	msg       string
+}
+
+func (e *ValidationError) Error() string {
+	return fmt.Sprintf("%s not valid, %s", e.ParamName, e.msg)
+}
+
+func NewValidationError(param string, msg string) error {
+	return &ValidationError{
+		ParamName: param,
+		msg:       msg,
+	}
+}
 
 type RpcRequest struct {
 	ID      interface{}     `json:"id"`
@@ -53,35 +106,3 @@ type RpcErrorObject struct {
 	Message string `json:"message"`
 	// Data    interface{} `json:"data"`
 }
-
-func NewErrorWithMessage(err error, msg string) error {
-	return fmt.Errorf("%s: %s", err.Error(), msg)
-}
-
-// func (req *RpcRequest) ToRegisterArgs() (string, error) {
-// 	if len(req.Params) < 1 {
-// 		return "", errArguments
-// 	}
-
-// 	var args string
-// 	err := json.Unmarshal(req.Params, &args)
-// 	if err != nil {
-// 		return "", err
-// 	}
-
-// 	return args, nil
-// }
-
-// func (req *RpcRequest) ToWatchTxArgs() (string, error) {
-// 	if len(req.Params) < 1 {
-// 		return "", errArguments
-// 	}
-
-// 	var args string
-// 	err := json.Unmarshal(req.Params, &args)
-// 	if err != nil {
-// 		return "", err
-// 	}
-
-// 	return args, nil
-// }
diff --git a/rpc/util.go b/rpc/util.go
index 8ff3c6d31..573190e59 100644
--- a/rpc/util.go
+++ b/rpc/util.go
@@ -42,7 +42,7 @@ type JsonWrapper struct{}
 func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error) {
 	var data []json.RawMessage
 	if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
-		return errDecodeArgs
+		return NewDecodeParamError(err.Error())
 	}
 
 	// Number index determines the index in the array for a possible block number
@@ -74,7 +74,7 @@ func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error
 		fallthrough
 	default:
 		if err = json.Unmarshal(data[0], iface); err != nil {
-			return errDecodeArgs
+			return NewDecodeParamError(err.Error())
 		}
 		numberIndex = 1
 	}
@@ -82,7 +82,7 @@ func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error
 	// <0 index means out of bound for block number
 	if numberIndex >= 0 && len(data) > numberIndex {
 		if err = blockNumber(data[numberIndex], number); err != nil {
-			return errDecodeArgs
+			return NewDecodeParamError(err.Error())
 		}
 	}
 
-- 
cgit v1.2.3


From d4ed66c83df40c6d3035e21c705b4ca06e52a0be Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Thu, 12 Mar 2015 19:20:46 -0500
Subject: Add web3_clientVersion

---
 rpc/api.go | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

(limited to 'rpc')

diff --git a/rpc/api.go b/rpc/api.go
index b72a0dd60..05f4d0bc4 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -477,6 +477,10 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		*reply = toHex(crypto.Sha3(fromHex(args.Data)))
+	case "web3_clientVersion":
+		*reply = p.xeth().Backend().Version()
+	case "net_version":
+		return NewNotImplementedError(req.Method)
 	case "net_listening":
 		*reply = p.xeth().IsListening()
 	case "net_peerCount":
@@ -675,9 +679,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		*reply = uncle
 	case "eth_getCompilers":
 		return p.GetCompilers(reply)
-	case "eth_compileSolidity":
-	case "eth_compileLLL":
-	case "eth_compileSerpent":
+	case "eth_compileSolidity", "eth_compileLLL", "eth_compileSerpent":
 		return NewNotImplementedError(req.Method)
 	case "eth_newFilter":
 		args := new(FilterOptions)
@@ -715,8 +717,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		return p.AllLogs(args, reply)
-	case "eth_getWork":
-	case "eth_submitWork":
+	case "eth_getWork", "eth_submitWork":
 		return NewNotImplementedError(req.Method)
 	case "db_put":
 		args := new(DbArgs)
@@ -744,8 +745,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 			return err
 		}
 		return p.HasWhisperIdentity(args.Identity, reply)
-	case "shh_newGroup":
-	case "shh_addToGroup":
+	case "shh_newGroup", "shh_addToGroup":
 		return NewNotImplementedError(req.Method)
 	case "shh_newFilter":
 		args := new(WhisperFilterArgs)
-- 
cgit v1.2.3


From 0932f843830a30ea3da5d866fbe4e459d2748b1e Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Fri, 13 Mar 2015 10:03:19 -0400
Subject: Fix eth_newBlockFilter

---
 rpc/api.go  | 12 ++++++++----
 rpc/args.go |  9 +++++++--
 2 files changed, 15 insertions(+), 6 deletions(-)

(limited to 'rpc')

diff --git a/rpc/api.go b/rpc/api.go
index 05f4d0bc4..630fb32b5 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -176,7 +176,7 @@ func (self *EthereumApi) UninstallFilter(id int, reply *interface{}) error {
 	return nil
 }
 
-func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error {
+func (self *EthereumApi) NewFilterString(args *FilterStringArgs, reply *interface{}) error {
 	var id int
 	filter := core.NewFilter(self.xeth().Backend())
 
@@ -186,10 +186,14 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error
 
 		self.logs[id].add(&state.StateLog{})
 	}
-	if args == "pending" {
+
+	switch args.Word {
+	case "pending":
 		filter.PendingCallback = callback
-	} else if args == "chain" {
+	case "latest":
 		filter.BlockCallback = callback
+	default:
+		return NewValidationError("Word", "Must be `latest` or `pending`")
 	}
 
 	id = self.filterManager.InstallFilter(filter)
@@ -692,7 +696,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		if err := json.Unmarshal(req.Params, &args); err != nil {
 			return err
 		}
-		return p.NewFilterString(args.Word, reply)
+		return p.NewFilterString(args, reply)
 	case "eth_uninstallFilter":
 		args := new(FilterIdArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
diff --git a/rpc/args.go b/rpc/args.go
index 8d4ad5967..b935c5007 100644
--- a/rpc/args.go
+++ b/rpc/args.go
@@ -503,7 +503,7 @@ type FilterStringArgs struct {
 }
 
 func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
-	var obj []string
+	var obj []interface{}
 	r := bytes.NewReader(b)
 	if err := json.NewDecoder(r).Decode(&obj); err != nil {
 		return NewDecodeParamError(err.Error())
@@ -513,7 +513,12 @@ func (args *FilterStringArgs) UnmarshalJSON(b []byte) (err error) {
 		return NewInsufficientParamsError(len(obj), 1)
 	}
 
-	args.Word = obj[0]
+	var argstr string
+	argstr, ok := obj[0].(string)
+	if !ok {
+		return NewDecodeParamError("Filter is not a string")
+	}
+	args.Word = argstr
 
 	return nil
 }
-- 
cgit v1.2.3


From d3f96dc720bcda6a3db45c69f6ff4ff66cac5ec0 Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Fri, 13 Mar 2015 10:03:48 -0400
Subject: Consolidate error type switch

---
 rpc/http.go | 16 ++--------------
 1 file changed, 2 insertions(+), 14 deletions(-)

(limited to 'rpc')

diff --git a/rpc/http.go b/rpc/http.go
index 8b45319ff..8dcd55ad1 100644
--- a/rpc/http.go
+++ b/rpc/http.go
@@ -34,15 +34,7 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 		switch reqerr.(type) {
 		case nil:
 			break
-		case *DecodeParamError:
-			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
-			return
-		case *InsufficientParamsError:
-			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
-			return
-		case *ValidationError:
+		case *DecodeParamError, *InsufficientParamsError, *ValidationError:
 			jsonerr := &RpcErrorObject{-32602, reqerr.Error()}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: nil, Error: jsonerr})
 			return
@@ -61,11 +53,7 @@ func JSONRPC(pipe *xeth.XEth, dataDir string) http.Handler {
 			jsonerr := &RpcErrorObject{-32601, reserr.Error()}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
 			return
-		case *InsufficientParamsError:
-			jsonerr := &RpcErrorObject{-32602, reserr.Error()}
-			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
-			return
-		case *ValidationError:
+		case *DecodeParamError, *InsufficientParamsError, *ValidationError:
 			jsonerr := &RpcErrorObject{-32602, reserr.Error()}
 			json.Send(w, &RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr})
 			return
-- 
cgit v1.2.3


From e3b64d70c212d893c147b8af62abe5c03fb2f492 Mon Sep 17 00:00:00 2001
From: Taylor Gerring <taylor.gerring@gmail.com>
Date: Fri, 13 Mar 2015 10:56:41 -0400
Subject: Rename db_put db_get

---
 rpc/api.go | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

(limited to 'rpc')

diff --git a/rpc/api.go b/rpc/api.go
index 630fb32b5..af9f10530 100644
--- a/rpc/api.go
+++ b/rpc/api.go
@@ -723,18 +723,20 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
 		return p.AllLogs(args, reply)
 	case "eth_getWork", "eth_submitWork":
 		return NewNotImplementedError(req.Method)
-	case "db_put":
+	case "db_putString":
 		args := new(DbArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
 			return err
 		}
 		return p.DbPut(args, reply)
-	case "db_get":
+	case "db_getString":
 		args := new(DbArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
 			return err
 		}
 		return p.DbGet(args, reply)
+	case "db_putHex", "db_getHex":
+		return NewNotImplementedError(req.Method)
 	case "shh_post":
 		args := new(WhisperMessageArgs)
 		if err := json.Unmarshal(req.Params, &args); err != nil {
-- 
cgit v1.2.3