diff --git a/eth/backend.go b/eth/backend.go index 6fd211b35..bb203b4a6 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -131,6 +131,7 @@ type Ethereum struct { Mining bool DataDir string + version string } func New(config *Config) (*Ethereum, error) { @@ -165,6 +166,7 @@ func New(config *Config) (*Ethereum, error) { logger: servlogger, accountManager: config.AccountManager, DataDir: config.DataDir, + version: config.Name, // TODO should separate from Name } eth.chainManager = core.NewChainManager(blockDb, stateDb, eth.EventMux()) @@ -236,6 +238,7 @@ func (s *Ethereum) IsListening() bool { return true } // Alwa func (s *Ethereum) PeerCount() int { return s.net.PeerCount() } func (s *Ethereum) Peers() []*p2p.Peer { return s.net.Peers() } func (s *Ethereum) MaxPeers() int { return s.net.MaxPeers } +func (s *Ethereum) Version() string { return s.version } // Start the ethereum func (s *Ethereum) Start() error { diff --git a/rpc/api.go b/rpc/api.go index b94d2d6dc..af9f10530 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) @@ -477,6 +481,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": @@ -578,7 +586,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 +626,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 +640,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 +654,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 +673,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) @@ -675,10 +683,8 @@ 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": - return errNotImplemented + case "eth_compileSolidity", "eth_compileLLL", "eth_compileSerpent": + return NewNotImplementedError(req.Method) case "eth_newFilter": args := new(FilterOptions) if err := json.Unmarshal(req.Params, &args); err != nil { @@ -690,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 { @@ -715,21 +721,22 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.AllLogs(args, reply) - case "eth_getWork": - case "eth_submitWork": - return errNotImplemented - case "db_put": + case "eth_getWork", "eth_submitWork": + return NewNotImplementedError(req.Method) + 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 { @@ -744,9 +751,8 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.HasWhisperIdentity(args.Identity, reply) - case "shh_newGroup": - case "shh_addToGroup": - return errNotImplemented + case "shh_newGroup", "shh_addToGroup": + return NewNotImplementedError(req.Method) case "shh_newFilter": args := new(WhisperFilterArgs) if err := json.Unmarshal(req.Params, &args); err != nil { @@ -790,7 +796,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..b935c5007 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 { @@ -502,17 +503,22 @@ 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 errDecodeArgs + return NewDecodeParamError(err.Error()) } if len(obj) < 1 { - return errDecodeArgs + 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 } @@ -525,11 +531,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 +551,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 +577,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 +590,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..8dcd55ad1 100644 --- a/rpc/http.go +++ b/rpc/http.go @@ -25,22 +25,39 @@ 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, *InsufficientParamsError, *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 *DecodeParamError, *InsufficientParamsError, *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()) } } diff --git a/xeth/xeth.go b/xeth/xeth.go index 3e8c544c6..4e8b479c6 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -39,6 +39,7 @@ type Backend interface { IsMining() bool StartMining() error StopMining() + Version() string } // Frontend should be implemented by users of XEth. Its methods are