From a88f609b8ab1e20eb2564d47605985d6b8f593e8 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 28 Jan 2015 10:22:37 -0600 Subject: Use custom Send methods --- rpc/ws/server.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'rpc') diff --git a/rpc/ws/server.go b/rpc/ws/server.go index 248ebc585..e2b918430 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -14,7 +14,7 @@ You should have received a copy of the GNU General Public License along with go-ethereum. If not, see . */ -package ws +package rpcws import ( "fmt" @@ -30,6 +30,7 @@ import ( ) var wslogger = logger.NewLogger("RPC-WS") +var JSON rpc.JsonWrapper type WebSocketServer struct { eth *eth.Ethereum @@ -98,25 +99,28 @@ func (s *WebSocketServer) apiHandler(api *rpc.EthereumApi) http.Handler { func sockHandler(api *rpc.EthereumApi) websocket.Handler { fn := func(conn *websocket.Conn) { for { - wslogger.Debugln("Handling request") + wslogger.Debugln("Handling connection") var reqParsed rpc.RpcRequest + // reqParsed, reqerr := JSON.ParseRequestBody(conn.Request()) if err := websocket.JSON.Receive(conn, &reqParsed); err != nil { - wslogger.Debugln(rpc.ErrorParseRequest) - websocket.JSON.Send(conn, rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) + // if reqerr != nil { + JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) + // websocket.JSON.Send(conn, rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) continue } var response interface{} reserr := api.GetRequestReply(&reqParsed, &response) if reserr != nil { - wslogger.Errorln(reserr) - websocket.JSON.Send(conn, rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) + // websocket.JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) + JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) continue } wslogger.Debugf("Generated response: %T %s", response, response) - websocket.JSON.Send(conn, rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) + JSON.Send(conn, &rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) + // websocket.JSON.Send(conn, rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) } } return websocket.Handler(fn) -- cgit v1.2.3 From d613bf69bf3fd0cfbe28a2f68c87421f7d5bccf9 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Wed, 11 Feb 2015 11:56:29 +0100 Subject: #295 Allow RPC ID to be string --- rpc/http/server.go | 2 +- rpc/message.go | 6 +++--- rpc/util.go | 2 +- rpc/ws/server.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index a34400a77..10c8fa813 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -102,7 +102,7 @@ func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler { if reserr != nil { rpchttplogger.Warnln(reserr) jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()} - JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: &reqParsed.ID, Error: jsonerr}) + JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr}) return } diff --git a/rpc/message.go b/rpc/message.go index 78dc6e2ff..7983e003d 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -34,20 +34,20 @@ const ( ) type RpcRequest struct { + ID interface{} `json:"id"` JsonRpc string `json:"jsonrpc"` - ID int `json:"id"` Method string `json:"method"` Params []json.RawMessage `json:"params"` } type RpcSuccessResponse struct { - ID int `json:"id"` + ID interface{} `json:"id"` JsonRpc string `json:"jsonrpc"` Result interface{} `json:"result"` } type RpcErrorResponse struct { - ID *int `json:"id"` + ID interface{} `json:"id"` JsonRpc string `json:"jsonrpc"` Error *RpcErrorObject `json:"error"` } diff --git a/rpc/util.go b/rpc/util.go index 509d9a17d..679d83754 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -47,7 +47,6 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) // Convert JSON to native types d := json.NewDecoder(req.Body) - // d.UseNumber() defer req.Body.Close() err := d.Decode(&reqParsed) @@ -55,6 +54,7 @@ func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) rpclogger.Errorln("Error decoding JSON: ", err) return reqParsed, err } + rpclogger.DebugDetailf("Parsed request: %s", reqParsed) return reqParsed, nil diff --git a/rpc/ws/server.go b/rpc/ws/server.go index fe6af042f..100713c10 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -109,7 +109,7 @@ func sockHandler(api *rpc.EthereumApi) websocket.Handler { if reserr != nil { wslogger.Warnln(reserr) jsonerr := &rpc.RpcErrorObject{-32603, reserr.Error()} - JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: &reqParsed.ID, Error: jsonerr}) + JSON.Send(conn, &rpc.RpcErrorResponse{JsonRpc: jsonrpcver, ID: reqParsed.ID, Error: jsonerr}) continue } -- cgit v1.2.3 From 16ae675107c150f3373bc8f6ae0647b27f4f0b4e Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Feb 2015 02:08:08 +0100 Subject: Unmarshal in to pointer to string --- rpc/args.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 84b076d4a..12e3103bc 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -43,7 +43,7 @@ type PushTxArgs struct { func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) { arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { + if err = json.Unmarshal(b, &arg0); err == nil { obj.Tx = arg0 return } @@ -82,7 +82,7 @@ type GetStateArgs struct { func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) { arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { + if err = json.Unmarshal(b, &arg0); err == nil { obj.Address = arg0 return } @@ -114,7 +114,7 @@ type GetTxCountArgs struct { func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { + if err = json.Unmarshal(b, &arg0); err == nil { obj.Address = arg0 return } -- cgit v1.2.3 From 09e53367a24025564686af42c8349d2bd05729c3 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Feb 2015 02:12:14 +0100 Subject: Use a mutex write-lock for a write operation --- rpc/packages.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index ac3127356..ef31ff1e1 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -109,8 +109,8 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error } func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { - self.logMut.RLock() - defer self.logMut.RUnlock() + self.logMut.Lock() + defer self.logMut.Unlock() *reply = toLogs(self.logs[id]) @@ -309,8 +309,8 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e } func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error { - self.messagesMut.RLock() - defer self.messagesMut.RUnlock() + self.messagesMut.Lock() + defer self.messagesMut.Unlock() *reply = self.messages[id] -- cgit v1.2.3 From 7299eb72e0c57d8bf7279cbf2544c266a3fd145b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 15 Feb 2015 02:26:30 +0100 Subject: HTTP RPC only listen on localhost --- rpc/http/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index 10c8fa813..dd6ba68e3 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -30,7 +30,7 @@ var rpchttplogger = logger.NewLogger("RPC-HTTP") var JSON rpc.JsonWrapper func NewRpcHttpServer(pipe *xeth.XEth, port int) (*RpcHttpServer, error) { - sport := fmt.Sprintf(":%d", port) + sport := fmt.Sprintf("127.0.0.1:%d", port) l, err := net.Listen("tcp", sport) if err != nil { return nil, err -- cgit v1.2.3 From bb346a3ae1b6c250fdcb28b97280d3512a7fe219 Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Tue, 17 Feb 2015 12:37:09 +0100 Subject: rpc/ws: switch to golang.org/x/net code.google.com/p/go.net is deprecated and will cause problems in future versions of Go. --- rpc/ws/server.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/ws/server.go b/rpc/ws/server.go index 100713c10..b8cc2fa6b 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -21,10 +21,10 @@ import ( "net" "net/http" - "code.google.com/p/go.net/websocket" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/rpc" "github.com/ethereum/go-ethereum/xeth" + "golang.org/x/net/websocket" ) var wslogger = logger.NewLogger("RPC-WS") -- cgit v1.2.3 From 547788b1b0c6a27c24ba3bc4362aa93143dfea2c Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Feb 2015 14:19:05 +0100 Subject: Added optional address slice. Closes #326 --- rpc/args.go | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 12e3103bc..9c2c7d7a6 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1,6 +1,7 @@ package rpc import "encoding/json" + import "github.com/ethereum/go-ethereum/core" type GetBlockArgs struct { @@ -203,7 +204,7 @@ func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { type FilterOptions struct { Earliest int64 Latest int64 - Address string + Address interface{} Topic []string Skip int Max int @@ -211,9 +212,22 @@ type FilterOptions struct { func toFilterOptions(options *FilterOptions) core.FilterOptions { var opts core.FilterOptions + + // Convert optional address slice/string to byte slice + if str, ok := options.Address.(string); ok { + opts.Address = [][]byte{fromHex(str)} + } else if slice, ok := options.Address.([]interface{}); ok { + bslice := make([][]byte, len(slice)) + for i, addr := range slice { + if saddr, ok := addr.(string); ok { + bslice[i] = fromHex(saddr) + } + } + opts.Address = bslice + } + opts.Earliest = options.Earliest opts.Latest = options.Latest - opts.Address = fromHex(options.Address) opts.Topics = make([][]byte, len(options.Topic)) for i, topic := range options.Topic { opts.Topics[i] = fromHex(topic) -- cgit v1.2.3 From 13c00afc68652d517f91313bb8c3eeb206d23f22 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Feb 2015 16:54:52 +0100 Subject: Implement register and watchTx --- rpc/message.go | 28 +++++++++++++++++++++++++++ rpc/packages.go | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 86 insertions(+), 2 deletions(-) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index 7983e003d..b5b852f54 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -342,3 +342,31 @@ func (req *RpcRequest) ToWhisperHasIdentityArgs() (string, error) { rpclogger.DebugDetailf("%T %v", args, args) return args, nil } + +func (req *RpcRequest) ToRegisterArgs() (string, error) { + if len(req.Params) < 1 { + return "", NewErrorResponse(ErrorArguments) + } + + var args string + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return "", err + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToWatchTxArgs() (string, error) { + if len(req.Params) < 1 { + return "", NewErrorResponse(ErrorArguments) + } + + var args string + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return "", err + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} diff --git a/rpc/packages.go b/rpc/packages.go index ef31ff1e1..0b73d48a7 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -55,6 +55,9 @@ type EthereumApi struct { messagesMut sync.RWMutex messages map[int][]xeth.WhisperMessage + // Register keeps a list of accounts and transaction data + regmut sync.Mutex + register map[string][]*NewTxArgs db ethutil.Database } @@ -73,6 +76,36 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { return api } +func (self *EthereumApi) Register(args string, reply *interface{}) error { + self.regmut.Lock() + defer self.regmut.Unlock() + + if _, ok := self.register[args]; ok { + self.register[args] = nil // register with empty + } + return nil +} + +func (self *EthereumApi) Unregister(args string, reply *interface{}) error { + self.regmut.Lock() + defer self.regmut.Unlock() + + delete(self.register, args) + + return nil +} + +func (self *EthereumApi) WatchTx(args string, reply *interface{}) error { + self.regmut.Lock() + defer self.regmut.Unlock() + + txs := self.register[args] + self.register[args] = nil + + *reply = txs + return nil +} + func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error { var id int filter := core.NewFilter(self.xeth.Backend()) @@ -149,8 +182,13 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { args.GasPrice = defaultGasPrice } - result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) - *reply = result + // TODO if no_private_key then + if _, exists := p.register[args.From]; exists { + p.register[args.From] = append(p.register[args.From], args) + } else { + result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + *reply = result + } return nil } @@ -424,6 +462,24 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error case "eth_gasPrice": *reply = defaultGasPrice return nil + case "eth_register": + args, err := req.ToRegisterArgs() + if err != nil { + return err + } + return p.Register(args, reply) + case "eth_unregister": + args, err := req.ToRegisterArgs() + if err != nil { + return err + } + return p.Unregister(args, reply) + case "eth_watchTx": + args, err := req.ToWatchTxArgs() + if err != nil { + return err + } + return p.WatchTx(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From 7fc9b5b3f9ca0111cc4bc1b2a6b4bb2eccd3e048 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Feb 2015 22:20:47 +0100 Subject: Changed to ChainEvent and fixed a nil pointer in transact --- rpc/args.go | 29 +++++++++++++++++++++++++++++ rpc/packages.go | 6 ++++++ 2 files changed, 35 insertions(+) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 9c2c7d7a6..429b385d5 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -38,6 +38,35 @@ type NewTxArgs struct { Data string `json:"data"` } +func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { + // Data can be either specified as "data" or "code" :-/ + var ext struct { + From string + To string + Value string + Gas string + GasPrice string + Data string + Code string + } + + if err = json.Unmarshal(b, &ext); err == nil { + if len(ext.Data) == 0 { + ext.Data = ext.Code + } + obj.From = ext.From + obj.To = ext.To + obj.Value = ext.Value + obj.Gas = ext.Gas + obj.GasPrice = ext.GasPrice + obj.Data = ext.Data + + return + } + + return NewErrorResponse(ErrorDecodeArgs) +} + type PushTxArgs struct { Tx string `json:"tx"` } diff --git a/rpc/packages.go b/rpc/packages.go index 0b73d48a7..4d2194571 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -127,6 +127,9 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error filter := core.NewFilter(self.xeth.Backend()) callback := func(block *types.Block) { + self.logMut.Lock() + defer self.logMut.Unlock() + self.logs[id] = append(self.logs[id], &state.StateLog{}) } if args == "pending" { @@ -153,6 +156,9 @@ func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { } func (self *EthereumApi) Logs(id int, reply *interface{}) error { + self.logMut.Lock() + defer self.logMut.Unlock() + filter := self.filterManager.GetFilter(id) *reply = toLogs(filter.Find()) -- cgit v1.2.3 From 26d58e0446521f725616b5a5d1b9d1ac04837f00 Mon Sep 17 00:00:00 2001 From: obscuren Date: Tue, 17 Feb 2015 22:46:30 +0100 Subject: Forgot to add the case for logs. Closes #336 --- rpc/packages.go | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 4d2194571..8aa604aa5 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -1,21 +1,4 @@ /* - This file is part of go-ethereum - - go-ethereum is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - go-ethereum 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 General Public License for more details. - - You should have received a copy of the GNU General Public License - along with go-ethereum. If not, see . -*/ -/* - For each request type, define the following: 1. RpcRequest "To" method [message.go], which does basic validation and conversion to "Args" type via json.Decoder() @@ -160,7 +143,9 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error { defer self.logMut.Unlock() filter := self.filterManager.GetFilter(id) - *reply = toLogs(filter.Find()) + if filter != nil { + *reply = toLogs(filter.Find()) + } return nil } @@ -465,6 +450,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.FilterChanged(args, reply) + case "eth_filterLogs": + args, err := req.ToFilterChangedArgs() + if err != nil { + return err + } + return p.Logs(args, reply) case "eth_gasPrice": *reply = defaultGasPrice return nil -- cgit v1.2.3 From 03b8c6841be08f19db0f98cea6d0a6f4fd64736f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 11:49:58 +0100 Subject: Topics => Topic. Closes #343 --- rpc/args.go | 2 +- rpc/message.go | 17 +---------------- rpc/packages.go | 10 +++++----- 3 files changed, 7 insertions(+), 22 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 429b385d5..f730819fd 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -289,7 +289,7 @@ type WhisperMessageArgs struct { Payload string To string From string - Topics []string + Topic []string Priority uint32 Ttl uint32 } diff --git a/rpc/message.go b/rpc/message.go index b5b852f54..d96c35d7e 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -231,21 +231,6 @@ func (req *RpcRequest) ToFilterStringArgs() (string, error) { return args, nil } -func (req *RpcRequest) ToFilterChangedArgs() (int, error) { - if len(req.Params) < 1 { - return 0, NewErrorResponse(ErrorArguments) - } - - var id int - r := bytes.NewReader(req.Params[0]) - err := json.NewDecoder(r).Decode(&id) - if err != nil { - return 0, NewErrorResponse(ErrorDecodeArgs) - } - rpclogger.DebugDetailf("%T %v", id, id) - return id, nil -} - func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) { if len(req.Params) < 3 { return nil, NewErrorResponse(ErrorArguments) @@ -301,7 +286,7 @@ func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) { return &args, nil } -func (req *RpcRequest) ToWhisperIdArgs() (int, error) { +func (req *RpcRequest) ToIdArgs() (int, error) { if len(req.Params) < 1 { return 0, NewErrorResponse(ErrorArguments) } diff --git a/rpc/packages.go b/rpc/packages.go index 8aa604aa5..7044d9d12 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -349,7 +349,7 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error { } func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) error { - err := p.xeth.Whisper().Post(args.Payload, args.To, args.From, args.Topics, args.Priority, args.Ttl) + err := p.xeth.Whisper().Post(args.Payload, args.To, args.From, args.Topic, args.Priority, args.Ttl) if err != nil { return err } @@ -445,13 +445,13 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.NewFilterString(args, reply) case "eth_changed": - args, err := req.ToFilterChangedArgs() + args, err := req.ToIdArgs() if err != nil { return err } return p.FilterChanged(args, reply) case "eth_filterLogs": - args, err := req.ToFilterChangedArgs() + args, err := req.ToIdArgs() if err != nil { return err } @@ -504,7 +504,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.NewWhisperFilter(args, reply) case "shh_changed": - args, err := req.ToWhisperIdArgs() + args, err := req.ToIdArgs() if err != nil { return err } @@ -522,7 +522,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.HasWhisperIdentity(args, reply) case "shh_getMessages": - args, err := req.ToWhisperIdArgs() + args, err := req.ToIdArgs() if err != nil { return err } -- cgit v1.2.3 From 0057bb4ef6d55b5d580a4e0421526a477ef93de9 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 11:51:38 +0100 Subject: WIP QT Clipboard --- rpc/util.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'rpc') diff --git a/rpc/util.go b/rpc/util.go index 679d83754..366e315ac 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -80,7 +80,7 @@ type RpcServer interface { type Log struct { Address string `json:"address"` - Topics []string `json:"topics"` + Topic []string `json:"topics"` Data string `json:"data"` } @@ -89,11 +89,11 @@ func toLogs(logs state.Logs) (ls []Log) { for i, log := range logs { var l Log - l.Topics = make([]string, len(log.Topics())) + l.Topic = make([]string, len(log.Topics())) l.Address = toHex(log.Address()) l.Data = toHex(log.Data()) for j, topic := range log.Topics() { - l.Topics[j] = toHex(topic) + l.Topic[j] = toHex(topic) } ls[i] = l } -- cgit v1.2.3 From dba4f3122e83a66edc1fa089c5d69f789b07a6b3 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 13:21:37 +0100 Subject: Added uninstall filter methods --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 13 +++++++++++++ 2 files changed, 28 insertions(+) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index b5b852f54..524d7fc84 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -231,6 +231,21 @@ func (req *RpcRequest) ToFilterStringArgs() (string, error) { return args, nil } +func (req *RpcRequest) ToUninstallFilterArgs() (int, error) { + if len(req.Params) < 1 { + return 0, NewErrorResponse(ErrorArguments) + } + + var args int + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return 0, NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToFilterChangedArgs() (int, error) { if len(req.Params) < 1 { return 0, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 8aa604aa5..216321dba 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -105,6 +105,13 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro return nil } +func (self *EthereumApi) UninstallFilter(id int, reply *interface{}) error { + delete(self.logs, id) + self.filterManager.UninstallFilter(id) + *reply = true + return nil +} + func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error { var id int filter := core.NewFilter(self.xeth.Backend()) @@ -444,6 +451,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.NewFilterString(args, reply) + case "eth_uninstallFilter": + args, err := req.ToUninstallFilterArgs() + if err != nil { + return err + } + return p.UninstallFilter(args, reply) case "eth_changed": args, err := req.ToFilterChangedArgs() if err != nil { -- cgit v1.2.3 From 605dd3a9820bb74be883afe3cb0e462aca40b32d Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 18:41:50 +0100 Subject: Add serpent compilation to RPC --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index 524d7fc84..1935bf1e2 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -201,6 +201,21 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { return args, nil } +func (req *RpcRequest) ToCompileArgs() (string, error) { + if len(req.Params) < 1 { + return "", NewErrorResponse(ErrorArguments) + } + + var args string + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return "", NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 216321dba..c969f58cc 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -300,6 +300,21 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) GetCompilers(reply *interface{}) error { + c := []string{"serpent"} + *reply = c + return nil +} + +func (p *EthereumApi) CompileSerpent(script string, reply *interface{}) error { + res, err := ethutil.Compile(script, false) + if err != nil { + return err + } + *reply = res + return nil +} + func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { *reply = toHex(crypto.Sha3(fromHex(args.Data))) return nil @@ -490,6 +505,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.WatchTx(args, reply) + case "eth_compilers": + return p.GetCompilers(reply) + case "eth_serpent": + args, err := req.ToCompileArgs() + if err != nil { + return err + } + return p.CompileSerpent(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From a59cd94625f589bb167be7a9c4588ff959dcfc00 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 19 Feb 2015 18:58:15 +0100 Subject: Add setMining RPC method --- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 11 +++++++++++ 2 files changed, 26 insertions(+) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index 1935bf1e2..d02acef0e 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -201,6 +201,21 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { return args, nil } +func (req *RpcRequest) ToBoolArgs() (bool, error) { + if len(req.Params) < 1 { + return false, NewErrorResponse(ErrorArguments) + } + + var args bool + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return false, NewErrorResponse(ErrorDecodeArgs) + } + + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToCompileArgs() (string, error) { if len(req.Params) < 1 { return "", NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index c969f58cc..d82538c92 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -267,6 +267,11 @@ func (p *EthereumApi) GetIsMining(reply *interface{}) error { return nil } +func (p *EthereumApi) SetMining(shouldmine bool, reply *interface{}) error { + *reply = p.xeth.SetMining(shouldmine) + return nil +} + func (p *EthereumApi) BlockNumber(reply *interface{}) error { *reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() return nil @@ -400,6 +405,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return p.GetIsListening(reply) case "eth_mining": return p.GetIsMining(reply) + case "eth_setMining": + args, err := req.ToBoolArgs() + if err != nil { + return err + } + return p.SetMining(args, reply) case "eth_peerCount": return p.GetPeerCount(reply) case "eth_number": -- cgit v1.2.3 From fa4cbad315609e41d88c59ecbce7c6c6169fc57a Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 19 Feb 2015 22:33:22 +0100 Subject: Optimisations and fixed a couple of DDOS issues in the miner --- rpc/packages.go | 1 + 1 file changed, 1 insertion(+) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 7044d9d12..63eea54d6 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -180,6 +180,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) *reply = result } + return nil } -- cgit v1.2.3 From 982f73fa6d6f12874729faacd0db14fc78d518dd Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 12:59:54 +0100 Subject: Added timeout for filter & removed clipboard. Closes #350 --- rpc/packages.go | 72 ++++++++++++++++++++++++++++++++++++++++++---------- rpc/packages_test.go | 37 +++++++++++++++++++++++++++ rpc/util.go | 33 ++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 13 deletions(-) create mode 100644 rpc/packages_test.go (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 63eea54d6..7411392c2 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -13,6 +13,7 @@ import ( "math/big" "strings" "sync" + "time" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/types" @@ -31,13 +32,14 @@ const ( type EthereumApi struct { xeth *xeth.XEth + quit chan struct{} filterManager *filter.FilterManager logMut sync.RWMutex - logs map[int]state.Logs + logs map[int]*logFilter messagesMut sync.RWMutex - messages map[int][]xeth.WhisperMessage + messages map[int]*whisperFilter // Register keeps a list of accounts and transaction data regmut sync.Mutex register map[string][]*NewTxArgs @@ -49,12 +51,14 @@ func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ xeth: eth, + quit: make(chan struct{}), filterManager: filter.NewFilterManager(eth.Backend().EventMux()), - logs: make(map[int]state.Logs), - messages: make(map[int][]xeth.WhisperMessage), + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), db: db, } go api.filterManager.Start() + go api.start() return api } @@ -97,7 +101,11 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro self.logMut.Lock() defer self.logMut.Unlock() - self.logs[id] = append(self.logs[id], logs...) + if self.logs[id] == nil { + self.logs[id] = &logFilter{timeout: time.Now()} + } + + self.logs[id].add(logs...) } id = self.filterManager.InstallFilter(filter) *reply = id @@ -113,7 +121,11 @@ func (self *EthereumApi) NewFilterString(args string, reply *interface{}) error self.logMut.Lock() defer self.logMut.Unlock() - self.logs[id] = append(self.logs[id], &state.StateLog{}) + if self.logs[id] == nil { + self.logs[id] = &logFilter{timeout: time.Now()} + } + + self.logs[id].add(&state.StateLog{}) } if args == "pending" { filter.PendingCallback = callback @@ -131,9 +143,9 @@ func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { self.logMut.Lock() defer self.logMut.Unlock() - *reply = toLogs(self.logs[id]) - - self.logs[id] = nil // empty the logs + if self.logs[id] != nil { + *reply = toLogs(self.logs[id].get()) + } return nil } @@ -331,7 +343,10 @@ func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) e args.Fn = func(msg xeth.WhisperMessage) { p.messagesMut.Lock() defer p.messagesMut.Unlock() - p.messages[id] = append(p.messages[id], msg) + if p.messages[id] == nil { + p.messages[id] = &whisperFilter{timeout: time.Now()} + } + p.messages[id].add(msg) // = append(p.messages[id], msg) } id = p.xeth.Whisper().Watch(args) *reply = id @@ -342,9 +357,9 @@ func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error { self.messagesMut.Lock() defer self.messagesMut.Unlock() - *reply = self.messages[id] - - self.messages[id] = nil // empty the messages + if self.messages[id] != nil { + *reply = self.messages[id].get() + } return nil } @@ -535,3 +550,34 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error rpclogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } + +var filterTickerTime = 15 * time.Second + +func (self *EthereumApi) start() { + timer := time.NewTicker(filterTickerTime) +done: + for { + select { + case <-timer.C: + self.logMut.Lock() + self.messagesMut.Lock() + for id, filter := range self.logs { + if time.Since(filter.timeout) > 20*time.Second { + delete(self.logs, id) + } + } + + for id, filter := range self.messages { + if time.Since(filter.timeout) > 20*time.Second { + delete(self.messages, id) + } + } + case <-self.quit: + break done + } + } +} + +func (self *EthereumApi) stop() { + close(self.quit) +} diff --git a/rpc/packages_test.go b/rpc/packages_test.go new file mode 100644 index 000000000..037fd78b3 --- /dev/null +++ b/rpc/packages_test.go @@ -0,0 +1,37 @@ +package rpc + +import ( + "sync" + "testing" + "time" +) + +func TestFilterClose(t *testing.T) { + api := &EthereumApi{ + logs: make(map[int]*logFilter), + messages: make(map[int]*whisperFilter), + quit: make(chan struct{}), + } + + filterTickerTime = 1 + api.logs[0] = &logFilter{} + api.messages[0] = &whisperFilter{} + var wg sync.WaitGroup + wg.Add(1) + go api.start() + go func() { + select { + case <-time.After(500 * time.Millisecond): + api.stop() + wg.Done() + } + }() + wg.Wait() + if len(api.logs) != 0 { + t.Error("expected logs to be empty") + } + + if len(api.messages) != 0 { + t.Error("expected messages to be empty") + } +} diff --git a/rpc/util.go b/rpc/util.go index 366e315ac..29824bcdb 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -20,10 +20,12 @@ import ( "encoding/json" "io" "net/http" + "time" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/state" + "github.com/ethereum/go-ethereum/xeth" ) var rpclogger = logger.NewLogger("RPC") @@ -100,3 +102,34 @@ func toLogs(logs state.Logs) (ls []Log) { return } + +type whisperFilter struct { + messages []xeth.WhisperMessage + timeout time.Time +} + +func (w *whisperFilter) add(msgs ...xeth.WhisperMessage) { + w.messages = append(w.messages, msgs...) +} +func (w *whisperFilter) get() []xeth.WhisperMessage { + w.timeout = time.Now() + tmp := w.messages + w.messages = nil + return tmp +} + +type logFilter struct { + logs state.Logs + timeout time.Time +} + +func (l *logFilter) add(logs ...state.Log) { + l.logs = append(l.logs, logs...) +} + +func (l *logFilter) get() state.Logs { + l.timeout = time.Now() + tmp := l.logs + l.logs = nil + return tmp +} -- cgit v1.2.3 From 66d5559866f37a79a7b5aeccd03dfe1b4401542b Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 20 Feb 2015 16:59:08 +0100 Subject: Fixed chain event issue --- rpc/packages.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 56c1751d7..72e090130 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -101,13 +101,11 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro self.logMut.Lock() defer self.logMut.Unlock() - if self.logs[id] == nil { - self.logs[id] = &logFilter{timeout: time.Now()} - } - self.logs[id].add(logs...) } id = self.filterManager.InstallFilter(filter) + self.logs[id] = &logFilter{timeout: time.Now()} + *reply = id return nil -- cgit v1.2.3 From cb7cd0391992e1800e25e1dc049c5d64a5432fe4 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sat, 21 Feb 2015 00:53:27 +0100 Subject: unlock mutex --- rpc/packages.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 72e090130..aed43cae2 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -617,6 +617,8 @@ done: delete(self.messages, id) } } + self.logMut.Unlock() + self.messagesMut.Unlock() case <-self.quit: break done } -- cgit v1.2.3 From 483d96a89d68023360d211ab329400f4b960fe48 Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:12:01 +0100 Subject: Added eth_logs & fixed issue with manual log filtering * Implemented `eth_logs` * Fixed issue with `filter.Find()` where logs were appended to an incorrect, non-returned slice resulting in no logs found --- rpc/packages.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index aed43cae2..b51bde7ce 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -167,6 +167,15 @@ func (self *EthereumApi) Logs(id int, reply *interface{}) error { return nil } +func (self *EthereumApi) AllLogs(args *FilterOptions, reply *interface{}) error { + filter := core.NewFilter(self.xeth.Backend()) + filter.SetOptions(toFilterOptions(args)) + + *reply = toLogs(filter.Find()) + + return nil +} + func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { err := args.requirements() if err != nil { @@ -509,6 +518,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.Logs(args, reply) + case "eth_logs": + args, err := req.ToFilterArgs() + if err != nil { + return err + } + return p.AllLogs(args, reply) case "eth_gasPrice": *reply = defaultGasPrice return nil -- cgit v1.2.3 From bba85a207488d27819dc6f6f5758b80947ea200b Mon Sep 17 00:00:00 2001 From: obscuren Date: Sun, 22 Feb 2015 13:24:26 +0100 Subject: Added Number to logs --- rpc/util.go | 2 ++ 1 file changed, 2 insertions(+) (limited to 'rpc') diff --git a/rpc/util.go b/rpc/util.go index 29824bcdb..1939b3474 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -84,6 +84,7 @@ type Log struct { Address string `json:"address"` Topic []string `json:"topics"` Data string `json:"data"` + Number uint64 `json:"number"` } func toLogs(logs state.Logs) (ls []Log) { @@ -94,6 +95,7 @@ func toLogs(logs state.Logs) (ls []Log) { l.Topic = make([]string, len(log.Topics())) l.Address = toHex(log.Address()) l.Data = toHex(log.Data()) + l.Number = log.Number() for j, topic := range log.Topics() { l.Topic[j] = toHex(topic) } -- cgit v1.2.3