Browse Source

begin conversion to rpc over http

Per specification at
https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
Taylor Gerring 10 years ago
parent
commit
32bed50ba1
5 changed files with 438 additions and 263 deletions
  1. 67 0
      rpc/json.go
  2. 163 8
      rpc/message.go
  3. 175 168
      rpc/packages.go
  4. 33 12
      rpc/server.go
  5. 0 75
      rpc/writer.go

+ 67 - 0
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

+ 163 - 8
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)
 }

+ 175 - 168
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
+// }

+ 33 - 12
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)
+}

+ 0 - 75
rpc/writer.go

@@ -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
-	}
-}
-*/