Updated RPC

* Added a generic RawMessage deserialiser
* Updated ethereum.js
* Updated coin test app
This commit is contained in:
obscuren
2015-03-10 20:14:38 +01:00
parent bbe8b18660
commit f22684439a
5 changed files with 152 additions and 136 deletions

View File

@ -165,7 +165,7 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro
id = self.filterManager.InstallFilter(filter)
self.logs[id] = &logFilter{timeout: time.Now()}
*reply = id
*reply = i2hex(id)
return nil
}
@ -417,7 +417,7 @@ func (p *EthereumApi) WhisperMessages(id int, reply *interface{}) error {
func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error {
// Spec at https://github.com/ethereum/wiki/wiki/Generic-JSON-RPC
rpclogger.DebugDetailf("%T %s", req.Params, req.Params)
rpclogger.Infof("%s %s", req.Method, req.Params)
switch req.Method {
case "web3_sha3":
args := new(Sha3Args)
@ -446,7 +446,7 @@ func (p *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) error
return err
}
return p.GetBalance(args, reply)
case "eth_getStorage":
case "eth_getStorage", "eth_storageAt":
// TODO handle BlockNumber
args := new(GetStorageArgs)
if err := json.Unmarshal(req.Params, &args); err != nil {

View File

@ -3,32 +3,26 @@ package rpc
import (
"bytes"
"encoding/json"
"fmt"
"math/big"
"github.com/ethereum/go-ethereum/ethutil"
)
// Unmarshal state is a helper method which has the ability to decode messsages
// that use the `defaultBlock` (https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter)
// For example a `call`: [{to: "0x....", data:"0x..."}, "latest"]. The first argument is the transaction
// message and the second one refers to the block height (or state) to which to apply this `call`.
func unmarshalState(b []byte, iface interface{}, str *string) (err error) {
var data []json.RawMessage
if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
func blockNumber(raw json.RawMessage, number *int64) (err error) {
var str string
if err = json.Unmarshal(raw, &str); err != nil {
return errDecodeArgs
}
if err = json.Unmarshal(data[0], iface); err != nil {
return errDecodeArgs
switch str {
case "latest":
*number = -1
case "pending":
*number = 0
default:
*number = ethutil.String2Big(str).Int64()
}
// Second argument is optional (transact doesn't require it)
if len(data) > 1 {
if err = json.Unmarshal(data[1], str); err != nil {
return errDecodeArgs
}
}
return nil
}
@ -88,20 +82,12 @@ type NewTxArgs struct {
GasPrice *big.Int
Data string
BlockHeight string
BlockNumber int64
}
func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
var obj struct {
From string `json:"from"`
To string `json:"to"`
Value string `json:"value"`
Gas string `json:"gas"`
GasPrice string `json:"gasPrice"`
Data string `json:"data"`
}
var height string
if err = unmarshalState(b, &obj, &height); err != nil {
var obj struct{ From, To, Value, Gas, GasPrice, Data string }
if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return err
}
@ -111,7 +97,6 @@ func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) {
args.Gas = ethutil.Big(obj.Gas)
args.GasPrice = ethutil.Big(obj.GasPrice)
args.Data = obj.Data
args.BlockHeight = height
return nil
}
@ -122,24 +107,10 @@ type GetStorageArgs struct {
}
func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.Address = obj[0].(string)
if len(obj) > 1 {
if obj[1].(string) == "latest" {
args.BlockNumber = -1
} else {
args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
}
}
fmt.Println(args)
return nil
}
@ -158,25 +129,18 @@ type GetStorageAtArgs struct {
}
func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
var obj []string
if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil {
return errDecodeArgs
}
if len(obj) < 2 {
return errDecodeArgs
}
if len(obj) < 2 {
return errArguments
}
args.Address = obj[0].(string)
args.Key = obj[1].(string)
args.Address = obj[0]
args.Key = obj[1]
if len(obj) > 2 {
if obj[2].(string) == "latest" {
args.BlockNumber = -1
} else {
args.BlockNumber = ethutil.Big(obj[2].(string)).Int64()
}
}
fmt.Println(args)
return nil
}
@ -198,26 +162,10 @@ type GetTxCountArgs struct {
}
func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.Address = obj[0].(string)
if len(obj) > 1 {
if obj[1].(string) == "latest" {
args.BlockNumber = -1
} else {
args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
}
}
return nil
}
@ -234,25 +182,10 @@ type GetBalanceArgs struct {
}
func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.Address = obj[0].(string)
if len(obj) > 1 {
if obj[1].(string) == "latest" {
args.BlockNumber = -1
} else {
args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
}
}
return nil
}
@ -269,25 +202,10 @@ type GetDataArgs struct {
}
func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) {
var obj []interface{}
r := bytes.NewReader(b)
if err := json.NewDecoder(r).Decode(&obj); err != nil {
if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil {
return errDecodeArgs
}
if len(obj) < 1 {
return errArguments
}
args.Address = obj[0].(string)
if len(obj) > 1 {
if obj[1].(string) == "latest" {
args.BlockNumber = -1
} else {
args.BlockNumber = ethutil.Big(obj[1].(string)).Int64()
}
}
return nil
}

View File

@ -18,8 +18,11 @@ package rpc
import (
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"reflect"
"time"
"github.com/ethereum/go-ethereum/ethutil"
@ -32,6 +35,60 @@ var rpclogger = logger.NewLogger("RPC")
type JsonWrapper struct{}
// Unmarshal state is a helper method which has the ability to decode messsages
// that use the `defaultBlock` (https://github.com/ethereum/wiki/wiki/JSON-RPC#the-default-block-parameter)
// For example a `call`: [{to: "0x....", data:"0x..."}, "latest"]. The first argument is the transaction
// message and the second one refers to the block height (or state) to which to apply this `call`.
func UnmarshalRawMessages(b []byte, iface interface{}, number *int64) (err error) {
var data []json.RawMessage
if err = json.Unmarshal(b, &data); err != nil && len(data) == 0 {
return errDecodeArgs
}
// Number index determines the index in the array for a possible block number
numberIndex := 0
value := reflect.ValueOf(iface)
rvalue := reflect.Indirect(value)
switch rvalue.Kind() {
case reflect.Slice:
// This is a bit of a cheat, but `data` is expected to be larger than 2 if iface is a slice
if number != nil {
numberIndex = len(data) - 1
} else {
numberIndex = len(data)
}
slice := reflect.MakeSlice(rvalue.Type(), numberIndex, numberIndex)
for i, raw := range data[0:numberIndex] {
v := slice.Index(i).Interface()
if err = json.Unmarshal(raw, &v); err != nil {
fmt.Println(err, v)
return err
}
slice.Index(i).Set(reflect.ValueOf(v))
}
reflect.Indirect(rvalue).Set(slice) //value.Set(slice)
case reflect.Struct:
fallthrough
default:
if err = json.Unmarshal(data[0], iface); err != nil {
return errDecodeArgs
}
numberIndex = 1
}
// <0 index means out of bound for block number
if numberIndex >= 0 && len(data) > numberIndex {
if err = blockNumber(data[numberIndex], number); err != nil {
return errDecodeArgs
}
}
return nil
}
func (self JsonWrapper) Send(writer io.Writer, v interface{}) (n int, err error) {
var payload []byte
payload, err = json.Marshal(v)
@ -80,6 +137,10 @@ func fromHex(s string) []byte {
return nil
}
func i2hex(n int) string {
return toHex(big.NewInt(int64(n)).Bytes())
}
type RpcServer interface {
Start()
Stop()