diff options
author | obscuren <geffobscura@gmail.com> | 2015-03-19 23:59:13 +0800 |
---|---|---|
committer | obscuren <geffobscura@gmail.com> | 2015-03-19 23:59:13 +0800 |
commit | b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1 (patch) | |
tree | 9d94b69006029e91d7cdf2d0eb9d6d457d238671 /rpc | |
parent | ce063e8d9c2d26dd283a43b097903628225179ea (diff) | |
parent | e540a75030de611ca8cf0a70621421b6aa3fbebf (diff) | |
download | go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar.gz go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar.bz2 go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar.lz go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar.xz go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.tar.zst go-tangerine-b5a71d955cacec0c8f81fbcf36b6f3d6d60b4bb1.zip |
merge
Diffstat (limited to 'rpc')
-rw-r--r-- | rpc/api.go | 24 | ||||
-rw-r--r-- | rpc/args.go | 194 | ||||
-rw-r--r-- | rpc/args_test.go | 80 | ||||
-rw-r--r-- | rpc/util.go | 72 |
4 files changed, 227 insertions, 143 deletions
diff --git a/rpc/api.go b/rpc/api.go index 486eec008..02c640661 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -86,7 +86,7 @@ func (self *EthereumApi) getStateWithNum(num int64) *xeth.State { } func (self *EthereumApi) start() { - timer := time.NewTicker(filterTickerTime) + timer := time.NewTicker(2 * time.Second) done: for { select { @@ -94,20 +94,20 @@ done: self.logMut.Lock() self.messagesMut.Lock() for id, filter := range self.logs { - if time.Since(filter.timeout) > 20*time.Second { + if time.Since(filter.timeout) > filterTickerTime { self.filterManager.UninstallFilter(id) delete(self.logs, id) } } for id, filter := range self.messages { - if time.Since(filter.timeout) > 20*time.Second { + if time.Since(filter.timeout) > filterTickerTime { self.xeth().Whisper().Unwatch(id) delete(self.messages, id) } } - self.logMut.Unlock() self.messagesMut.Unlock() + self.logMut.Unlock() case <-self.quit: break done } @@ -161,7 +161,7 @@ func (self *EthereumApi) NewFilter(args *FilterOptions, reply *interface{}) erro id = self.filterManager.InstallFilter(filter) self.logs[id] = &logFilter{timeout: time.Now()} - *reply = i2hex(id) + *reply = common.ToHex(big.NewInt(int64(id)).Bytes()) return nil } @@ -180,10 +180,13 @@ func (self *EthereumApi) NewFilterString(args *FilterStringArgs, reply *interfac var id int filter := core.NewFilter(self.xeth().Backend()) - callback := func(block *types.Block) { + callback := func(block *types.Block, logs state.Logs) { self.logMut.Lock() defer self.logMut.Unlock() + for _, log := range logs { + self.logs[id].add(log) + } self.logs[id].add(&state.StateLog{}) } @@ -198,7 +201,7 @@ func (self *EthereumApi) NewFilterString(args *FilterStringArgs, reply *interfac id = self.filterManager.InstallFilter(filter) self.logs[id] = &logFilter{timeout: time.Now()} - *reply = i2hex(id) + *reply = common.ToHex(big.NewInt(int64(id)).Bytes()) return nil } @@ -257,6 +260,11 @@ func (p *EthereumApi) Transact(args *NewTxArgs, reply *interface{}) (err error) p.register[ags.From] = append(p.register[args.From], args) } */ + + if err := args.requirements(); err != nil { + return err + } + // TODO: align default values to have the same type, e.g. not depend on // common.Value conversions later on if args.Gas.Cmp(big.NewInt(0)) == 0 { @@ -478,7 +486,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.Debugf("%s %s", req.Method, req.Params) + rpclogger.Infof("%s %s", req.Method, req.Params) switch req.Method { case "web3_sha3": args := new(Sha3Args) diff --git a/rpc/args.go b/rpc/args.go index fee44c4e0..ab1c40585 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -8,10 +8,18 @@ import ( "github.com/ethereum/go-ethereum/common" ) -func blockNumber(raw json.RawMessage, number *int64) (err error) { - var str string - if err = json.Unmarshal(raw, &str); err != nil { - return NewDecodeParamError(err.Error()) +func blockAge(raw interface{}, number *int64) (err error) { + // Parse as integer + num, ok := raw.(float64) + if ok { + *number = int64(num) + return nil + } + + // Parse as string/hexstring + str, ok := raw.(string) + if !ok { + return NewDecodeParamError("BlockNumber is not a string") } switch str { @@ -22,6 +30,7 @@ func blockNumber(raw json.RawMessage, number *int64) (err error) { default: *number = common.String2Big(str).Int64() } + return nil } @@ -95,18 +104,51 @@ type NewTxArgs struct { } func (args *NewTxArgs) UnmarshalJSON(b []byte) (err error) { - var obj struct{ From, To, Value, Gas, GasPrice, Data string } - if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil { - return err + var obj []json.RawMessage + var ext struct{ From, To, Value, Gas, GasPrice, Data string } + + // Decode byte slice to array of RawMessages + if err := json.Unmarshal(b, &obj); err != nil { + return NewDecodeParamError(err.Error()) + } + + // Check for sufficient params + if len(obj) < 1 { + return NewInsufficientParamsError(len(obj), 1) + } + + // Decode 0th RawMessage to temporary struct + if err := json.Unmarshal(obj[0], &ext); err != nil { + return NewDecodeParamError(err.Error()) + } + + // var ok bool + args.From = ext.From + args.To = ext.To + args.Value = common.String2Big(ext.Value) + args.Gas = common.String2Big(ext.Gas) + args.GasPrice = common.String2Big(ext.GasPrice) + args.Data = ext.Data + + // Check for optional BlockNumber param + if len(obj) > 1 { + var raw interface{} + if err = json.Unmarshal(obj[1], &raw); err != nil { + return NewDecodeParamError(err.Error()) + } + + if err := blockAge(raw, &args.BlockNumber); err != nil { + return err + } } - args.From = obj.From - args.To = obj.To - args.Value = common.Big(obj.Value) - args.Gas = common.Big(obj.Gas) - args.GasPrice = common.Big(obj.GasPrice) - args.Data = obj.Data + return nil +} +func (args *NewTxArgs) requirements() error { + if len(args.From) == 0 { + return NewValidationError("From", "Is required") + } return nil } @@ -116,10 +158,27 @@ type GetStorageArgs struct { } func (args *GetStorageArgs) UnmarshalJSON(b []byte) (err error) { - if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { return NewDecodeParamError(err.Error()) } + if len(obj) < 1 { + return NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return NewDecodeParamError("Address is not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockAge(obj[1], &args.BlockNumber); err != nil { + return err + } + } + return nil } @@ -137,16 +196,32 @@ type GetStorageAtArgs struct { } func (args *GetStorageAtArgs) UnmarshalJSON(b []byte) (err error) { - var obj []string - if err = UnmarshalRawMessages(b, &obj, &args.BlockNumber); err != nil { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { return NewDecodeParamError(err.Error()) } + if len(obj) < 2 { return NewInsufficientParamsError(len(obj), 2) } - args.Address = obj[0] - args.Key = obj[1] + addstr, ok := obj[0].(string) + if !ok { + return NewDecodeParamError("Address is not a string") + } + args.Address = addstr + + keystr, ok := obj[1].(string) + if !ok { + return NewDecodeParamError("Key is not a string") + } + args.Key = keystr + + if len(obj) > 2 { + if err := blockAge(obj[2], &args.BlockNumber); err != nil { + return err + } + } return nil } @@ -168,10 +243,27 @@ type GetTxCountArgs struct { } func (args *GetTxCountArgs) UnmarshalJSON(b []byte) (err error) { - if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { return NewDecodeParamError(err.Error()) } + if len(obj) < 1 { + return NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return NewDecodeParamError("Address is not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockAge(obj[1], &args.BlockNumber); err != nil { + return err + } + } + return nil } @@ -189,8 +281,7 @@ 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 := json.Unmarshal(b, &obj); err != nil { return NewDecodeParamError(err.Error()) } @@ -205,17 +296,11 @@ func (args *GetBalanceArgs) UnmarshalJSON(b []byte) (err error) { args.Address = addstr if len(obj) > 1 { - if obj[1].(string) == "latest" { - args.BlockNumber = -1 - } else { - args.BlockNumber = common.Big(obj[1].(string)).Int64() + if err := blockAge(obj[1], &args.BlockNumber); err != nil { + return err } } - // if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil { - // return NewDecodeParamError(err.Error()) - // } - return nil } @@ -232,10 +317,27 @@ type GetDataArgs struct { } func (args *GetDataArgs) UnmarshalJSON(b []byte) (err error) { - if err = UnmarshalRawMessages(b, &args.Address, &args.BlockNumber); err != nil { + var obj []interface{} + if err := json.Unmarshal(b, &obj); err != nil { return NewDecodeParamError(err.Error()) } + if len(obj) < 1 { + return NewInsufficientParamsError(len(obj), 1) + } + + addstr, ok := obj[0].(string) + if !ok { + return NewDecodeParamError("Address is not a string") + } + args.Address = addstr + + if len(obj) > 1 { + if err := blockAge(obj[1], &args.BlockNumber); err != nil { + return err + } + } + return nil } @@ -392,10 +494,6 @@ func (args *FilterOptions) UnmarshalJSON(b []byte) (err error) { return nil } -// type FilterChangedArgs struct { -// n int -// } - type DbArgs struct { Database string Key string @@ -578,31 +676,3 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { return nil } - -// func (req *RpcRequest) ToRegisterArgs() (string, error) { -// if len(req.Params) < 1 { -// return "", errArguments -// } - -// var args string -// err := json.Unmarshal(req.Params, &args) -// if err != nil { -// return "", err -// } - -// return args, nil -// } - -// func (req *RpcRequest) ToWatchTxArgs() (string, error) { -// if len(req.Params) < 1 { -// return "", errArguments -// } - -// var args string -// err := json.Unmarshal(req.Params, &args) -// if err != nil { -// return "", err -// } - -// return args, nil -// } diff --git a/rpc/args_test.go b/rpc/args_test.go index 61b9dad25..0d8dc4085 100644 --- a/rpc/args_test.go +++ b/rpc/args_test.go @@ -43,6 +43,30 @@ func TestGetBalanceArgs(t *testing.T) { } } +func TestGetBalanceArgsLatest(t *testing.T) { + input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]` + expected := new(GetBalanceArgs) + expected.Address = "0x407d73d8a49eeb85d32cf465507dd71d507100c1" + expected.BlockNumber = -1 + + args := new(GetBalanceArgs) + if err := json.Unmarshal([]byte(input), &args); err != nil { + t.Error(err) + } + + if err := args.requirements(); err != nil { + t.Error(err) + } + + if args.Address != expected.Address { + t.Errorf("Address should be %v but is %v", expected.Address, args.Address) + } + + if args.BlockNumber != expected.BlockNumber { + t.Errorf("BlockNumber should be %v but is %v", expected.BlockNumber, args.BlockNumber) + } +} + func TestGetBalanceEmptyArgs(t *testing.T) { input := `[]` @@ -120,7 +144,8 @@ func TestNewTxArgs(t *testing.T) { "gas": "0x76c0", "gasPrice": "0x9184e72a000", "value": "0x9184e72a000", - "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}]` + "data": "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675"}, + "0x10"]` expected := new(NewTxArgs) expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" expected.To = "0xd46e8dd67c5d32be8058bb8eb970870f072445675" @@ -128,6 +153,7 @@ func TestNewTxArgs(t *testing.T) { expected.GasPrice = big.NewInt(10000000000000) expected.Value = big.NewInt(10000000000000) expected.Data = "0xd46e8dd67c5d32be8d46e8dd67c5d32be8058bb8eb970870f072445675058bb8eb970870f072445675" + expected.BlockNumber = big.NewInt(16).Int64() args := new(NewTxArgs) if err := json.Unmarshal([]byte(input), &args); err != nil { @@ -157,6 +183,30 @@ func TestNewTxArgs(t *testing.T) { if expected.Data != args.Data { t.Errorf("Data shoud be %#v but is %#v", expected.Data, args.Data) } + + if expected.BlockNumber != args.BlockNumber { + t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) + } +} + +func TestNewTxArgsBlockInt(t *testing.T) { + input := `[{"from": "0xb60e8dd61c5d32be8058bb8eb970870f07233155"}, 5]` + expected := new(NewTxArgs) + expected.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" + expected.BlockNumber = big.NewInt(5).Int64() + + args := new(NewTxArgs) + if err := json.Unmarshal([]byte(input), &args); err != nil { + t.Error(err) + } + + if expected.From != args.From { + t.Errorf("From shoud be %#v but is %#v", expected.From, args.From) + } + + if expected.BlockNumber != args.BlockNumber { + t.Errorf("BlockNumber shoud be %#v but is %#v", expected.BlockNumber, args.BlockNumber) + } } func TestNewTxArgsEmpty(t *testing.T) { @@ -169,6 +219,34 @@ func TestNewTxArgsEmpty(t *testing.T) { } } +func TestNewTxArgsReqs(t *testing.T) { + args := new(NewTxArgs) + args.From = "0xb60e8dd61c5d32be8058bb8eb970870f07233155" + + err := args.requirements() + switch err.(type) { + case nil: + break + default: + t.Errorf("Get %T", err) + } +} + +func TestNewTxArgsReqsFromBlank(t *testing.T) { + args := new(NewTxArgs) + args.From = "" + + err := args.requirements() + switch err.(type) { + case nil: + t.Error("Expected error but didn't get one") + case *ValidationError: + break + default: + t.Error("Wrong type of error") + } +} + func TestGetStorageArgs(t *testing.T) { input := `["0x407d73d8a49eeb85d32cf465507dd71d507100c1", "latest"]` expected := new(GetStorageArgs) diff --git a/rpc/util.go b/rpc/util.go index b3d83409f..724c8b503 100644 --- a/rpc/util.go +++ b/rpc/util.go @@ -17,10 +17,6 @@ package rpc import ( - "encoding/json" - "fmt" - "math/big" - "reflect" "time" "github.com/ethereum/go-ethereum/common" @@ -31,74 +27,6 @@ import ( var rpclogger = logger.NewLogger("RPC") -// 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 NewDecodeParamError(err.Error()) - } - - // Hrm... Occurs when no params - if len(data) == 0 { - return NewDecodeParamError("No data") - } - - // 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 NewDecodeParamError(err.Error()) - } - 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 NewDecodeParamError(err.Error()) - } - } - - return nil -} - -func i2hex(n int) string { - return common.ToHex(big.NewInt(int64(n)).Bytes()) -} - -type RpcServer interface { - Start() - Stop() -} - type Log struct { Address string `json:"address"` Topic []string `json:"topic"` |