diff options
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/api.go | 6 | ||||
-rw-r--r-- | rpc/args.go | 140 | ||||
-rw-r--r-- | rpc/util.go | 61 |
3 files changed, 86 insertions, 121 deletions
diff --git a/rpc/api.go b/rpc/api.go index 20e0e705c..0abed3c14 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -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 } @@ -455,7 +455,7 @@ func (p *EthereumApi) GetBlockUncleCountByNumber(blocknum int64) (int64, 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) @@ -484,7 +484,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 { diff --git a/rpc/args.go b/rpc/args.go index e2e987812..ab711e78f 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -8,27 +8,20 @@ import ( "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 - } - - // Second argument is optional (transact doesn't require it) - if len(data) > 1 { - if err = json.Unmarshal(data[1], str); err != nil { - return errDecodeArgs - } + switch str { + case "latest": + *number = -1 + case "pending": + *number = 0 + default: + *number = ethutil.String2Big(str).Int64() } - return nil } @@ -93,20 +86,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 } @@ -116,7 +101,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 } @@ -127,27 +111,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 v, ok := obj[1].(float64); ok { - args.BlockNumber = int64(v) - } else if obj[1].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() - } - } - return nil } @@ -165,27 +132,16 @@ 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 errArguments + return errDecodeArgs } - args.Address = obj[0].(string) - args.Key = obj[1].(string) - if len(obj) > 2 { - if v, ok := obj[2].(float64); ok { - args.BlockNumber = int64(v) - } else if obj[2].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = ethutil.Big(obj[2].(string)).Int64() - } - } + args.Address = obj[0] + args.Key = obj[1] return nil } @@ -207,28 +163,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 v, ok := obj[1].(float64); ok { - args.BlockNumber = int64(v) - } else if obj[1].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() - } - } - return nil } @@ -245,27 +183,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 v, ok := obj[1].(float64); ok { - args.BlockNumber = int64(v) - } else if obj[1].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() - } - } - return nil } @@ -282,27 +203,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 v, ok := obj[1].(float64); ok { - args.BlockNumber = int64(v) - } else if obj[1].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = ethutil.Big(obj[1].(string)).Int64() - } - } - return nil } diff --git a/rpc/util.go b/rpc/util.go index 69c7b629f..fb4efdb45 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -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() |