From 32bed50ba107ff69ff489e4df6f935fd404a5caa Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Mon, 12 Jan 2015 23:25:29 -0600 Subject: begin conversion to rpc over http Per specification at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC --- rpc/json.go | 67 +++++++++++ rpc/message.go | 171 ++++++++++++++++++++++++++-- rpc/packages.go | 343 +++++++++++++++++++++++++++++--------------------------- rpc/server.go | 45 ++++++-- rpc/writer.go | 75 ------------- 5 files changed, 438 insertions(+), 263 deletions(-) delete mode 100644 rpc/writer.go (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go index e467f9a34..85b198d12 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -3,6 +3,7 @@ package rpc import ( "encoding/json" "io" + "net/http" ) type jsonWrapper struct{} @@ -11,10 +12,76 @@ func (self jsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) var payload []byte payload, err = json.Marshal(v) if err != nil { + jsonlogger.Fatalln("Error marshalling JSON", err) return 0, err } + jsonlogger.Infof("Sending payload: %s", payload) return writer.Write(payload) } +func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { + var reqParsed RpcRequest + + // Convert JSON to native types + d := json.NewDecoder(req.Body) + // d.UseNumber() + defer req.Body.Close() + err := d.Decode(&reqParsed) + + if err != nil { + jsonlogger.Errorln("Error decoding JSON: ", err) + return reqParsed, err + } + jsonlogger.DebugDetailf("Parsed request: %s", reqParsed) + + return reqParsed, nil +} + +func (self jsonWrapper) GetRequestReply(xeth *EthereumApi, req *RpcRequest, reply *interface{}) error { + // call function for request method + jsonlogger.DebugDetailf("%T %s", req.Params, req.Params) + switch req.Method { + case "eth_coinbase": + return xeth.GetCoinbase(reply) + case "eth_listening": + return xeth.GetIsListening(reply) + case "eth_mining": + return xeth.GetIsMining(reply) + case "eth_peerCount": + return xeth.GetPeerCount(reply) + case "eth_countAt": + args, err := req.ToGetTxCountArgs() + if err != nil { + return err + } + return xeth.GetTxCountAt(args, reply) + // case "eth_codeAt": + // return nil + case "eth_balanceAt": + args, err := req.ToGetBalanceArgs() + if err != nil { + return err + } + return xeth.GetBalanceAt(args, reply) + case "eth_stateAt": + args, err := req.ToGetStorageArgs() + if err != nil { + return err + } + return xeth.GetStorageAt(args, reply) + case "eth_blockByNumber", "eth_blockByHash": + args, err := req.ToGetBlockArgs() + if err != nil { + return err + } + return xeth.GetBlock(args, reply) + default: + return NewErrorResponse(ErrorNotImplemented) + } + + jsonlogger.DebugDetailf("Reply: %T %s", reply, reply) + return nil +} + var JSON jsonWrapper diff --git a/rpc/message.go b/rpc/message.go index c8103eded..f520548c9 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -1,14 +1,169 @@ package rpc -import "github.com/ethereum/go-ethereum/ethutil" +import ( + "bytes" + "encoding/json" + "errors" -type Message struct { - Call string `json:"call"` - Args []interface{} `json:"args"` - Id int `json:"_id"` - Data interface{} `json:"data"` + // "github.com/ethereum/go-ethereum/ethutil" +) + +const ( + ErrorArguments = "Error: Insufficient arguments" + ErrorNotImplemented = "Error: Method not implemented" + ErrorUnknown = "Error: Unknown error" + ErrorParseRequest = "Error: Could not parse request" + ErrorDecodeArgs = "Error: Could not decode arguments" +) + +// type JsonResponse interface { +// } + +type ErrorResponse struct { + Error bool `json:"error"` + ErrorText string `json:"errorText"` +} + +// type SuccessRes struct { +// Error bool `json:"error"` +// Result JsonResponse `json:"result"` +// } + +// type Message struct { +// Call string `json:"call"` +// Args []interface{} `json:"args"` +// Id int `json:"_id"` +// Data interface{} `json:"data"` +// } + +// func (self *Message) Arguments() *ethutil.Value { +// return ethutil.NewValue(self.Args) +// } + +type RpcSuccessResponse struct { + ID int `json:"id"` + JsonRpc string `json:"jsonrpc"` + Error bool `json:"error"` + Result interface{} `json:"result"` } -func (self *Message) Arguments() *ethutil.Value { - return ethutil.NewValue(self.Args) +type RpcErrorResponse struct { + ID int `json:"id"` + JsonRpc string `json:"jsonrpc"` + Error bool `json:"error"` + ErrorText string `json:"errortext"` +} + +type RpcRequest struct { + JsonRpc string `json:"jsonrpc"` + ID int `json:"id"` + Method string `json:"method"` + Params []json.RawMessage `json:"params"` +} + +func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetBlockArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { + if len(req.Params) < 7 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(NewTxArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(PushTxArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) { + if len(req.Params) < 2 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetStorageArgs) + // TODO need to pass both arguments + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetTxCountArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetBalanceArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + +// func NewSuccessRes(object JsonResponse) string { +// e := SuccessRes{Error: false, Result: object} +// res, err := json.Marshal(e) +// if err != nil { +// // This should never happen +// panic("Creating json error response failed, help") +// } +// success := string(res) +// return success +// // return res +// } + +func NewErrorResponse(msg string) error { + return errors.New(msg) } diff --git a/rpc/packages.go b/rpc/packages.go index 5535e6e79..06f00678c 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -1,11 +1,12 @@ package rpc import ( + // "bytes" "encoding/json" - "errors" "math/big" "strings" + // "errors" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/xeth" ) @@ -14,84 +15,169 @@ type EthereumApi struct { pipe *xeth.JSXEth } -type JsonArgs interface { - requirements() error -} +func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } -type BlockResponse struct { - JsonResponse -} -type GetBlockArgs struct { - BlockNumber int - Hash string + // var block xeth.JSBlock + if args.BlockNumber > 0 { + // block := p.pipe.BlockByNumber(int32(args.BlockNumber)) + *reply = p.pipe.BlockByNumber(args.BlockNumber) + } else { + // block := p.pipe.BlockByHash(args.Hash) + *reply = p.pipe.BlockByHash(args.Hash) + } + return nil } -type ErrorResponse struct { - Error bool `json:"error"` - ErrorText string `json:"errorText"` +func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } + result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + *reply = result + return nil } -type JsonResponse interface { -} +func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { + err := args.requirementsContract() + if err != nil { + return err + } -type SuccessRes struct { - Error bool `json:"error"` - Result JsonResponse `json:"result"` + result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) + *reply = result + return nil } -func NewSuccessRes(object JsonResponse) string { - e := SuccessRes{Error: false, Result: object} - res, err := json.Marshal(e) +func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { + err := args.requirementsPushTx() if err != nil { - // This should never happen - panic("Creating json error response failed, help") + return err } - success := string(res) - return success + result, _ := p.pipe.PushTx(args.Tx) + *reply = result + return nil } -func NewErrorResponse(msg string) error { - e := ErrorResponse{Error: true, ErrorText: msg} - res, err := json.Marshal(e) +func (p *EthereumApi) GetKey(args interface{}, reply *interface{}) error { + *reply = p.pipe.Key() + return nil +} + +func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error { + err := args.requirements() if err != nil { - // This should never happen - panic("Creating json error response failed, help") + return err } - newErr := errors.New(string(res)) - return newErr + + state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) + + var hx string + if strings.Index(args.Key, "0x") == 0 { + hx = string([]byte(args.Key)[2:]) + } else { + // Convert the incoming string (which is a bigint) into hex + i, _ := new(big.Int).SetString(args.Key, 10) + hx = ethutil.Bytes2Hex(i.Bytes()) + } + jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) + value := state.Storage(ethutil.Hex2Bytes(hx)) + *reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()} + return nil } -func (b *GetBlockArgs) requirements() error { - if b.BlockNumber == 0 && b.Hash == "" { - return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") +func (p *EthereumApi) GetPeerCount(reply *interface{}) error { + *reply = p.pipe.PeerCount() + return nil +} + +func (p *EthereumApi) GetIsListening(reply *interface{}) error { + *reply = p.pipe.IsListening() + // *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.IsListening()}) + return nil +} + +func (p *EthereumApi) GetCoinbase(reply *interface{}) error { + *reply = p.pipe.CoinBase() + // *reply = p.pipe.CoinBase() + return nil +} + +func (p *EthereumApi) GetIsMining(reply *interface{}) error { + *reply = p.pipe.IsMining() + return nil +} + +func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err } + *reply = p.pipe.TxCountAt(args.Address) return nil } -func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *string) error { +func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) error { err := args.requirements() if err != nil { return err } + state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) + *reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address} + return nil +} + +// type JsonArgs interface { +// requirements() error +// } + +// type BlockResponse struct { +// JsonResponse +// } + +type GetBlockArgs struct { + BlockNumber int32 + Hash string +} + +func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { + argint, argstr := int32(0), "" + if err = json.Unmarshal(b, &argint); err == nil { + obj.BlockNumber = argint + return + } + if err = json.Unmarshal(b, &argstr); err == nil { + obj.Hash = argstr + return + } + return NewErrorResponse("Could not determine JSON parameters") +} - block := p.pipe.BlockByHash(args.Hash) - *reply = NewSuccessRes(block) +func (obj *GetBlockArgs) requirements() error { + if obj.BlockNumber == 0 && obj.Hash == "" { + return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") + } return nil } type NewTxArgs struct { - Sec string - Recipient string - Value string - Gas string - GasPrice string - Init string - Body string -} -type TxResponse struct { - Hash string + Sec string `json:"sec"` + Recipient string `json:"recipient"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasprice"` + Init string `json:"init"` + Body string `json:"body"` } +// type TxResponse struct { +// Hash string +// } + func (a *NewTxArgs) requirements() error { if a.Recipient == "" { return NewErrorResponse("Transact requires a 'recipient' address as argument") @@ -124,29 +210,8 @@ func (a *NewTxArgs) requirementsContract() error { return nil } -func (p *EthereumApi) Transact(args *NewTxArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) - *reply = NewSuccessRes(result) - return nil -} - -func (p *EthereumApi) Create(args *NewTxArgs, reply *string) error { - err := args.requirementsContract() - if err != nil { - return err - } - - result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) - *reply = NewSuccessRes(result) - return nil -} - type PushTxArgs struct { - Tx string + Tx string `json:"tx"` } func (a *PushTxArgs) requirementsPushTx() error { @@ -156,21 +221,6 @@ func (a *PushTxArgs) requirementsPushTx() error { return nil } -func (p *EthereumApi) PushTx(args *PushTxArgs, reply *string) error { - err := args.requirementsPushTx() - if err != nil { - return err - } - result, _ := p.pipe.PushTx(args.Tx) - *reply = NewSuccessRes(result) - return nil -} - -func (p *EthereumApi) GetKey(args interface{}, reply *string) error { - *reply = NewSuccessRes(p.pipe.Key()) - return nil -} - type GetStorageArgs struct { Address string Key string @@ -192,33 +242,21 @@ type GetStorageAtRes struct { Address string `json:"address"` } -func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - - state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) - - var hx string - if strings.Index(args.Key, "0x") == 0 { - hx = string([]byte(args.Key)[2:]) - } else { - // Convert the incoming string (which is a bigint) into hex - i, _ := new(big.Int).SetString(args.Key, 10) - hx = ethutil.Bytes2Hex(i.Bytes()) - } - jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) - value := state.Storage(ethutil.Hex2Bytes(hx)) - *reply = NewSuccessRes(GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()}) - return nil -} - type GetTxCountArgs struct { Address string `json:"address"` } -type GetTxCountRes struct { - Nonce int `json:"nonce"` + +// type GetTxCountRes struct { +// Nonce int `json:"nonce"` +// } + +func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse("Could not determine JSON parameters") } func (a *GetTxCountArgs) requirements() error { @@ -228,54 +266,33 @@ func (a *GetTxCountArgs) requirements() error { return nil } -type GetPeerCountRes struct { - PeerCount int `json:"peerCount"` -} +// type GetPeerCountRes struct { +// PeerCount int `json:"peerCount"` +// } -func (p *EthereumApi) GetPeerCount(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetPeerCountRes{PeerCount: p.pipe.PeerCount()}) - return nil -} +// type GetListeningRes struct { +// IsListening bool `json:"isListening"` +// } -type GetListeningRes struct { - IsListening bool `json:"isListening"` -} +// type GetCoinbaseRes struct { +// Coinbase string `json:"coinbase"` +// } -func (p *EthereumApi) GetIsListening(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.IsListening()}) - return nil -} - -type GetCoinbaseRes struct { - Coinbase string `json:"coinbase"` -} - -func (p *EthereumApi) GetCoinbase(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetCoinbaseRes{Coinbase: p.pipe.CoinBase()}) - return nil -} - -type GetMiningRes struct { - IsMining bool `json:"isMining"` -} +// type GetMiningRes struct { +// IsMining bool `json:"isMining"` +// } -func (p *EthereumApi) GetIsMining(args *interface{}, reply *string) error { - *reply = NewSuccessRes(GetMiningRes{IsMining: p.pipe.IsMining()}) - return nil +type GetBalanceArgs struct { + Address string } -func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err +func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, &arg0); err == nil { + obj.Address = arg0 + return } - state := p.pipe.TxCountAt(args.Address) - *reply = NewSuccessRes(GetTxCountRes{Nonce: state}) - return nil -} - -type GetBalanceArgs struct { - Address string + return NewErrorResponse("Could not determine JSON parameters") } func (a *GetBalanceArgs) requirements() error { @@ -290,22 +307,12 @@ type BalanceRes struct { Address string `json:"address"` } -func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *string) error { - err := args.requirements() - if err != nil { - return err - } - state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) - *reply = NewSuccessRes(BalanceRes{Balance: state.Balance().String(), Address: args.Address}) - return nil -} - -type TestRes struct { - JsonResponse `json:"-"` - Answer int `json:"answer"` -} +// type TestRes struct { +// JsonResponse `json:"-"` +// Answer int `json:"answer"` +// } -func (p *EthereumApi) Test(args *GetBlockArgs, reply *string) error { - *reply = NewSuccessRes(TestRes{Answer: 15}) - return nil -} +// func (p *EthereumApi) Test(args *GetBlockArgs, reply *interface{}) error { +// *reply = NewSuccessRes(TestRes{Answer: 15}) +// return nil +// } diff --git a/rpc/server.go b/rpc/server.go index 983dc6c33..39b955dff 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -3,8 +3,7 @@ package rpc import ( "fmt" "net" - "net/rpc" - "net/rpc/jsonrpc" + "net/http" "github.com/ethereum/go-ethereum/logger" "github.com/ethereum/go-ethereum/xeth" @@ -38,17 +37,14 @@ func (s *JsonRpcServer) Stop() { func (s *JsonRpcServer) Start() { jsonlogger.Infoln("Starting JSON-RPC server") go s.exitHandler() - rpc.Register(&EthereumApi{pipe: s.pipe}) - rpc.HandleHTTP() - for { - conn, err := s.listener.Accept() - if err != nil { - jsonlogger.Infoln("Error starting JSON-RPC:", err) - break - } - jsonlogger.Debugln("Incoming request.") - go jsonrpc.ServeConn(conn) + h := apiHandler(&EthereumApi{pipe: s.pipe}) + http.Handle("/", h) + + err := http.Serve(s.listener, nil) + // TODO Complains on shutdown due to listner already being closed + if err != nil { + jsonlogger.Errorln("Error on JSON-RPC interface:", err) } } @@ -65,3 +61,28 @@ func NewJsonRpcServer(pipe *xeth.JSXEth, port int) (*JsonRpcServer, error) { pipe: pipe, }, nil } + +func apiHandler(xeth *EthereumApi) http.Handler { + fn := func(w http.ResponseWriter, req *http.Request) { + jsonlogger.Debugln("Handling request") + + reqParsed, reqerr := JSON.ParseRequestBody(req) + if reqerr != nil { + JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: ErrorParseRequest}) + return + } + + var response interface{} + reserr := JSON.GetRequestReply(xeth, &reqParsed, &response) + if reserr != nil { + jsonlogger.Errorln(reserr) + JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) + return + } + + jsonlogger.Debugf("Generated response: %T %s", response, response) + JSON.Send(w, &RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) + } + + return http.HandlerFunc(fn) +} diff --git a/rpc/writer.go b/rpc/writer.go deleted file mode 100644 index 4cc39f577..000000000 --- a/rpc/writer.go +++ /dev/null @@ -1,75 +0,0 @@ -package rpc - -/* -func pack(id int, v ...interface{}) Message { - return Message{Data: v, Id: id} -} - -func WriteOn(msg *Message, writer io.Writer) { - //msg := &Message{Seed: seed, Data: data} - - switch msg.Call { - case "compile": - data := ethutil.NewValue(msg.Args) - bcode, err := ethutil.Compile(data.Get(0).Str(), false) - if err != nil { - JSON.Send(writer, pack(msg.Id, err.Error())) - } - - code := ethutil.Bytes2Hex(bcode) - - JSON.Send(writer, pack(msg.Id, code, nil)) - case "block": - args := msg.Arguments() - - block := pipe.BlockByNumber(int32(args.Get(0).Uint())) - - JSON.Send(writer, pack(msg.Id, block)) - case "transact": - if mp, ok := msg.Args[0].(map[string]interface{}); ok { - object := mapToTxParams(mp) - JSON.Send( - writer, - pack(msg.Id, args(pipe.Transact(object["from"], object["to"], object["value"], object["gas"], object["gasPrice"], object["data"]))), - ) - - } - case "coinbase": - JSON.Send(writer, pack(msg.Id, pipe.CoinBase(), msg.Seed)) - - case "listening": - JSON.Send(writer, pack(msg.Id, pipe.IsListening())) - - case "mining": - JSON.Send(writer, pack(msg.Id, pipe.IsMining())) - - case "peerCoint": - JSON.Send(writer, pack(msg.Id, pipe.PeerCount())) - - case "countAt": - args := msg.Arguments() - - JSON.Send(writer, pack(msg.Id, pipe.TxCountAt(args.Get(0).Str()))) - - case "codeAt": - args := msg.Arguments() - - JSON.Send(writer, pack(msg.Id, len(pipe.CodeAt(args.Get(0).Str())))) - - case "stateAt": - args := msg.Arguments() - - JSON.Send(writer, pack(msg.Id, pipe.StorageAt(args.Get(0).Str(), args.Get(1).Str()))) - - case "balanceAt": - args := msg.Arguments() - - JSON.Send(writer, pack(msg.Id, pipe.BalanceAt(args.Get(0).Str()))) - - case "newFilter": - case "newFilterString": - case "messages": - // TODO - } -} -*/ -- cgit v1.2.3 From b2112729faa2263fe0dbf6f735339e27608ae614 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Mon, 12 Jan 2015 23:44:56 -0600 Subject: cleanup --- rpc/message.go | 21 --------------------- rpc/packages.go | 34 +++++++++------------------------- 2 files changed, 9 insertions(+), 46 deletions(-) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index f520548c9..8aadfa691 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -4,8 +4,6 @@ import ( "bytes" "encoding/json" "errors" - - // "github.com/ethereum/go-ethereum/ethutil" ) const ( @@ -16,30 +14,11 @@ const ( ErrorDecodeArgs = "Error: Could not decode arguments" ) -// type JsonResponse interface { -// } - type ErrorResponse struct { Error bool `json:"error"` ErrorText string `json:"errorText"` } -// type SuccessRes struct { -// Error bool `json:"error"` -// Result JsonResponse `json:"result"` -// } - -// type Message struct { -// Call string `json:"call"` -// Args []interface{} `json:"args"` -// Id int `json:"_id"` -// Data interface{} `json:"data"` -// } - -// func (self *Message) Arguments() *ethutil.Value { -// return ethutil.NewValue(self.Args) -// } - type RpcSuccessResponse struct { ID int `json:"id"` JsonRpc string `json:"jsonrpc"` diff --git a/rpc/packages.go b/rpc/packages.go index 06f00678c..4414abf19 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -1,12 +1,19 @@ +/* + +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() +2. json.Decoder() calls "UnmarshalJSON" defined on each "Args" struct +3. EthereumApi "Get" method, taking the "Args" type and replying with an interface to be marshalled to JSON + +*/ package rpc import ( - // "bytes" "encoding/json" "math/big" "strings" - // "errors" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/xeth" ) @@ -21,12 +28,9 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { return err } - // var block xeth.JSBlock if args.BlockNumber > 0 { - // block := p.pipe.BlockByNumber(int32(args.BlockNumber)) *reply = p.pipe.BlockByNumber(args.BlockNumber) } else { - // block := p.pipe.BlockByHash(args.Hash) *reply = p.pipe.BlockByHash(args.Hash) } return nil @@ -97,13 +101,11 @@ func (p *EthereumApi) GetPeerCount(reply *interface{}) error { func (p *EthereumApi) GetIsListening(reply *interface{}) error { *reply = p.pipe.IsListening() - // *reply = NewSuccessRes(GetListeningRes{IsListening: p.pipe.IsListening()}) return nil } func (p *EthereumApi) GetCoinbase(reply *interface{}) error { *reply = p.pipe.CoinBase() - // *reply = p.pipe.CoinBase() return nil } @@ -131,14 +133,6 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err return nil } -// type JsonArgs interface { -// requirements() error -// } - -// type BlockResponse struct { -// JsonResponse -// } - type GetBlockArgs struct { BlockNumber int32 Hash string @@ -306,13 +300,3 @@ type BalanceRes struct { Balance string `json:"balance"` Address string `json:"address"` } - -// type TestRes struct { -// JsonResponse `json:"-"` -// Answer int `json:"answer"` -// } - -// func (p *EthereumApi) Test(args *GetBlockArgs, reply *interface{}) error { -// *reply = NewSuccessRes(TestRes{Answer: 15}) -// return nil -// } -- cgit v1.2.3 From b178414a475aa48764622487223237a7d28edd46 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 13 Jan 2015 09:13:43 -0600 Subject: Added license headers --- rpc/json.go | 16 ++++++++++++++++ rpc/message.go | 16 ++++++++++++++++ rpc/packages.go | 16 ++++++++++++++++ rpc/server.go | 16 ++++++++++++++++ 4 files changed, 64 insertions(+) (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go index 85b198d12..8c2a672e3 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -1,3 +1,19 @@ +/* + 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 . +*/ package rpc import ( diff --git a/rpc/message.go b/rpc/message.go index 8aadfa691..03e9625ac 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -1,3 +1,19 @@ +/* + 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 . +*/ package rpc import ( diff --git a/rpc/packages.go b/rpc/packages.go index 4414abf19..8a58700b2 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -1,3 +1,19 @@ +/* + 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: diff --git a/rpc/server.go b/rpc/server.go index 39b955dff..56b16b649 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -1,3 +1,19 @@ +/* + 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 . +*/ package rpc import ( -- cgit v1.2.3 From 961e4da7d885a6d5d00fc7c3ab2e11c80c9eeecc Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 13 Jan 2015 09:27:36 -0600 Subject: Add support for CodeAt --- rpc/json.go | 8 ++++++-- rpc/message.go | 15 +++++++++++++++ rpc/packages.go | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go index 8c2a672e3..2e6ef2c2b 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -72,8 +72,12 @@ func (self jsonWrapper) GetRequestReply(xeth *EthereumApi, req *RpcRequest, repl return err } return xeth.GetTxCountAt(args, reply) - // case "eth_codeAt": - // return nil + case "eth_codeAt": + args, err := req.ToGetCodeAtArgs() + if err != nil { + return err + } + return xeth.GetCodeAt(args, reply) case "eth_balanceAt": args, err := req.ToGetBalanceArgs() if err != nil { diff --git a/rpc/message.go b/rpc/message.go index 03e9625ac..91fbde99b 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -147,6 +147,21 @@ func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) { return args, nil } +func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetCodeAtArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + jsonlogger.DebugDetailf("%T %v", args, args) + return args, nil +} + // func NewSuccessRes(object JsonResponse) string { // e := SuccessRes{Error: false, Result: object} // res, err := json.Marshal(e) diff --git a/rpc/packages.go b/rpc/packages.go index 8a58700b2..4e6016b9e 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -149,6 +149,15 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err return nil } +func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } + *reply = p.pipe.CodeAt(args.Address) + return nil +} + type GetBlockArgs struct { BlockNumber int32 Hash string @@ -236,6 +245,15 @@ type GetStorageArgs struct { Key string } +func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + func (a *GetStorageArgs) requirements() error { if a.Address == "" { return NewErrorResponse("GetStorageAt requires an 'address' value as argument") @@ -316,3 +334,22 @@ type BalanceRes struct { Balance string `json:"balance"` Address string `json:"address"` } +type GetCodeAtArgs struct { + Address string +} + +func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, &arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (a *GetCodeAtArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetCodeAt requires an 'address' value as argument") + } + return nil +} -- cgit v1.2.3 From a81d835e4d27f600fac31f74d938d0b6502c3072 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 13 Jan 2015 09:37:08 -0600 Subject: cleanup --- rpc/json.go | 2 +- rpc/message.go | 12 ------------ rpc/packages.go | 5 +++-- rpc/server.go | 2 +- 4 files changed, 5 insertions(+), 16 deletions(-) (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go index 2e6ef2c2b..dc37a7cb7 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -55,7 +55,7 @@ func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) } func (self jsonWrapper) GetRequestReply(xeth *EthereumApi, req *RpcRequest, reply *interface{}) error { - // call function for request method + // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC jsonlogger.DebugDetailf("%T %s", req.Params, req.Params) switch req.Method { case "eth_coinbase": diff --git a/rpc/message.go b/rpc/message.go index 91fbde99b..63de734b8 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -162,18 +162,6 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { return args, nil } -// func NewSuccessRes(object JsonResponse) string { -// e := SuccessRes{Error: false, Result: object} -// res, err := json.Marshal(e) -// if err != nil { -// // This should never happen -// panic("Creating json error response failed, help") -// } -// success := string(res) -// return success -// // return res -// } - func NewErrorResponse(msg string) error { return errors.New(msg) } diff --git a/rpc/packages.go b/rpc/packages.go index 4e6016b9e..e5ed995e7 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -20,7 +20,7 @@ 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() 2. json.Decoder() calls "UnmarshalJSON" defined on each "Args" struct -3. EthereumApi "Get" method, taking the "Args" type and replying with an interface to be marshalled to JSON +3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to JSON */ package rpc @@ -173,7 +173,7 @@ func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { obj.Hash = argstr return } - return NewErrorResponse("Could not determine JSON parameters") + return NewErrorResponse(ErrorDecodeArgs) } func (obj *GetBlockArgs) requirements() error { @@ -334,6 +334,7 @@ type BalanceRes struct { Balance string `json:"balance"` Address string `json:"address"` } + type GetCodeAtArgs struct { Address string } diff --git a/rpc/server.go b/rpc/server.go index 56b16b649..d14f50f24 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -58,7 +58,7 @@ func (s *JsonRpcServer) Start() { http.Handle("/", h) err := http.Serve(s.listener, nil) - // TODO Complains on shutdown due to listner already being closed + // FIX Complains on shutdown due to listner already being closed if err != nil { jsonlogger.Errorln("Error on JSON-RPC interface:", err) } -- cgit v1.2.3 From 499bc404e818848e53c8c7f4f6d1bfe2349e97ae Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 13 Jan 2015 09:37:30 -0600 Subject: Stub missing UnmarshalJSON methods --- rpc/packages.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index e5ed995e7..d371c4ca1 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -197,6 +197,13 @@ type NewTxArgs struct { // Hash string // } +func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { + if err = json.Unmarshal(b, obj); err == nil { + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + func (a *NewTxArgs) requirements() error { if a.Recipient == "" { return NewErrorResponse("Transact requires a 'recipient' address as argument") @@ -233,6 +240,15 @@ type PushTxArgs struct { Tx string `json:"tx"` } +func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Tx = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + func (a *PushTxArgs) requirementsPushTx() error { if a.Tx == "" { return NewErrorResponse("PushTx requires a 'tx' as argument") -- cgit v1.2.3 From a6d4ce263012ef160c9a897ac6ba032ddac526c7 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 20 Jan 2015 13:57:51 -0600 Subject: Move argument types to separate file --- rpc/args.go | 218 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ rpc/packages.go | 211 ------------------------------------------------------ 2 files changed, 218 insertions(+), 211 deletions(-) create mode 100644 rpc/args.go (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go new file mode 100644 index 000000000..8b01cc191 --- /dev/null +++ b/rpc/args.go @@ -0,0 +1,218 @@ +package rpc + +import ( + "encoding/json" +) + +type GetBlockArgs struct { + BlockNumber int32 + Hash string +} + +func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { + argint, argstr := int32(0), "" + if err = json.Unmarshal(b, &argint); err == nil { + obj.BlockNumber = argint + return + } + if err = json.Unmarshal(b, &argstr); err == nil { + obj.Hash = argstr + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (obj *GetBlockArgs) requirements() error { + if obj.BlockNumber == 0 && obj.Hash == "" { + return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") + } + return nil +} + +type NewTxArgs struct { + Sec string `json:"sec"` + Recipient string `json:"recipient"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasprice"` + Init string `json:"init"` + Body string `json:"body"` +} + +// type TxResponse struct { +// Hash string +// } + +func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { + if err = json.Unmarshal(b, obj); err == nil { + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (a *NewTxArgs) requirements() error { + if a.Recipient == "" { + return NewErrorResponse("Transact requires a 'recipient' address as argument") + } + if a.Value == "" { + return NewErrorResponse("Transact requires a 'value' as argument") + } + if a.Gas == "" { + return NewErrorResponse("Transact requires a 'gas' value as argument") + } + if a.GasPrice == "" { + return NewErrorResponse("Transact requires a 'gasprice' value as argument") + } + return nil +} + +func (a *NewTxArgs) requirementsContract() error { + if a.Value == "" { + return NewErrorResponse("Create requires a 'value' as argument") + } + if a.Gas == "" { + return NewErrorResponse("Create requires a 'gas' value as argument") + } + if a.GasPrice == "" { + return NewErrorResponse("Create requires a 'gasprice' value as argument") + } + if a.Body == "" { + return NewErrorResponse("Create requires a 'body' value as argument") + } + return nil +} + +type PushTxArgs struct { + Tx string `json:"tx"` +} + +func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Tx = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (a *PushTxArgs) requirementsPushTx() error { + if a.Tx == "" { + return NewErrorResponse("PushTx requires a 'tx' as argument") + } + return nil +} + +type GetStorageArgs struct { + Address string + Key string +} + +func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (a *GetStorageArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetStorageAt requires an 'address' value as argument") + } + if a.Key == "" { + return NewErrorResponse("GetStorageAt requires an 'key' value as argument") + } + return nil +} + +type GetStorageAtRes struct { + Key string `json:"key"` + Value string `json:"value"` + Address string `json:"address"` +} + +type GetTxCountArgs struct { + Address string `json:"address"` +} + +// type GetTxCountRes struct { +// Nonce int `json:"nonce"` +// } + +func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse("Could not determine JSON parameters") +} + +func (a *GetTxCountArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetTxCountAt requires an 'address' value as argument") + } + return nil +} + +// type GetPeerCountRes struct { +// PeerCount int `json:"peerCount"` +// } + +// type GetListeningRes struct { +// IsListening bool `json:"isListening"` +// } + +// type GetCoinbaseRes struct { +// Coinbase string `json:"coinbase"` +// } + +// type GetMiningRes struct { +// IsMining bool `json:"isMining"` +// } + +type GetBalanceArgs struct { + Address string +} + +func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, &arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse("Could not determine JSON parameters") +} + +func (a *GetBalanceArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") + } + return nil +} + +type BalanceRes struct { + Balance string `json:"balance"` + Address string `json:"address"` +} + +type GetCodeAtArgs struct { + Address string +} + +func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) { + arg0 := "" + if err = json.Unmarshal(b, &arg0); err == nil { + obj.Address = arg0 + return + } + return NewErrorResponse(ErrorDecodeArgs) +} + +func (a *GetCodeAtArgs) requirements() error { + if a.Address == "" { + return NewErrorResponse("GetCodeAt requires an 'address' value as argument") + } + return nil +} diff --git a/rpc/packages.go b/rpc/packages.go index d371c4ca1..34a4467b1 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -26,7 +26,6 @@ For each request type, define the following: package rpc import ( - "encoding/json" "math/big" "strings" @@ -158,215 +157,5 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } -type GetBlockArgs struct { - BlockNumber int32 - Hash string -} - -func (obj *GetBlockArgs) UnmarshalJSON(b []byte) (err error) { - argint, argstr := int32(0), "" - if err = json.Unmarshal(b, &argint); err == nil { - obj.BlockNumber = argint - return - } - if err = json.Unmarshal(b, &argstr); err == nil { - obj.Hash = argstr - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - -func (obj *GetBlockArgs) requirements() error { - if obj.BlockNumber == 0 && obj.Hash == "" { - return NewErrorResponse("GetBlock requires either a block 'number' or a block 'hash' as argument") - } - return nil -} - -type NewTxArgs struct { - Sec string `json:"sec"` - Recipient string `json:"recipient"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasprice"` - Init string `json:"init"` - Body string `json:"body"` -} - -// type TxResponse struct { -// Hash string -// } - -func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - if err = json.Unmarshal(b, obj); err == nil { - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - -func (a *NewTxArgs) requirements() error { - if a.Recipient == "" { - return NewErrorResponse("Transact requires a 'recipient' address as argument") - } - if a.Value == "" { - return NewErrorResponse("Transact requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Transact requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Transact requires a 'gasprice' value as argument") - } - return nil -} - -func (a *NewTxArgs) requirementsContract() error { - if a.Value == "" { - return NewErrorResponse("Create requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Create requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Create requires a 'gasprice' value as argument") - } - if a.Body == "" { - return NewErrorResponse("Create requires a 'body' value as argument") - } - return nil -} - -type PushTxArgs struct { - Tx string `json:"tx"` -} - -func (obj *PushTxArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { - obj.Tx = arg0 - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - -func (a *PushTxArgs) requirementsPushTx() error { - if a.Tx == "" { - return NewErrorResponse("PushTx requires a 'tx' as argument") - } - return nil -} - -type GetStorageArgs struct { - Address string - Key string -} - -func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { - obj.Address = arg0 - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - -func (a *GetStorageArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetStorageAt requires an 'address' value as argument") - } - if a.Key == "" { - return NewErrorResponse("GetStorageAt requires an 'key' value as argument") - } - return nil -} - -type GetStorageAtRes struct { - Key string `json:"key"` - Value string `json:"value"` - Address string `json:"address"` -} - -type GetTxCountArgs struct { - Address string `json:"address"` -} - -// type GetTxCountRes struct { -// Nonce int `json:"nonce"` -// } - -func (obj *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, arg0); err == nil { - obj.Address = arg0 - return - } - return NewErrorResponse("Could not determine JSON parameters") -} - -func (a *GetTxCountArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetTxCountAt requires an 'address' value as argument") - } - return nil -} - -// type GetPeerCountRes struct { -// PeerCount int `json:"peerCount"` -// } - -// type GetListeningRes struct { -// IsListening bool `json:"isListening"` -// } - -// type GetCoinbaseRes struct { -// Coinbase string `json:"coinbase"` -// } - -// type GetMiningRes struct { -// IsMining bool `json:"isMining"` -// } - -type GetBalanceArgs struct { - Address string -} - -func (obj *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return - } - return NewErrorResponse("Could not determine JSON parameters") -} - -func (a *GetBalanceArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetBalanceAt requires an 'address' value as argument") - } - return nil -} - -type BalanceRes struct { - Balance string `json:"balance"` - Address string `json:"address"` -} - -type GetCodeAtArgs struct { - Address string -} - -func (obj *GetCodeAtArgs) UnmarshalJSON(b []byte) (err error) { - arg0 := "" - if err = json.Unmarshal(b, &arg0); err == nil { - obj.Address = arg0 - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - -func (a *GetCodeAtArgs) requirements() error { - if a.Address == "" { - return NewErrorResponse("GetCodeAt requires an 'address' value as argument") - } return nil } -- cgit v1.2.3 From 215780ab562b940bfc653c16bf84f812ef062821 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 20 Jan 2015 13:58:51 -0600 Subject: Move GetRequestReply to EthereumApi Off of jsonWrapper --- rpc/json.go | 50 -------------------------------------------------- rpc/packages.go | 47 +++++++++++++++++++++++++++++++++++++++++++++++ rpc/server.go | 2 +- 3 files changed, 48 insertions(+), 51 deletions(-) (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go index dc37a7cb7..5446cb3c1 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -54,54 +54,4 @@ func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) return reqParsed, nil } -func (self jsonWrapper) GetRequestReply(xeth *EthereumApi, req *RpcRequest, reply *interface{}) error { - // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC - jsonlogger.DebugDetailf("%T %s", req.Params, req.Params) - switch req.Method { - case "eth_coinbase": - return xeth.GetCoinbase(reply) - case "eth_listening": - return xeth.GetIsListening(reply) - case "eth_mining": - return xeth.GetIsMining(reply) - case "eth_peerCount": - return xeth.GetPeerCount(reply) - case "eth_countAt": - args, err := req.ToGetTxCountArgs() - if err != nil { - return err - } - return xeth.GetTxCountAt(args, reply) - case "eth_codeAt": - args, err := req.ToGetCodeAtArgs() - if err != nil { - return err - } - return xeth.GetCodeAt(args, reply) - case "eth_balanceAt": - args, err := req.ToGetBalanceArgs() - if err != nil { - return err - } - return xeth.GetBalanceAt(args, reply) - case "eth_stateAt": - args, err := req.ToGetStorageArgs() - if err != nil { - return err - } - return xeth.GetStorageAt(args, reply) - case "eth_blockByNumber", "eth_blockByHash": - args, err := req.ToGetBlockArgs() - if err != nil { - return err - } - return xeth.GetBlock(args, reply) - default: - return NewErrorResponse(ErrorNotImplemented) - } - - jsonlogger.DebugDetailf("Reply: %T %s", reply, reply) - return nil -} - var JSON jsonWrapper diff --git a/rpc/packages.go b/rpc/packages.go index 34a4467b1..e87e0db7c 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -157,5 +157,52 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { + // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC + jsonlogger.DebugDetailf("%T %s", req.Params, req.Params) + switch req.Method { + case "eth_coinbase": + return p.GetCoinbase(reply) + case "eth_listening": + return p.GetIsListening(reply) + case "eth_mining": + return p.GetIsMining(reply) + case "eth_peerCount": + return p.GetPeerCount(reply) + case "eth_countAt": + args, err := req.ToGetTxCountArgs() + if err != nil { + return err + } + return p.GetTxCountAt(args, reply) + case "eth_codeAt": + args, err := req.ToGetCodeAtArgs() + if err != nil { + return err + } + return p.GetCodeAt(args, reply) + case "eth_balanceAt": + args, err := req.ToGetBalanceArgs() + if err != nil { + return err + } + return p.GetBalanceAt(args, reply) + case "eth_stateAt": + args, err := req.ToGetStorageArgs() + if err != nil { + return err + } + return p.GetStorageAt(args, reply) + case "eth_blockByNumber", "eth_blockByHash": + args, err := req.ToGetBlockArgs() + if err != nil { + return err + } + return p.GetBlock(args, reply) + default: + return NewErrorResponse(ErrorNotImplemented) + } + + jsonlogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } diff --git a/rpc/server.go b/rpc/server.go index d14f50f24..a4cf1aa7c 100644 --- a/rpc/server.go +++ b/rpc/server.go @@ -89,7 +89,7 @@ func apiHandler(xeth *EthereumApi) http.Handler { } var response interface{} - reserr := JSON.GetRequestReply(xeth, &reqParsed, &response) + reserr := xeth.GetRequestReply(&reqParsed, &response) if reserr != nil { jsonlogger.Errorln(reserr) JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) -- cgit v1.2.3 From d790229a33b1f3e6256ca6916be17a0cc3663076 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Sun, 25 Jan 2015 14:50:43 -0600 Subject: Move HTTP transport to sub package of RPC --- rpc/http/server.go | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++++ rpc/json.go | 19 +++++----- rpc/message.go | 14 +++---- rpc/packages.go | 15 ++++++-- rpc/server.go | 104 --------------------------------------------------- 5 files changed, 136 insertions(+), 123 deletions(-) create mode 100644 rpc/http/server.go delete mode 100644 rpc/server.go (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go new file mode 100644 index 000000000..a8b116076 --- /dev/null +++ b/rpc/http/server.go @@ -0,0 +1,107 @@ +/* + 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 . +*/ +package rpchttp + +import ( + "fmt" + "net" + "net/http" + + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/xeth" +) + +var rpchttplogger = logger.NewLogger("RPC-HTTP") +var JSON rpc.JsonWrapper + +func NewRpcHttpServer(pipe *xeth.JSXEth, port int) (*RpcHttpServer, error) { + sport := fmt.Sprintf(":%d", port) + l, err := net.Listen("tcp", sport) + if err != nil { + return nil, err + } + + return &RpcHttpServer{ + listener: l, + quit: make(chan bool), + pipe: pipe, + }, nil +} + +type RpcHttpServer struct { + quit chan bool + listener net.Listener + pipe *xeth.JSXEth +} + +func (s *RpcHttpServer) exitHandler() { +out: + for { + select { + case <-s.quit: + s.listener.Close() + break out + } + } + + rpchttplogger.Infoln("Shutdown RPC-HTTP server") +} + +func (s *RpcHttpServer) Stop() { + close(s.quit) +} + +func (s *RpcHttpServer) Start() { + rpchttplogger.Infoln("Starting RPC-HTTP server") + go s.exitHandler() + + api := rpc.NewEthereumApi(s.pipe) + h := s.apiHandler(api) + http.Handle("/", h) + + err := http.Serve(s.listener, nil) + // FIX Complains on shutdown due to listner already being closed + if err != nil { + rpchttplogger.Errorln("Error on RPC-HTTP interface:", err) + } +} + +func (s *RpcHttpServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { + fn := func(w http.ResponseWriter, req *http.Request) { + rpchttplogger.Debugln("Handling request") + + reqParsed, reqerr := JSON.ParseRequestBody(req) + if reqerr != nil { + JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) + return + } + + var response interface{} + reserr := xeth.GetRequestReply(&reqParsed, &response) + if reserr != nil { + rpchttplogger.Errorln(reserr) + JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) + return + } + + rpchttplogger.Debugf("Generated response: %T %s", response, response) + JSON.Send(w, &rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) + } + + return http.HandlerFunc(fn) +} diff --git a/rpc/json.go b/rpc/json.go index 5446cb3c1..9bd204818 100644 --- a/rpc/json.go +++ b/rpc/json.go @@ -18,25 +18,28 @@ package rpc import ( "encoding/json" + "github.com/ethereum/go-ethereum/logger" "io" "net/http" ) -type jsonWrapper struct{} +var rpclogger = logger.NewLogger("RPC") -func (self jsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { +type JsonWrapper struct{} + +func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { var payload []byte payload, err = json.Marshal(v) if err != nil { - jsonlogger.Fatalln("Error marshalling JSON", err) + rpclogger.Fatalln("Error marshalling JSON", err) return 0, err } - jsonlogger.Infof("Sending payload: %s", payload) + rpclogger.Infof("Sending payload: %s", payload) return writer.Write(payload) } -func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { +func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { var reqParsed RpcRequest // Convert JSON to native types @@ -46,12 +49,10 @@ func (self jsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) err := d.Decode(&reqParsed) if err != nil { - jsonlogger.Errorln("Error decoding JSON: ", err) + rpclogger.Errorln("Error decoding JSON: ", err) return reqParsed, err } - jsonlogger.DebugDetailf("Parsed request: %s", reqParsed) + rpclogger.DebugDetailf("Parsed request: %s", reqParsed) return reqParsed, nil } - -var JSON jsonWrapper diff --git a/rpc/message.go b/rpc/message.go index 63de734b8..caf50a6c0 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -67,7 +67,7 @@ func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -82,7 +82,7 @@ func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -97,7 +97,7 @@ func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -113,7 +113,7 @@ func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -128,7 +128,7 @@ func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -143,7 +143,7 @@ func (req *RpcRequest) ToGetBalanceArgs() (*GetBalanceArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } @@ -158,7 +158,7 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { if err != nil { return nil, NewErrorResponse(ErrorDecodeArgs) } - jsonlogger.DebugDetailf("%T %v", args, args) + rpclogger.DebugDetailf("%T %v", args, args) return args, nil } diff --git a/rpc/packages.go b/rpc/packages.go index e87e0db7c..8b5965069 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -33,6 +33,15 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) +type RpcServer interface { + Start() + Stop() +} + +func NewEthereumApi(xeth *xeth.JSXEth) *EthereumApi { + return &EthereumApi{pipe: xeth} +} + type EthereumApi struct { pipe *xeth.JSXEth } @@ -103,7 +112,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err i, _ := new(big.Int).SetString(args.Key, 10) hx = ethutil.Bytes2Hex(i.Bytes()) } - jsonlogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) + rpclogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) value := state.Storage(ethutil.Hex2Bytes(hx)) *reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()} return nil @@ -159,7 +168,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC - jsonlogger.DebugDetailf("%T %s", req.Params, req.Params) + rpclogger.DebugDetailf("%T %s", req.Params, req.Params) switch req.Method { case "eth_coinbase": return p.GetCoinbase(reply) @@ -203,6 +212,6 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return NewErrorResponse(ErrorNotImplemented) } - jsonlogger.DebugDetailf("Reply: %T %s", reply, reply) + rpclogger.DebugDetailf("Reply: %T %s", reply, reply) return nil } diff --git a/rpc/server.go b/rpc/server.go deleted file mode 100644 index a4cf1aa7c..000000000 --- a/rpc/server.go +++ /dev/null @@ -1,104 +0,0 @@ -/* - 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 . -*/ -package rpc - -import ( - "fmt" - "net" - "net/http" - - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/xeth" -) - -var jsonlogger = logger.NewLogger("JSON") - -type JsonRpcServer struct { - quit chan bool - listener net.Listener - pipe *xeth.JSXEth -} - -func (s *JsonRpcServer) exitHandler() { -out: - for { - select { - case <-s.quit: - s.listener.Close() - break out - } - } - - jsonlogger.Infoln("Shutdown JSON-RPC server") -} - -func (s *JsonRpcServer) Stop() { - close(s.quit) -} - -func (s *JsonRpcServer) Start() { - jsonlogger.Infoln("Starting JSON-RPC server") - go s.exitHandler() - - h := apiHandler(&EthereumApi{pipe: s.pipe}) - http.Handle("/", h) - - err := http.Serve(s.listener, nil) - // FIX Complains on shutdown due to listner already being closed - if err != nil { - jsonlogger.Errorln("Error on JSON-RPC interface:", err) - } -} - -func NewJsonRpcServer(pipe *xeth.JSXEth, port int) (*JsonRpcServer, error) { - sport := fmt.Sprintf(":%d", port) - l, err := net.Listen("tcp", sport) - if err != nil { - return nil, err - } - - return &JsonRpcServer{ - listener: l, - quit: make(chan bool), - pipe: pipe, - }, nil -} - -func apiHandler(xeth *EthereumApi) http.Handler { - fn := func(w http.ResponseWriter, req *http.Request) { - jsonlogger.Debugln("Handling request") - - reqParsed, reqerr := JSON.ParseRequestBody(req) - if reqerr != nil { - JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: ErrorParseRequest}) - return - } - - var response interface{} - reserr := xeth.GetRequestReply(&reqParsed, &response) - if reserr != nil { - jsonlogger.Errorln(reserr) - JSON.Send(w, &RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) - return - } - - jsonlogger.Debugf("Generated response: %T %s", response, response) - JSON.Send(w, &RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) - } - - return http.HandlerFunc(fn) -} -- cgit v1.2.3 From 2f0166b94583cc17fab28f3e4f1214f220d6c4a3 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 27 Jan 2015 12:26:30 -0600 Subject: Indicate port in startup log message --- rpc/http/server.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index a8b116076..631d47110 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -40,6 +40,7 @@ func NewRpcHttpServer(pipe *xeth.JSXEth, port int) (*RpcHttpServer, error) { listener: l, quit: make(chan bool), pipe: pipe, + port: port, }, nil } @@ -47,6 +48,7 @@ type RpcHttpServer struct { quit chan bool listener net.Listener pipe *xeth.JSXEth + port int } func (s *RpcHttpServer) exitHandler() { @@ -67,7 +69,7 @@ func (s *RpcHttpServer) Stop() { } func (s *RpcHttpServer) Start() { - rpchttplogger.Infoln("Starting RPC-HTTP server") + rpchttplogger.Infof("Starting RPC-HTTP server on port %d", s.port) go s.exitHandler() api := rpc.NewEthereumApi(s.pipe) -- cgit v1.2.3 From b8e7b8e2e1b88e40090c9b741b4cd7000689ae9e Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 27 Jan 2015 12:27:14 -0600 Subject: New simplified Websocket transport Uses rpc.EthereumApi abstraction --- rpc/websocket/server.go | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 rpc/websocket/server.go (limited to 'rpc') diff --git a/rpc/websocket/server.go b/rpc/websocket/server.go new file mode 100644 index 000000000..f854fe502 --- /dev/null +++ b/rpc/websocket/server.go @@ -0,0 +1,124 @@ +/* + 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 . +*/ +package websocket + +import ( + "fmt" + "net" + "net/http" + + ws "code.google.com/p/go.net/websocket" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/event/filter" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/xeth" +) + +var wslogger = logger.NewLogger("RPC-WS") + +type WebSocketServer struct { + eth *eth.Ethereum + filterManager *filter.FilterManager + port int + doneCh chan bool + listener net.Listener +} + +func NewWebSocketServer(eth *eth.Ethereum, port int) (*WebSocketServer, error) { + sport := fmt.Sprintf(":%d", port) + l, err := net.Listen("tcp", sport) + if err != nil { + return nil, err + } + + filterManager := filter.NewFilterManager(eth.EventMux()) + go filterManager.Start() + + return &WebSocketServer{eth, + filterManager, + port, + make(chan bool), + l, + }, nil +} + +func (self *WebSocketServer) handlerLoop() { + for { + select { + case <-self.doneCh: + wslogger.Infoln("Shutdown RPC-WS server") + return + } + } +} + +func (self *WebSocketServer) Stop() { + close(self.doneCh) +} + +func (self *WebSocketServer) Start() { + wslogger.Infof("Starting RPC-WS server on port %d", self.port) + go self.handlerLoop() + + api := rpc.NewEthereumApi(xeth.NewJSXEth(self.eth)) + h := self.apiHandler(api) + http.Handle("/ws", h) + + err := http.Serve(self.listener, nil) + if err != nil { + wslogger.Errorln("Error on RPC-WS interface:", err) + } +} + +func (s *WebSocketServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { + fn := func(w http.ResponseWriter, req *http.Request) { + h := sockHandler(xeth) + s := ws.Server{Handler: h} + s.ServeHTTP(w, req) + } + + return http.HandlerFunc(fn) +} + +func sockHandler(xeth *rpc.EthereumApi) ws.Handler { + fn := func(conn *ws.Conn) { + for { + // FIX wslogger does not output to console + wslogger.Debugln("Handling request") + var reqParsed rpc.RpcRequest + + if err := ws.JSON.Receive(conn, &reqParsed); err != nil { + wslogger.Debugln(rpc.ErrorParseRequest) + ws.JSON.Send(conn, rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) + continue + } + + var response interface{} + reserr := xeth.GetRequestReply(&reqParsed, &response) + if reserr != nil { + wslogger.Errorln(reserr) + ws.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) + ws.JSON.Send(conn, rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) + } + } + return fn +} -- cgit v1.2.3 From dd3f38fe5b283f3c728823cb2d4e844712017e48 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 27 Jan 2015 14:16:34 -0600 Subject: Rename transport to ws Cleanup object naming for clarity --- rpc/websocket/server.go | 124 ------------------------------------------------ rpc/ws/server.go | 124 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 124 deletions(-) delete mode 100644 rpc/websocket/server.go create mode 100644 rpc/ws/server.go (limited to 'rpc') diff --git a/rpc/websocket/server.go b/rpc/websocket/server.go deleted file mode 100644 index f854fe502..000000000 --- a/rpc/websocket/server.go +++ /dev/null @@ -1,124 +0,0 @@ -/* - 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 . -*/ -package websocket - -import ( - "fmt" - "net" - "net/http" - - ws "code.google.com/p/go.net/websocket" - "github.com/ethereum/go-ethereum/eth" - "github.com/ethereum/go-ethereum/event/filter" - "github.com/ethereum/go-ethereum/logger" - "github.com/ethereum/go-ethereum/rpc" - "github.com/ethereum/go-ethereum/xeth" -) - -var wslogger = logger.NewLogger("RPC-WS") - -type WebSocketServer struct { - eth *eth.Ethereum - filterManager *filter.FilterManager - port int - doneCh chan bool - listener net.Listener -} - -func NewWebSocketServer(eth *eth.Ethereum, port int) (*WebSocketServer, error) { - sport := fmt.Sprintf(":%d", port) - l, err := net.Listen("tcp", sport) - if err != nil { - return nil, err - } - - filterManager := filter.NewFilterManager(eth.EventMux()) - go filterManager.Start() - - return &WebSocketServer{eth, - filterManager, - port, - make(chan bool), - l, - }, nil -} - -func (self *WebSocketServer) handlerLoop() { - for { - select { - case <-self.doneCh: - wslogger.Infoln("Shutdown RPC-WS server") - return - } - } -} - -func (self *WebSocketServer) Stop() { - close(self.doneCh) -} - -func (self *WebSocketServer) Start() { - wslogger.Infof("Starting RPC-WS server on port %d", self.port) - go self.handlerLoop() - - api := rpc.NewEthereumApi(xeth.NewJSXEth(self.eth)) - h := self.apiHandler(api) - http.Handle("/ws", h) - - err := http.Serve(self.listener, nil) - if err != nil { - wslogger.Errorln("Error on RPC-WS interface:", err) - } -} - -func (s *WebSocketServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { - fn := func(w http.ResponseWriter, req *http.Request) { - h := sockHandler(xeth) - s := ws.Server{Handler: h} - s.ServeHTTP(w, req) - } - - return http.HandlerFunc(fn) -} - -func sockHandler(xeth *rpc.EthereumApi) ws.Handler { - fn := func(conn *ws.Conn) { - for { - // FIX wslogger does not output to console - wslogger.Debugln("Handling request") - var reqParsed rpc.RpcRequest - - if err := ws.JSON.Receive(conn, &reqParsed); err != nil { - wslogger.Debugln(rpc.ErrorParseRequest) - ws.JSON.Send(conn, rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: rpc.ErrorParseRequest}) - continue - } - - var response interface{} - reserr := xeth.GetRequestReply(&reqParsed, &response) - if reserr != nil { - wslogger.Errorln(reserr) - ws.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) - ws.JSON.Send(conn, rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) - } - } - return fn -} diff --git a/rpc/ws/server.go b/rpc/ws/server.go new file mode 100644 index 000000000..9be305b6c --- /dev/null +++ b/rpc/ws/server.go @@ -0,0 +1,124 @@ +/* + 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 . +*/ +package ws + +import ( + "fmt" + "net" + "net/http" + + "code.google.com/p/go.net/websocket" + "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/event/filter" + "github.com/ethereum/go-ethereum/logger" + "github.com/ethereum/go-ethereum/rpc" + "github.com/ethereum/go-ethereum/xeth" +) + +var wslogger = logger.NewLogger("RPC-WS") + +type WebSocketServer struct { + eth *eth.Ethereum + filterManager *filter.FilterManager + port int + doneCh chan bool + listener net.Listener +} + +func NewWebSocketServer(eth *eth.Ethereum, port int) (*WebSocketServer, error) { + sport := fmt.Sprintf(":%d", port) + l, err := net.Listen("tcp", sport) + if err != nil { + return nil, err + } + + filterManager := filter.NewFilterManager(eth.EventMux()) + go filterManager.Start() + + return &WebSocketServer{eth, + filterManager, + port, + make(chan bool), + l, + }, nil +} + +func (self *WebSocketServer) handlerLoop() { + for { + select { + case <-self.doneCh: + wslogger.Infoln("Shutdown RPC-WS server") + return + } + } +} + +func (self *WebSocketServer) Stop() { + close(self.doneCh) +} + +func (self *WebSocketServer) Start() { + wslogger.Infof("Starting RPC-WS server on port %d", self.port) + go self.handlerLoop() + + api := rpc.NewEthereumApi(xeth.NewJSXEth(self.eth)) + h := self.apiHandler(api) + http.Handle("/ws", h) + + err := http.Serve(self.listener, nil) + if err != nil { + wslogger.Errorln("Error on RPC-WS interface:", err) + } +} + +func (s *WebSocketServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { + fn := func(w http.ResponseWriter, req *http.Request) { + h := sockHandler(xeth) + s := websocket.Server{Handler: h} + s.ServeHTTP(w, req) + } + + return http.HandlerFunc(fn) +} + +func sockHandler(xeth *rpc.EthereumApi) websocket.Handler { + fn := func(conn *websocket.Conn) { + for { + // FIX wslogger does not output to console + wslogger.Debugln("Handling request") + var reqParsed rpc.RpcRequest + + 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}) + continue + } + + var response interface{} + reserr := xeth.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()}) + 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}) + } + } + return fn +} -- cgit v1.2.3 From d8c6168d11dda55ffb10bc70601e74e347c156e1 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 27 Jan 2015 14:26:42 -0600 Subject: Return a websocker.Handler of the function --- 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 9be305b6c..c275031f4 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -120,5 +120,5 @@ func sockHandler(xeth *rpc.EthereumApi) websocket.Handler { websocket.JSON.Send(conn, rpc.RpcSuccessResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: false, Result: response}) } } - return fn + return websocket.Handler(fn) } -- cgit v1.2.3 From e9d017ba082bfd624267c974fa93a77da6269756 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Tue, 27 Jan 2015 14:34:01 -0600 Subject: Rename api var for clarity --- rpc/http/server.go | 4 ++-- rpc/ws/server.go | 9 ++++----- 2 files changed, 6 insertions(+), 7 deletions(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index 631d47110..93b52a634 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -83,7 +83,7 @@ func (s *RpcHttpServer) Start() { } } -func (s *RpcHttpServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { +func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler { fn := func(w http.ResponseWriter, req *http.Request) { rpchttplogger.Debugln("Handling request") @@ -94,7 +94,7 @@ func (s *RpcHttpServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { } var response interface{} - reserr := xeth.GetRequestReply(&reqParsed, &response) + reserr := api.GetRequestReply(&reqParsed, &response) if reserr != nil { rpchttplogger.Errorln(reserr) JSON.Send(w, &rpc.RpcErrorResponse{JsonRpc: reqParsed.JsonRpc, ID: reqParsed.ID, Error: true, ErrorText: reserr.Error()}) diff --git a/rpc/ws/server.go b/rpc/ws/server.go index c275031f4..248ebc585 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -85,9 +85,9 @@ func (self *WebSocketServer) Start() { } } -func (s *WebSocketServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { +func (s *WebSocketServer) apiHandler(api *rpc.EthereumApi) http.Handler { fn := func(w http.ResponseWriter, req *http.Request) { - h := sockHandler(xeth) + h := sockHandler(api) s := websocket.Server{Handler: h} s.ServeHTTP(w, req) } @@ -95,10 +95,9 @@ func (s *WebSocketServer) apiHandler(xeth *rpc.EthereumApi) http.Handler { return http.HandlerFunc(fn) } -func sockHandler(xeth *rpc.EthereumApi) websocket.Handler { +func sockHandler(api *rpc.EthereumApi) websocket.Handler { fn := func(conn *websocket.Conn) { for { - // FIX wslogger does not output to console wslogger.Debugln("Handling request") var reqParsed rpc.RpcRequest @@ -109,7 +108,7 @@ func sockHandler(xeth *rpc.EthereumApi) websocket.Handler { } var response interface{} - reserr := xeth.GetRequestReply(&reqParsed, &response) + 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()}) -- cgit v1.2.3 From 7f638f0b2d8d989be25e660178d79df3278e4c84 Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 Jan 2015 18:14:28 +0100 Subject: moving to a better xeth --- rpc/http/server.go | 2 ++ rpc/packages.go | 35 +++++++++++++++-------------------- 2 files changed, 17 insertions(+), 20 deletions(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index 93b52a634..2a492f465 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -85,6 +85,8 @@ func (s *RpcHttpServer) Start() { func (s *RpcHttpServer) apiHandler(api *rpc.EthereumApi) http.Handler { fn := func(w http.ResponseWriter, req *http.Request) { + w.Header().Set("Access-Control-Allow-Origin", "*") + rpchttplogger.Debugln("Handling request") reqParsed, reqerr := JSON.ParseRequestBody(req) diff --git a/rpc/packages.go b/rpc/packages.go index 8b5965069..e6d4859d2 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -39,11 +39,11 @@ type RpcServer interface { } func NewEthereumApi(xeth *xeth.JSXEth) *EthereumApi { - return &EthereumApi{pipe: xeth} + return &EthereumApi{xeth: xeth} } type EthereumApi struct { - pipe *xeth.JSXEth + xeth *xeth.JSXEth } func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { @@ -53,9 +53,9 @@ func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { } if args.BlockNumber > 0 { - *reply = p.pipe.BlockByNumber(args.BlockNumber) + *reply = p.xeth.BlockByNumber(args.BlockNumber) } else { - *reply = p.pipe.BlockByHash(args.Hash) + *reply = p.xeth.BlockByHash(args.Hash) } return nil } @@ -65,7 +65,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) *reply = result return nil } @@ -76,7 +76,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { return err } - result, _ := p.pipe.Transact(p.pipe.Key().PrivateKey, "", args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ "", "", args.Value, args.Gas, args.GasPrice, args.Body) *reply = result return nil } @@ -86,23 +86,18 @@ func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.pipe.PushTx(args.Tx) + result, _ := p.xeth.PushTx(args.Tx) *reply = result return nil } -func (p *EthereumApi) GetKey(args interface{}, reply *interface{}) error { - *reply = p.pipe.Key() - return nil -} - func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error { err := args.requirements() if err != nil { return err } - state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) + state := p.xeth.State().SafeGet(args.Address) var hx string if strings.Index(args.Key, "0x") == 0 { @@ -119,22 +114,22 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err } func (p *EthereumApi) GetPeerCount(reply *interface{}) error { - *reply = p.pipe.PeerCount() + *reply = p.xeth.PeerCount() return nil } func (p *EthereumApi) GetIsListening(reply *interface{}) error { - *reply = p.pipe.IsListening() + *reply = p.xeth.IsListening() return nil } func (p *EthereumApi) GetCoinbase(reply *interface{}) error { - *reply = p.pipe.CoinBase() + *reply = p.xeth.Coinbase() return nil } func (p *EthereumApi) GetIsMining(reply *interface{}) error { - *reply = p.pipe.IsMining() + *reply = p.xeth.IsMining() return nil } @@ -143,7 +138,7 @@ func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) err if err != nil { return err } - *reply = p.pipe.TxCountAt(args.Address) + *reply = p.xeth.TxCountAt(args.Address) return nil } @@ -152,7 +147,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err if err != nil { return err } - state := p.pipe.World().SafeGet(ethutil.Hex2Bytes(args.Address)) + state := p.xeth.State().SafeGet(args.Address) *reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address} return nil } @@ -162,7 +157,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { if err != nil { return err } - *reply = p.pipe.CodeAt(args.Address) + *reply = p.xeth.CodeAt(args.Address) return nil } -- cgit v1.2.3 From 872b2497114209119becf2e8a4d4a5818e2084ee Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 Jan 2015 18:35:49 +0100 Subject: further cleaned up xeth interface --- rpc/http/server.go | 4 ++-- rpc/packages.go | 10 +++++----- rpc/ws/server.go | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) (limited to 'rpc') diff --git a/rpc/http/server.go b/rpc/http/server.go index 2a492f465..965727a4e 100644 --- a/rpc/http/server.go +++ b/rpc/http/server.go @@ -29,7 +29,7 @@ import ( var rpchttplogger = logger.NewLogger("RPC-HTTP") var JSON rpc.JsonWrapper -func NewRpcHttpServer(pipe *xeth.JSXEth, port int) (*RpcHttpServer, error) { +func NewRpcHttpServer(pipe *xeth.XEth, port int) (*RpcHttpServer, error) { sport := fmt.Sprintf(":%d", port) l, err := net.Listen("tcp", sport) if err != nil { @@ -47,7 +47,7 @@ func NewRpcHttpServer(pipe *xeth.JSXEth, port int) (*RpcHttpServer, error) { type RpcHttpServer struct { quit chan bool listener net.Listener - pipe *xeth.JSXEth + pipe *xeth.XEth port int } diff --git a/rpc/packages.go b/rpc/packages.go index e6d4859d2..700b9b2b3 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -19,8 +19,8 @@ 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() -2. json.Decoder() calls "UnmarshalJSON" defined on each "Args" struct -3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to JSON +2. json.Decoder() calls "UnmarshalON" defined on each "Args" struct +3. EthereumApi method, taking the "Args" type and replying with an interface to be marshalled to ON */ package rpc @@ -38,12 +38,12 @@ type RpcServer interface { Stop() } -func NewEthereumApi(xeth *xeth.JSXEth) *EthereumApi { +func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { return &EthereumApi{xeth: xeth} } type EthereumApi struct { - xeth *xeth.JSXEth + xeth *xeth.XEth } func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { @@ -162,7 +162,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { } func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { - // Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC + // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) switch req.Method { case "eth_coinbase": diff --git a/rpc/ws/server.go b/rpc/ws/server.go index 248ebc585..37b08ebd9 100644 --- a/rpc/ws/server.go +++ b/rpc/ws/server.go @@ -75,7 +75,7 @@ func (self *WebSocketServer) Start() { wslogger.Infof("Starting RPC-WS server on port %d", self.port) go self.handlerLoop() - api := rpc.NewEthereumApi(xeth.NewJSXEth(self.eth)) + api := rpc.NewEthereumApi(xeth.New(self.eth)) h := self.apiHandler(api) http.Handle("/ws", h) -- cgit v1.2.3 From cebb149f5cfaf008240d7069fd220401950cc7ee Mon Sep 17 00:00:00 2001 From: obscuren Date: Wed, 28 Jan 2015 20:50:09 +0100 Subject: removed key while in the process of moving to the new key storage --- rpc/packages.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 700b9b2b3..5d17a0f90 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -65,7 +65,7 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) *reply = result return nil } @@ -76,7 +76,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ "", "", args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Body) *reply = result return nil } -- cgit v1.2.3 From ec85458612e1d5374767f87005dd0ad5934f74d5 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 00:24:00 +0100 Subject: updated ethereum.js and moved to subfolder * Previous subtree caused a lot of trouble * Implemented sha3 in our shiny new http JSON RPC --- rpc/args.go | 11 +++++++++++ rpc/message.go | 14 ++++++++++++++ rpc/packages.go | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 8b01cc191..bebd79eb9 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -216,3 +216,14 @@ func (a *GetCodeAtArgs) requirements() error { } return nil } + +type Sha3Args struct { + Data string +} + +func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { + if err = json.Unmarshal(b, &obj.Data); err != nil { + return NewErrorResponse(ErrorDecodeArgs) + } + return +} diff --git a/rpc/message.go b/rpc/message.go index caf50a6c0..5785fcc87 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -56,6 +56,20 @@ type RpcRequest struct { Params []json.RawMessage `json:"params"` } +func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(Sha3Args) + r := bytes.NewReader(req.Params[0]) + if err := json.NewDecoder(r).Decode(args); err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) diff --git a/rpc/packages.go b/rpc/packages.go index 5d17a0f90..2c5fbf6be 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -26,9 +26,11 @@ For each request type, define the following: package rpc import ( + "fmt" "math/big" "strings" + "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/xeth" ) @@ -161,6 +163,11 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { + *reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data))) + return nil +} + func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) @@ -203,8 +210,14 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.GetBlock(args, reply) + case "web3_sha3": + args, err := req.ToSha3Args() + if err != nil { + return err + } + return p.Sha3(args, reply) default: - return NewErrorResponse(ErrorNotImplemented) + return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) } rpclogger.DebugDetailf("Reply: %T %s", reply, reply) -- cgit v1.2.3 From 6d012f628bbfc22b2587828968eff513dfeb4d8e Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 12:01:51 +0100 Subject: implement transact --- rpc/args.go | 37 ++----------------------------------- rpc/message.go | 17 +++++++++++------ rpc/packages.go | 11 +++++++++-- 3 files changed, 22 insertions(+), 43 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index bebd79eb9..0c3087151 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1,8 +1,6 @@ package rpc -import ( - "encoding/json" -) +import "encoding/json" type GetBlockArgs struct { BlockNumber int32 @@ -30,33 +28,18 @@ func (obj *GetBlockArgs) requirements() error { } type NewTxArgs struct { - Sec string `json:"sec"` Recipient string `json:"recipient"` Value string `json:"value"` Gas string `json:"gas"` GasPrice string `json:"gasprice"` - Init string `json:"init"` - Body string `json:"body"` + Data string `json:"data"` } // type TxResponse struct { // Hash string // } -func (obj *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - if err = json.Unmarshal(b, obj); err == nil { - return - } - return NewErrorResponse(ErrorDecodeArgs) -} - func (a *NewTxArgs) requirements() error { - if a.Recipient == "" { - return NewErrorResponse("Transact requires a 'recipient' address as argument") - } - if a.Value == "" { - return NewErrorResponse("Transact requires a 'value' as argument") - } if a.Gas == "" { return NewErrorResponse("Transact requires a 'gas' value as argument") } @@ -66,22 +49,6 @@ func (a *NewTxArgs) requirements() error { return nil } -func (a *NewTxArgs) requirementsContract() error { - if a.Value == "" { - return NewErrorResponse("Create requires a 'value' as argument") - } - if a.Gas == "" { - return NewErrorResponse("Create requires a 'gas' value as argument") - } - if a.GasPrice == "" { - return NewErrorResponse("Create requires a 'gasprice' value as argument") - } - if a.Body == "" { - return NewErrorResponse("Create requires a 'body' value as argument") - } - return nil -} - type PushTxArgs struct { Tx string `json:"tx"` } diff --git a/rpc/message.go b/rpc/message.go index 5785fcc87..e9f47634f 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -20,6 +20,7 @@ import ( "bytes" "encoding/json" "errors" + "fmt" ) const ( @@ -56,6 +57,14 @@ type RpcRequest struct { Params []json.RawMessage `json:"params"` } +func NewErrorResponse(msg string) error { + return errors.New(msg) +} + +func NewErrorResponseWithError(msg string, err error) error { + return fmt.Errorf("%s: %v", msg, err) +} + func (req *RpcRequest) ToSha3Args() (*Sha3Args, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) @@ -86,7 +95,7 @@ func (req *RpcRequest) ToGetBlockArgs() (*GetBlockArgs, error) { } func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { - if len(req.Params) < 7 { + if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) } @@ -94,7 +103,7 @@ func (req *RpcRequest) ToNewTxArgs() (*NewTxArgs, error) { r := bytes.NewReader(req.Params[0]) err := json.NewDecoder(r).Decode(args) if err != nil { - return nil, NewErrorResponse(ErrorDecodeArgs) + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) } rpclogger.DebugDetailf("%T %v", args, args) return args, nil @@ -175,7 +184,3 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return args, nil } - -func NewErrorResponse(msg string) error { - return errors.New(msg) -} diff --git a/rpc/packages.go b/rpc/packages.go index 2c5fbf6be..11a172bd6 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -67,7 +67,8 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data) + fmt.Println("result:", result) *reply = result return nil } @@ -78,7 +79,7 @@ func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Body) + result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Data) *reply = result return nil } @@ -210,6 +211,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.GetBlock(args, reply) + case "eth_transact": + args, err := req.ToNewTxArgs() + if err != nil { + return err + } + return p.Transact(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From b5918a1faa300773aef58528e51cda4a2ad42f6f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 12:06:47 +0100 Subject: removed create --- rpc/packages.go | 11 ----------- 1 file changed, 11 deletions(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 11a172bd6..3eaa71a7f 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -73,17 +73,6 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { return nil } -func (p *EthereumApi) Create(args *NewTxArgs, reply *interface{}) error { - err := args.requirementsContract() - if err != nil { - return err - } - - result, _ := p.xeth.Transact( /* TODO specify account */ "", args.Value, args.Gas, args.GasPrice, args.Data) - *reply = result - return nil -} - func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { err := args.requirementsPushTx() if err != nil { -- cgit v1.2.3 From 84adf77bf3492351de82f0ec820a1d280e85a5cd Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 13:10:34 +0100 Subject: Added RPC "Call" for JS calls to contracts --- rpc/args.go | 11 ++++++----- rpc/packages.go | 19 +++++++++++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 0c3087151..ff4974792 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -28,11 +28,12 @@ func (obj *GetBlockArgs) requirements() error { } type NewTxArgs struct { - Recipient string `json:"recipient"` - Value string `json:"value"` - Gas string `json:"gas"` - GasPrice string `json:"gasprice"` - Data string `json:"data"` + From string `json:"from"` + To string `json:"to"` + Value string `json:"value"` + Gas string `json:"gas"` + GasPrice string `json:"gasPrice"` + Data string `json:"data"` } // type TxResponse struct { diff --git a/rpc/packages.go b/rpc/packages.go index 3eaa71a7f..4302f6018 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -67,8 +67,17 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) error { if err != nil { return err } - result, _ := p.xeth.Transact( /* TODO specify account */ args.Recipient, args.Value, args.Gas, args.GasPrice, args.Data) - fmt.Println("result:", result) + result, _ := p.xeth.Transact( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + *reply = result + return nil +} + +func (p *EthereumApi) Call(args *NewTxArgs, reply *interface{}) error { + result, err := p.xeth.Call( /* TODO specify account */ args.To, args.Value, args.Gas, args.GasPrice, args.Data) + if err != nil { + return err + } + *reply = result return nil } @@ -206,6 +215,12 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.Transact(args, reply) + case "eth_call": + args, err := req.ToNewTxArgs() + if err != nil { + return err + } + return p.Call(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From ddf17d93acf92ef18b0134f19f22220362e06bad Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 14:46:59 +0100 Subject: Samples and disams cmd for evm code --- rpc/packages.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 4302f6018..b25660b25 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -35,6 +35,19 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) +func toHex(b []byte) string { + return "0x" + ethutil.Bytes2Hex(b) +} +func fromHex(s string) []byte { + if len(s) > 1 { + if s[0:2] == "0x" { + s = s[2:] + } + return ethutil.Hex2Bytes(s) + } + return nil +} + type RpcServer interface { Start() Stop() @@ -163,7 +176,7 @@ func (p *EthereumApi) GetCodeAt(args *GetCodeAtArgs, reply *interface{}) error { } func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { - *reply = ethutil.Bytes2Hex(crypto.Sha3(ethutil.Hex2Bytes(args.Data))) + *reply = toHex(crypto.Sha3(fromHex(args.Data))) return nil } -- cgit v1.2.3 From 6488a392a347d0d47212fdc78386e3e0e5841d7d Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 16:52:00 +0100 Subject: Reimplemented message filters for rpc calls --- rpc/args.go | 31 +++++++++++++++++--- rpc/message.go | 55 ++++++++++++++++++++++++++++++++++ rpc/packages.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 169 insertions(+), 8 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index ff4974792..79519e7d2 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 { BlockNumber int32 @@ -36,10 +37,6 @@ type NewTxArgs struct { Data string `json:"data"` } -// type TxResponse struct { -// Hash string -// } - func (a *NewTxArgs) requirements() error { if a.Gas == "" { return NewErrorResponse("Transact requires a 'gas' value as argument") @@ -195,3 +192,29 @@ func (obj *Sha3Args) UnmarshalJSON(b []byte) (err error) { } return } + +type FilterOptions struct { + Earliest int64 + Latest int64 + Address string + Topics []string + Skip int + Max int +} + +func toFilterOptions(options *FilterOptions) core.FilterOptions { + var opts core.FilterOptions + opts.Earliest = options.Earliest + opts.Latest = options.Latest + opts.Address = fromHex(options.Address) + opts.Topics = make([][]byte, len(options.Topics)) + for i, topic := range options.Topics { + opts.Topics[i] = fromHex(topic) + } + + return opts +} + +type FilterChangedArgs struct { + n int +} diff --git a/rpc/message.go b/rpc/message.go index e9f47634f..05f66ee95 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -21,6 +21,8 @@ import ( "encoding/json" "errors" "fmt" + + "github.com/ethereum/go-ethereum/state" ) const ( @@ -184,3 +186,56 @@ func (req *RpcRequest) ToGetCodeAtArgs() (*GetCodeAtArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return args, nil } + +func (req *RpcRequest) ToFilterArgs() (*FilterOptions, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(FilterOptions) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, 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) + } + + 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 +} + +type Log struct { + Address string `json:"address"` + Topics []string `json:"topics"` + Data string `json:"data"` +} + +func toLogs(logs state.Logs) (ls []Log) { + ls = make([]Log, len(logs)) + + for i, log := range logs { + var l Log + l.Topics = 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) + } + ls[i] = l + } + + return +} diff --git a/rpc/packages.go b/rpc/packages.go index b25660b25..e8dc570fd 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -29,9 +29,13 @@ import ( "fmt" "math/big" "strings" + "sync" + "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/event/filter" + "github.com/ethereum/go-ethereum/state" "github.com/ethereum/go-ethereum/xeth" ) @@ -53,12 +57,79 @@ type RpcServer interface { Stop() } +type EthereumApi struct { + xeth *xeth.XEth + filterManager *filter.FilterManager + + mut sync.RWMutex + logs map[int]state.Logs +} + func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { - return &EthereumApi{xeth: xeth} + api := &EthereumApi{ + xeth: xeth, + filterManager: filter.NewFilterManager(xeth.Backend().EventMux()), + logs: make(map[int]state.Logs), + } + go api.filterManager.Start() + + return api } -type EthereumApi struct { - xeth *xeth.XEth +func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) error { + var id int + filter := core.NewFilter(self.xeth.Backend()) + filter.LogsCallback = func(logs state.Logs) { + self.mut.Lock() + defer self.mut.Unlock() + + self.logs[id] = append(self.logs[id], logs...) + } + id = self.filterManager.InstallFilter(filter) + *reply = id + + return nil +} + +type Log struct { + Address string `json:"address"` + Topics []string `json:"topics"` + Data string `json:"data"` +} + +func toLogs(logs state.Logs) (ls []Log) { + ls = make([]Log, len(logs)) + + for i, log := range logs { + var l Log + l.Topics = 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) + } + ls[i] = l + } + + return +} + +func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { + self.mut.RLock() + defer self.mut.RUnlock() + + *reply = toLogs(self.logs[id]) + + self.logs[id] = nil // empty the logs + + return nil +} + +func (self *EthereumApi) Logs(id int, reply *interface{}) error { + filter := self.filterManager.GetFilter(id) + *reply = toLogs(filter.Find()) + + return nil } func (p *EthereumApi) GetBlock(args *GetBlockArgs, reply *interface{}) error { @@ -162,7 +233,7 @@ func (p *EthereumApi) GetBalanceAt(args *GetBalanceArgs, reply *interface{}) err return err } state := p.xeth.State().SafeGet(args.Address) - *reply = BalanceRes{Balance: state.Balance().String(), Address: args.Address} + *reply = toHex(state.Balance().Bytes()) return nil } @@ -234,6 +305,18 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.Call(args, reply) + case "eth_newFilter": + args, err := req.ToFilterArgs() + if err != nil { + return err + } + return p.NewFilter(args, reply) + case "eth_changed": + args, err := req.ToFilterChangedArgs() + if err != nil { + return err + } + return p.FilterChanged(args, reply) case "web3_sha3": args, err := req.ToSha3Args() if err != nil { -- cgit v1.2.3 From 89a48e365c6f401ed6e2b5fdbd5ab9ee9a91b033 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 29 Jan 2015 11:39:59 -0600 Subject: Cleanup --- rpc/json.go | 58 -------------------------------- rpc/message.go | 25 -------------- rpc/packages.go | 41 ---------------------- rpc/util.go | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ rpc/ws/server.go | 2 +- 5 files changed, 102 insertions(+), 125 deletions(-) delete mode 100644 rpc/json.go create mode 100644 rpc/util.go (limited to 'rpc') diff --git a/rpc/json.go b/rpc/json.go deleted file mode 100644 index 9bd204818..000000000 --- a/rpc/json.go +++ /dev/null @@ -1,58 +0,0 @@ -/* - 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 . -*/ -package rpc - -import ( - "encoding/json" - "github.com/ethereum/go-ethereum/logger" - "io" - "net/http" -) - -var rpclogger = logger.NewLogger("RPC") - -type JsonWrapper struct{} - -func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { - var payload []byte - payload, err = json.Marshal(v) - if err != nil { - rpclogger.Fatalln("Error marshalling JSON", err) - return 0, err - } - rpclogger.Infof("Sending payload: %s", payload) - - return writer.Write(payload) -} - -func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { - var reqParsed RpcRequest - - // Convert JSON to native types - d := json.NewDecoder(req.Body) - // d.UseNumber() - defer req.Body.Close() - err := d.Decode(&reqParsed) - - if err != nil { - rpclogger.Errorln("Error decoding JSON: ", err) - return reqParsed, err - } - rpclogger.DebugDetailf("Parsed request: %s", reqParsed) - - return reqParsed, nil -} diff --git a/rpc/message.go b/rpc/message.go index 05f66ee95..440bf4f8f 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -21,8 +21,6 @@ import ( "encoding/json" "errors" "fmt" - - "github.com/ethereum/go-ethereum/state" ) const ( @@ -216,26 +214,3 @@ func (req *RpcRequest) ToFilterChangedArgs() (int, error) { rpclogger.DebugDetailf("%T %v", id, id) return id, nil } - -type Log struct { - Address string `json:"address"` - Topics []string `json:"topics"` - Data string `json:"data"` -} - -func toLogs(logs state.Logs) (ls []Log) { - ls = make([]Log, len(logs)) - - for i, log := range logs { - var l Log - l.Topics = 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) - } - ls[i] = l - } - - return -} diff --git a/rpc/packages.go b/rpc/packages.go index e8dc570fd..53159d9ba 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -39,24 +39,6 @@ import ( "github.com/ethereum/go-ethereum/xeth" ) -func toHex(b []byte) string { - return "0x" + ethutil.Bytes2Hex(b) -} -func fromHex(s string) []byte { - if len(s) > 1 { - if s[0:2] == "0x" { - s = s[2:] - } - return ethutil.Hex2Bytes(s) - } - return nil -} - -type RpcServer interface { - Start() - Stop() -} - type EthereumApi struct { xeth *xeth.XEth filterManager *filter.FilterManager @@ -91,29 +73,6 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro return nil } -type Log struct { - Address string `json:"address"` - Topics []string `json:"topics"` - Data string `json:"data"` -} - -func toLogs(logs state.Logs) (ls []Log) { - ls = make([]Log, len(logs)) - - for i, log := range logs { - var l Log - l.Topics = 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) - } - ls[i] = l - } - - return -} - func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { self.mut.RLock() defer self.mut.RUnlock() diff --git a/rpc/util.go b/rpc/util.go new file mode 100644 index 000000000..bb4087c51 --- /dev/null +++ b/rpc/util.go @@ -0,0 +1,101 @@ +/* + 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 . +*/ +package rpc + +import ( + "encoding/json" + "github.com/ethereum/go-ethereum/logger" + "io" + "net/http" + "github.com/ethereum/go-ethereum/ethutil" + "github.com/ethereum/go-ethereum/state" +) + +var rpclogger = logger.NewLogger("RPC") + +type JsonWrapper struct{} + +func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) { + var payload []byte + payload, err = json.Marshal(v) + if err != nil { + rpclogger.Fatalln("Error marshalling JSON", err) + return 0, err + } + rpclogger.Infof("Sending payload: %s", payload) + + return writer.Write(payload) +} + +func (self JsonWrapper) ParseRequestBody(req *http.Request) (RpcRequest, error) { + var reqParsed RpcRequest + + // Convert JSON to native types + d := json.NewDecoder(req.Body) + // d.UseNumber() + defer req.Body.Close() + err := d.Decode(&reqParsed) + + if err != nil { + rpclogger.Errorln("Error decoding JSON: ", err) + return reqParsed, err + } + rpclogger.DebugDetailf("Parsed request: %s", reqParsed) + + return reqParsed, nil +} + +func toHex(b []byte) string { + return "0x" + ethutil.Bytes2Hex(b) +} +func fromHex(s string) []byte { + if len(s) > 1 { + if s[0:2] == "0x" { + s = s[2:] + } + return ethutil.Hex2Bytes(s) + } + return nil +} + +type RpcServer interface { + Start() + Stop() +} + +type Log struct { + Address string `json:"address"` + Topics []string `json:"topics"` + Data string `json:"data"` +} + +func toLogs(logs state.Logs) (ls []Log) { + ls = make([]Log, len(logs)) + + for i, log := range logs { + var l Log + l.Topics = 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) + } + ls[i] = l + } + + return +} diff --git a/rpc/ws/server.go b/rpc/ws/server.go index 37b08ebd9..2853181ec 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" -- cgit v1.2.3 From 0031f388ac1f6f4a23c5c75e5eeb4a007f0b2f31 Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 20:39:26 +0100 Subject: More dapp samples * Info DApp, coin DApp * Additional rpc methods --- rpc/args.go | 43 ++++++++++++++++++++--- rpc/message.go | 62 +++++++++++++++++++++++++++++++-- rpc/packages.go | 105 +++++++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 174 insertions(+), 36 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index 79519e7d2..aaa017c4e 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -69,10 +69,28 @@ func (a *PushTxArgs) requirementsPushTx() error { type GetStorageArgs struct { Address string - Key string } func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { + if err = json.Unmarshal(b, &obj.Address); err != nil { + return NewErrorResponse(ErrorDecodeArgs) + } + return +} + +func (a *GetStorageArgs) requirements() error { + if len(a.Address) == 0 { + return NewErrorResponse("GetStorageAt requires an 'address' value as argument") + } + return nil +} + +type GetStateArgs struct { + Address string + Key string +} + +func (obj *GetStateArgs) UnmarshalJSON(b []byte) (err error) { arg0 := "" if err = json.Unmarshal(b, arg0); err == nil { obj.Address = arg0 @@ -81,7 +99,7 @@ func (obj *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { return NewErrorResponse(ErrorDecodeArgs) } -func (a *GetStorageArgs) requirements() error { +func (a *GetStateArgs) requirements() error { if a.Address == "" { return NewErrorResponse("GetStorageAt requires an 'address' value as argument") } @@ -92,9 +110,8 @@ func (a *GetStorageArgs) requirements() error { } type GetStorageAtRes struct { - Key string `json:"key"` - Value string `json:"value"` - Address string `json:"address"` + Key string `json:"key"` + Value string `json:"value"` } type GetTxCountArgs struct { @@ -218,3 +235,19 @@ func toFilterOptions(options *FilterOptions) core.FilterOptions { type FilterChangedArgs struct { n int } + +type DbArgs struct { + Database string + Key string + Value string +} + +func (a *DbArgs) requirements() error { + if len(a.Database) == 0 { + return NewErrorResponse("DbPutArgs requires an 'Database' value as argument") + } + if len(a.Key) == 0 { + return NewErrorResponse("DbPutArgs requires an 'Key' value as argument") + } + return nil +} diff --git a/rpc/message.go b/rpc/message.go index 05f66ee95..a76eaece4 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -126,12 +126,12 @@ func (req *RpcRequest) ToPushTxArgs() (*PushTxArgs, error) { return args, nil } -func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) { - if len(req.Params) < 2 { +func (req *RpcRequest) ToGetStateArgs() (*GetStateArgs, error) { + if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) } - args := new(GetStorageArgs) + args := new(GetStateArgs) // TODO need to pass both arguments r := bytes.NewReader(req.Params[0]) err := json.NewDecoder(r).Decode(args) @@ -142,6 +142,21 @@ func (req *RpcRequest) ToGetStorageArgs() (*GetStorageArgs, error) { return args, nil } +func (req *RpcRequest) ToStorageAtArgs() (*GetStorageArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + args := new(GetStorageArgs) + r := bytes.NewReader(req.Params[0]) + err := json.NewDecoder(r).Decode(args) + if err != nil { + return nil, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", args, args) + return args, nil +} + func (req *RpcRequest) ToGetTxCountArgs() (*GetTxCountArgs, error) { if len(req.Params) < 1 { return nil, NewErrorResponse(ErrorArguments) @@ -239,3 +254,44 @@ func toLogs(logs state.Logs) (ls []Log) { return } + +func (req *RpcRequest) ToDbPutArgs() (*DbArgs, error) { + if len(req.Params) < 3 { + return nil, NewErrorResponse(ErrorArguments) + } + + var args DbArgs + err := json.Unmarshal(req.Params[0], &args.Database) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + err = json.Unmarshal(req.Params[1], &args.Key) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + err = json.Unmarshal(req.Params[2], &args.Value) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + rpclogger.DebugDetailf("%T %v", args, args) + return &args, nil +} + +func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) { + if len(req.Params) < 2 { + return nil, NewErrorResponse(ErrorArguments) + } + + var args DbArgs + err := json.Unmarshal(req.Params[0], &args.Database) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + + err = json.Unmarshal(req.Params[1], &args.Key) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + rpclogger.DebugDetailf("%T %v", args, args) + return &args, nil +} diff --git a/rpc/packages.go b/rpc/packages.go index e8dc570fd..2de1f06cd 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -33,6 +33,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethdb" "github.com/ethereum/go-ethereum/ethutil" "github.com/ethereum/go-ethereum/event/filter" "github.com/ethereum/go-ethereum/state" @@ -63,13 +64,17 @@ type EthereumApi struct { mut sync.RWMutex logs map[int]state.Logs + + db ethutil.Database } func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { + db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ xeth: xeth, filterManager: filter.NewFilterManager(xeth.Backend().EventMux()), logs: make(map[int]state.Logs), + db: db, } go api.filterManager.Start() @@ -91,29 +96,6 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro return nil } -type Log struct { - Address string `json:"address"` - Topics []string `json:"topics"` - Data string `json:"data"` -} - -func toLogs(logs state.Logs) (ls []Log) { - ls = make([]Log, len(logs)) - - for i, log := range logs { - var l Log - l.Topics = 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) - } - ls[i] = l - } - - return -} - func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { self.mut.RLock() defer self.mut.RUnlock() @@ -176,7 +158,7 @@ func (p *EthereumApi) PushTx(args *PushTxArgs, reply *interface{}) error { return nil } -func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error { +func (p *EthereumApi) GetStateAt(args *GetStateArgs, reply *interface{}) error { err := args.requirements() if err != nil { return err @@ -184,6 +166,7 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err state := p.xeth.State().SafeGet(args.Address) + value := state.StorageString(args.Key) var hx string if strings.Index(args.Key, "0x") == 0 { hx = string([]byte(args.Key)[2:]) @@ -192,9 +175,18 @@ func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) err i, _ := new(big.Int).SetString(args.Key, 10) hx = ethutil.Bytes2Hex(i.Bytes()) } - rpclogger.Debugf("GetStorageAt(%s, %s)\n", args.Address, hx) - value := state.Storage(ethutil.Hex2Bytes(hx)) - *reply = GetStorageAtRes{Address: args.Address, Key: args.Key, Value: value.Str()} + rpclogger.Debugf("GetStateAt(%s, %s)\n", args.Address, hx) + *reply = map[string]string{args.Key: value.Str()} + return nil +} + +func (p *EthereumApi) GetStorageAt(args *GetStorageArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } + + *reply = p.xeth.State().SafeGet(args.Address).Storage() return nil } @@ -213,11 +205,21 @@ func (p *EthereumApi) GetCoinbase(reply *interface{}) error { return nil } +func (p *EthereumApi) Accounts(reply *interface{}) error { + *reply = p.xeth.Accounts() + return nil +} + func (p *EthereumApi) GetIsMining(reply *interface{}) error { *reply = p.xeth.IsMining() return nil } +func (p *EthereumApi) BlockNumber(reply *interface{}) error { + *reply = p.xeth.Backend().ChainManager().CurrentBlock().Number() + return nil +} + func (p *EthereumApi) GetTxCountAt(args *GetTxCountArgs, reply *interface{}) error { err := args.requirements() if err != nil { @@ -251,6 +253,28 @@ func (p *EthereumApi) Sha3(args *Sha3Args, reply *interface{}) error { return nil } +func (p *EthereumApi) DbPut(args *DbArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } + + p.db.Put([]byte(args.Database+args.Key), []byte(args.Value)) + *reply = true + return nil +} + +func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error { + err := args.requirements() + if err != nil { + return err + } + + res, _ := p.db.Get([]byte(args.Database + args.Key)) + *reply = string(res) + return nil +} + func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) @@ -263,6 +287,10 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return p.GetIsMining(reply) case "eth_peerCount": return p.GetPeerCount(reply) + case "eth_number": + return p.BlockNumber(reply) + case "eth_accounts": + return p.Accounts(reply) case "eth_countAt": args, err := req.ToGetTxCountArgs() if err != nil { @@ -282,7 +310,13 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.GetBalanceAt(args, reply) case "eth_stateAt": - args, err := req.ToGetStorageArgs() + args, err := req.ToGetStateArgs() + if err != nil { + return err + } + return p.GetStateAt(args, reply) + case "eth_storageAt": + args, err := req.ToStorageAtArgs() if err != nil { return err } @@ -317,12 +351,27 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.FilterChanged(args, reply) + case "eth_gasPrice": + *reply = "1000000000000000" + return nil case "web3_sha3": args, err := req.ToSha3Args() if err != nil { return err } return p.Sha3(args, reply) + case "db_put": + args, err := req.ToDbPutArgs() + if err != nil { + return err + } + return p.DbPut(args, reply) + case "db_get": + args, err := req.ToDbGetArgs() + if err != nil { + return err + } + return p.DbGet(args, reply) default: return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) } -- cgit v1.2.3 From 9022f5034f952405d02f89c905104c80f0c13b8f Mon Sep 17 00:00:00 2001 From: obscuren Date: Thu, 29 Jan 2015 23:17:43 +0100 Subject: default values removed --- rpc/packages.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rpc') diff --git a/rpc/packages.go b/rpc/packages.go index 6136adf49..aa51aad42 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -334,7 +334,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.FilterChanged(args, reply) case "eth_gasPrice": - *reply = "1000000000000000" + *reply = "10000000000000" return nil case "web3_sha3": args, err := req.ToSha3Args() -- cgit v1.2.3 From c03d403437c20584bcbf3cf3fa9d79ac7a0a8ca7 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 Jan 2015 13:25:12 +0100 Subject: Added whisper interface for xeth, added examples, updated RPC * Added RPC methods for whisper * Added whisper example --- rpc/args.go | 9 +++++++ rpc/message.go | 44 +++++++++++++++++++++++++++++++ rpc/packages.go | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 124 insertions(+), 9 deletions(-) (limited to 'rpc') diff --git a/rpc/args.go b/rpc/args.go index aaa017c4e..75eef873d 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -251,3 +251,12 @@ func (a *DbArgs) requirements() error { } return nil } + +type WhisperMessageArgs struct { + Payload string + To string + From string + Topics []string + Priority uint32 + Ttl uint32 +} diff --git a/rpc/message.go b/rpc/message.go index 5045adb8f..919302921 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -21,6 +21,8 @@ import ( "encoding/json" "errors" "fmt" + + "github.com/ethereum/go-ethereum/xeth" ) const ( @@ -270,3 +272,45 @@ func (req *RpcRequest) ToDbGetArgs() (*DbArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return &args, nil } + +func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + var args xeth.Options + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return nil, NewErrorResponseWithError(ErrorDecodeArgs, err) + } + rpclogger.DebugDetailf("%T %v", args, args) + return &args, nil +} + +func (req *RpcRequest) ToWhisperChangedArgs() (int, error) { + if len(req.Params) < 1 { + return 0, NewErrorResponse(ErrorArguments) + } + + var id int + err := json.Unmarshal(req.Params[0], &id) + if err != nil { + return 0, NewErrorResponse(ErrorDecodeArgs) + } + rpclogger.DebugDetailf("%T %v", id, id) + return id, nil +} + +func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) { + if len(req.Params) < 1 { + return nil, NewErrorResponse(ErrorArguments) + } + + var args WhisperMessageArgs + err := json.Unmarshal(req.Params[0], &args) + if err != nil { + return nil, err + } + rpclogger.DebugDetailf("%T %v", args, args) + return &args, nil +} diff --git a/rpc/packages.go b/rpc/packages.go index aa51aad42..8344d6a46 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -44,18 +44,22 @@ type EthereumApi struct { xeth *xeth.XEth filterManager *filter.FilterManager - mut sync.RWMutex - logs map[int]state.Logs + logMut sync.RWMutex + logs map[int]state.Logs + + messagesMut sync.RWMutex + messages map[int][]xeth.WhisperMessage db ethutil.Database } -func NewEthereumApi(xeth *xeth.XEth) *EthereumApi { +func NewEthereumApi(eth *xeth.XEth) *EthereumApi { db, _ := ethdb.NewLDBDatabase("dapps") api := &EthereumApi{ - xeth: xeth, - filterManager: filter.NewFilterManager(xeth.Backend().EventMux()), + xeth: eth, + filterManager: filter.NewFilterManager(eth.Backend().EventMux()), logs: make(map[int]state.Logs), + messages: make(map[int][]xeth.WhisperMessage), db: db, } go api.filterManager.Start() @@ -67,8 +71,8 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro var id int filter := core.NewFilter(self.xeth.Backend()) filter.LogsCallback = func(logs state.Logs) { - self.mut.Lock() - defer self.mut.Unlock() + self.logMut.Lock() + defer self.logMut.Unlock() self.logs[id] = append(self.logs[id], logs...) } @@ -79,8 +83,8 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro } func (self *EthereumApi) FilterChanged(id int, reply *interface{}) error { - self.mut.RLock() - defer self.mut.RUnlock() + self.logMut.RLock() + defer self.logMut.RUnlock() *reply = toLogs(self.logs[id]) @@ -257,6 +261,44 @@ func (p *EthereumApi) DbGet(args *DbArgs, reply *interface{}) error { return nil } +func (p *EthereumApi) NewWhisperIdentity(reply *interface{}) error { + *reply = p.xeth.Whisper().NewIdentity() + return nil +} + +func (p *EthereumApi) NewWhisperFilter(args *xeth.Options, reply *interface{}) error { + var id int + args.Fn = func(msg xeth.WhisperMessage) { + p.messagesMut.Lock() + defer p.messagesMut.Unlock() + p.messages[id] = append(p.messages[id], msg) + } + id = p.xeth.Whisper().Watch(args) + *reply = id + return nil +} + +func (self *EthereumApi) MessagesChanged(id int, reply *interface{}) error { + self.messagesMut.RLock() + defer self.messagesMut.RUnlock() + + *reply = self.messages[id] + + self.messages[id] = nil // empty the messages + + return nil +} + +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) + if err != nil { + return err + } + + *reply = true + return nil +} + func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) @@ -354,6 +396,26 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error return err } return p.DbGet(args, reply) + case "shh_newIdentity": + return p.NewWhisperIdentity(reply) + case "shh_newFilter": + args, err := req.ToWhisperFilterArgs() + if err != nil { + return err + } + return p.NewWhisperFilter(args, reply) + case "shh_changed": + args, err := req.ToWhisperChangedArgs() + if err != nil { + return err + } + return p.MessagesChanged(args, reply) + case "shh_post": + args, err := req.ToWhisperPostArgs() + if err != nil { + return nil + } + return p.WhisperPost(args, reply) default: return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) } -- cgit v1.2.3 From af927ffdaf0c2c31047d22ab4a3163a4ef9d2342 Mon Sep 17 00:00:00 2001 From: obscuren Date: Fri, 30 Jan 2015 13:47:18 +0100 Subject: Added whisper messages * have identity & get messages --- rpc/message.go | 16 +++++++++++++++- rpc/packages.go | 26 ++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 3 deletions(-) (limited to 'rpc') diff --git a/rpc/message.go b/rpc/message.go index 919302921..26fac9d37 100644 --- a/rpc/message.go +++ b/rpc/message.go @@ -287,7 +287,7 @@ func (req *RpcRequest) ToWhisperFilterArgs() (*xeth.Options, error) { return &args, nil } -func (req *RpcRequest) ToWhisperChangedArgs() (int, error) { +func (req *RpcRequest) ToWhisperIdArgs() (int, error) { if len(req.Params) < 1 { return 0, NewErrorResponse(ErrorArguments) } @@ -314,3 +314,17 @@ func (req *RpcRequest) ToWhisperPostArgs() (*WhisperMessageArgs, error) { rpclogger.DebugDetailf("%T %v", args, args) return &args, nil } + +func (req *RpcRequest) ToWhisperHasIdentityArgs() (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 8344d6a46..06de5ca38 100644 --- a/rpc/packages.go +++ b/rpc/packages.go @@ -299,6 +299,16 @@ func (p *EthereumApi) WhisperPost(args *WhisperMessageArgs, reply *interface{}) return nil } +func (p *EthereumApi) HasWhisperIdentity(args string, reply *interface{}) error { + *reply = p.xeth.Whisper().HasIdentity(args) + return nil +} + +func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error { + *reply = p.xeth.Whisper().Messages(id) + return nil +} + func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error { // Spec at https://github.com/ethereum/wiki/wiki/Generic-ON-RPC rpclogger.DebugDetailf("%T %s", req.Params, req.Params) @@ -405,7 +415,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error } return p.NewWhisperFilter(args, reply) case "shh_changed": - args, err := req.ToWhisperChangedArgs() + args, err := req.ToWhisperIdArgs() if err != nil { return err } @@ -413,9 +423,21 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error case "shh_post": args, err := req.ToWhisperPostArgs() if err != nil { - return nil + return err } return p.WhisperPost(args, reply) + case "shh_haveIdentity": + args, err := req.ToWhisperHasIdentityArgs() + if err != nil { + return err + } + return p.HasWhisperIdentity(args, reply) + case "shh_getMessages": + args, err := req.ToWhisperIdArgs() + if err != nil { + return err + } + return p.WhisperMessages(args, reply) default: return NewErrorResponse(fmt.Sprintf("%v %s", ErrorNotImplemented, req.Method)) } -- cgit v1.2.3