From b9c9d6d798b26942d69ec9d3c3e88a1b8f563fb6 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 14:37:11 +0200 Subject: [PATCH 01/10] Use HashArgs for eth_getTransactionByHash --- rpc/api.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index 5e27890cef..8cc86103b6 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -192,8 +192,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err *reply = br case "eth_getTransactionByHash": - // HashIndexArgs used, but only the "Hash" part we need. - args := new(HashIndexArgs) + args := new(HashArgs) if err := json.Unmarshal(req.Params, &args); err != nil { } tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash) From 172b34351aeb03d0318d241c0941c27608448cfb Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 14:49:33 +0200 Subject: [PATCH 02/10] HashArgs fix + tests --- rpc/api.go | 1 + rpc/args_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/rpc/api.go b/rpc/api.go index 8cc86103b6..ee2a6a0473 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -194,6 +194,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err case "eth_getTransactionByHash": args := new(HashArgs) if err := json.Unmarshal(req.Params, &args); err != nil { + return err } tx, bhash, bnum, txi := api.xeth().EthTransactionByHash(args.Hash) if tx != nil { diff --git a/rpc/args_test.go b/rpc/args_test.go index 902f8013e4..0ac8f657bb 100644 --- a/rpc/args_test.go +++ b/rpc/args_test.go @@ -2090,6 +2090,51 @@ func TestHashIndexArgsInvalidIndex(t *testing.T) { } } +func TestHashArgs(t *testing.T) { + input := `["0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b"]` + expected := new(HashIndexArgs) + expected.Hash = "0xc6ef2fc5426d6ad6fd9e2a26abeab0aa2411b7ab17f30a99d3cb96aed1d1055b" + + args := new(HashArgs) + if err := json.Unmarshal([]byte(input), &args); err != nil { + t.Error(err) + } + + if expected.Hash != args.Hash { + t.Errorf("Hash shoud be %#v but is %#v", expected.Hash, args.Hash) + } +} + +func TestHashArgsEmpty(t *testing.T) { + input := `[]` + + args := new(HashArgs) + str := ExpectInsufficientParamsError(json.Unmarshal([]byte(input), &args)) + if len(str) > 0 { + t.Error(str) + } +} + +func TestHashArgsInvalid(t *testing.T) { + input := `{}` + + args := new(HashArgs) + str := ExpectDecodeParamError(json.Unmarshal([]byte(input), &args)) + if len(str) > 0 { + t.Error(str) + } +} + +func TestHashArgsInvalidHash(t *testing.T) { + input := `[7]` + + args := new(HashArgs) + str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), &args)) + if len(str) > 0 { + t.Error(str) + } +} + func TestSubmitWorkArgs(t *testing.T) { input := `["0x0000000000000001", "0x1234567890abcdef1234567890abcdef", "0xD1GE5700000000000000000000000000"]` expected := new(SubmitWorkArgs) From 876ce0fb12d7c1eae2907dad9ea13d01e9b3ac17 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 14:54:28 +0200 Subject: [PATCH 03/10] More nil checks --- rpc/api.go | 6 ++++++ rpc/responses.go | 6 ++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index ee2a6a0473..b46151cda4 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -212,6 +212,9 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err block := api.xeth().EthBlockByHash(args.Hash) br := NewBlockRes(block, true) + if br == nil { + *reply = nil + } if args.Index >= int64(len(br.Transactions)) || args.Index < 0 { return NewValidationError("Index", "does not exist") @@ -225,6 +228,9 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err block := api.xeth().EthBlockByNumber(args.BlockNumber) v := NewBlockRes(block, true) + if v == nil { + *reply = nil + } if args.Index >= int64(len(v.Transactions)) || args.Index < 0 { return NewValidationError("Index", "does not exist") diff --git a/rpc/responses.go b/rpc/responses.go index 3d1687cb68..079ee87655 100644 --- a/rpc/responses.go +++ b/rpc/responses.go @@ -125,8 +125,6 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { } func NewBlockRes(block *types.Block, fullTx bool) *BlockRes { - // TODO respect fullTx flag - if block == nil { return nil } @@ -182,6 +180,10 @@ type TransactionRes struct { } func NewTransactionRes(tx *types.Transaction) *TransactionRes { + if tx == nil { + return nil + } + var v = new(TransactionRes) v.Hash = newHexData(tx.Hash()) v.Nonce = newHexNum(tx.Nonce()) From 39085905783829161738207271aa35386f6ebc72 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 15:37:35 +0200 Subject: [PATCH 04/10] Make "To" field optional in whisper filter --- rpc/args.go | 13 ++++++++----- rpc/args_test.go | 25 +++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/rpc/args.go b/rpc/args.go index 70618a01a4..a8cb7dcb16 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -1021,12 +1021,15 @@ func (args *WhisperFilterArgs) UnmarshalJSON(b []byte) (err error) { return NewInsufficientParamsError(len(obj), 1) } - var argstr string - argstr, ok := obj[0].To.(string) - if !ok { - return NewInvalidTypeError("to", "is not a string") + if obj[0].To == nil { + args.To = "" + } else { + argstr, ok := obj[0].To.(string) + if !ok { + return NewInvalidTypeError("to", "is not a string") + } + args.To = argstr } - args.To = argstr t := make([]string, len(obj[0].Topics)) for i, j := range obj[0].Topics { diff --git a/rpc/args_test.go b/rpc/args_test.go index 0ac8f657bb..b88bab2805 100644 --- a/rpc/args_test.go +++ b/rpc/args_test.go @@ -1805,6 +1805,16 @@ func TestWhisperFilterArgsEmpty(t *testing.T) { } } +func TestWhisperFilterArgsToInt(t *testing.T) { + input := `[{"to": 2}]` + + args := new(WhisperFilterArgs) + str := ExpectInvalidTypeError(json.Unmarshal([]byte(input), args)) + if len(str) > 0 { + t.Error(str) + } +} + func TestWhisperFilterArgsToBool(t *testing.T) { input := `[{"topics": ["0x68656c6c6f20776f726c64"], "to": false}]` @@ -1815,6 +1825,21 @@ func TestWhisperFilterArgsToBool(t *testing.T) { } } +func TestWhisperFilterArgsToMissing(t *testing.T) { + input := `[{"topics": ["0x68656c6c6f20776f726c64"]}]` + expected := new(WhisperFilterArgs) + expected.To = "" + + args := new(WhisperFilterArgs) + if err := json.Unmarshal([]byte(input), &args); err != nil { + t.Error(err) + } + + if args.To != expected.To { + t.Errorf("To shoud be %v but is %v", expected.To, args.To) + } +} + func TestWhisperFilterArgsTopicInt(t *testing.T) { input := `[{"topics": [6], "to": "0x34ag445g3455b34"}]` From aa71e27a3b0f42b980082c52232c68fb50a45052 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 15:53:04 +0200 Subject: [PATCH 05/10] Detect non-valid strings for blockheight --- common/bytes.go | 5 +++++ rpc/args.go | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/common/bytes.go b/common/bytes.go index 2d885ac746..5bdacd810a 100644 --- a/common/bytes.go +++ b/common/bytes.go @@ -127,6 +127,11 @@ func CopyBytes(b []byte) (copiedBytes []byte) { return } +func HasHexPrefix(str string) bool { + l := len(str) + return l >= 2 && str[0:2] == "0x" +} + func IsHex(str string) bool { l := len(str) return l >= 4 && l%2 == 0 && str[0:2] == "0x" diff --git a/rpc/args.go b/rpc/args.go index a8cb7dcb16..cebabf4ba9 100644 --- a/rpc/args.go +++ b/rpc/args.go @@ -41,7 +41,11 @@ func blockHeight(raw interface{}, number *int64) error { case "pending": *number = -2 default: - *number = common.String2Big(str).Int64() + if common.HasHexPrefix(str) { + *number = common.String2Big(str).Int64() + } else { + return NewInvalidTypeError("blockNumber", "is not a valid string") + } } return nil From e882ba0c29a4e616113a4c16e6ea08b8a8abf06b Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 16:11:00 +0200 Subject: [PATCH 06/10] Return nil when requested index does not exist Instead of error --- rpc/api.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index b46151cda4..4ce2a98e2e 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -217,9 +217,11 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } if args.Index >= int64(len(br.Transactions)) || args.Index < 0 { - return NewValidationError("Index", "does not exist") + // return NewValidationError("Index", "does not exist") + *reply = nil + } else { + *reply = br.Transactions[args.Index] } - *reply = br.Transactions[args.Index] case "eth_getTransactionByBlockNumberAndIndex": args := new(BlockNumIndexArgs) if err := json.Unmarshal(req.Params, &args); err != nil { @@ -233,9 +235,11 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } if args.Index >= int64(len(v.Transactions)) || args.Index < 0 { - return NewValidationError("Index", "does not exist") + // return NewValidationError("Index", "does not exist") + *reply = nil + } else { + *reply = v.Transactions[args.Index] } - *reply = v.Transactions[args.Index] case "eth_getUncleByBlockHashAndIndex": args := new(HashIndexArgs) if err := json.Unmarshal(req.Params, &args); err != nil { From 537e2cfeb64a14d9c54d5ae69e02a866b5117bd3 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 16:12:19 +0200 Subject: [PATCH 07/10] Return nil when requested uncle index is not valid --- rpc/api.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index 4ce2a98e2e..872290eef8 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -253,13 +253,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } if args.Index >= int64(len(br.Uncles)) || args.Index < 0 { - return NewValidationError("Index", "does not exist") + // return NewValidationError("Index", "does not exist") + *reply = nil + } else { + uhash := br.Uncles[args.Index] + uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), true) + *reply = uncle } - - uhash := br.Uncles[args.Index] - uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false) - - *reply = uncle case "eth_getUncleByBlockNumberAndIndex": args := new(BlockNumIndexArgs) if err := json.Unmarshal(req.Params, &args); err != nil { @@ -275,13 +275,13 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } if args.Index >= int64(len(v.Uncles)) || args.Index < 0 { - return NewValidationError("Index", "does not exist") + // return NewValidationError("Index", "does not exist") + *reply = nil + } else { + uhash := v.Uncles[args.Index] + uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false) + *reply = uncle } - - uhash := v.Uncles[args.Index] - uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false) - - *reply = uncle case "eth_getCompilers": c := []string{""} *reply = c From 9bdf0b655de64c0c31d81da00ff2daec79359d89 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 16:28:42 +0200 Subject: [PATCH 08/10] Fix RLP decoding of tx metadata --- xeth/xeth.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/xeth/xeth.go b/xeth/xeth.go index 6c9db16c27..ad6b09b542 100644 --- a/xeth/xeth.go +++ b/xeth/xeth.go @@ -196,7 +196,7 @@ func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blha // meta var txExtra struct { BlockHash common.Hash - BlockIndex int64 + BlockIndex uint64 Index uint64 } @@ -205,8 +205,10 @@ func (self *XEth) EthTransactionByHash(hash string) (tx *types.Transaction, blha err := rlp.Decode(r, &txExtra) if err == nil { blhash = txExtra.BlockHash - blnum = big.NewInt(txExtra.BlockIndex) + blnum = big.NewInt(int64(txExtra.BlockIndex)) txi = txExtra.Index + } else { + pipelogger.Errorln(err) } return From 1d74086b4240f61d73e8fbf446f6234ab914ddce Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 17:55:42 +0200 Subject: [PATCH 09/10] New UncleRes type --- rpc/api.go | 8 ++----- rpc/responses.go | 59 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/rpc/api.go b/rpc/api.go index 872290eef8..b8207ea0d3 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -256,9 +256,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err // return NewValidationError("Index", "does not exist") *reply = nil } else { - uhash := br.Uncles[args.Index] - uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), true) - *reply = uncle + *reply = br.Uncles[args.Index] } case "eth_getUncleByBlockNumberAndIndex": args := new(BlockNumIndexArgs) @@ -278,9 +276,7 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err // return NewValidationError("Index", "does not exist") *reply = nil } else { - uhash := v.Uncles[args.Index] - uncle := NewBlockRes(api.xeth().EthBlockByHash(uhash.String()), false) - *reply = uncle + *reply = v.Uncles[args.Index] } case "eth_getCompilers": c := []string{""} diff --git a/rpc/responses.go b/rpc/responses.go index 079ee87655..52a2f714c1 100644 --- a/rpc/responses.go +++ b/rpc/responses.go @@ -28,7 +28,7 @@ type BlockRes struct { GasUsed *hexnum `json:"gasUsed"` UnixTimestamp *hexnum `json:"timestamp"` Transactions []*TransactionRes `json:"transactions"` - Uncles []*hexdata `json:"uncles"` + Uncles []*UncleRes `json:"uncles"` } func (b *BlockRes) MarshalJSON() ([]byte, error) { @@ -73,7 +73,10 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { ext.GasUsed = b.GasUsed ext.UnixTimestamp = b.UnixTimestamp ext.Transactions = b.Transactions - ext.Uncles = b.Uncles + ext.Uncles = make([]*hexdata, len(b.Uncles)) + for i, u := range b.Uncles { + ext.Uncles[i] = u.BlockHash + } return json.Marshal(ext) } else { var ext struct { @@ -119,7 +122,10 @@ func (b *BlockRes) MarshalJSON() ([]byte, error) { for i, tx := range b.Transactions { ext.Transactions[i] = tx.Hash } - ext.Uncles = b.Uncles + ext.Uncles = make([]*hexdata, len(b.Uncles)) + for i, u := range b.Uncles { + ext.Uncles[i] = u.BlockHash + } return json.Marshal(ext) } } @@ -157,9 +163,9 @@ func NewBlockRes(block *types.Block, fullTx bool) *BlockRes { res.Transactions[i].TxIndex = newHexNum(i) } - res.Uncles = make([]*hexdata, len(block.Uncles())) + res.Uncles = make([]*UncleRes, len(block.Uncles())) for i, uncle := range block.Uncles() { - res.Uncles[i] = newHexData(uncle.Hash()) + res.Uncles[i] = NewUncleRes(uncle) } return res @@ -200,6 +206,49 @@ func NewTransactionRes(tx *types.Transaction) *TransactionRes { return v } +type UncleRes struct { + BlockNumber *hexnum `json:"number"` + BlockHash *hexdata `json:"hash"` + ParentHash *hexdata `json:"parentHash"` + Nonce *hexdata `json:"nonce"` + Sha3Uncles *hexdata `json:"sha3Uncles"` + ReceiptHash *hexdata `json:"receiptHash"` + LogsBloom *hexdata `json:"logsBloom"` + TransactionRoot *hexdata `json:"transactionsRoot"` + StateRoot *hexdata `json:"stateRoot"` + Miner *hexdata `json:"miner"` + Difficulty *hexnum `json:"difficulty"` + ExtraData *hexdata `json:"extraData"` + GasLimit *hexnum `json:"gasLimit"` + GasUsed *hexnum `json:"gasUsed"` + UnixTimestamp *hexnum `json:"timestamp"` +} + +func NewUncleRes(h *types.Header) *UncleRes { + if h == nil { + return nil + } + + var v = new(UncleRes) + v.BlockNumber = newHexNum(h.Number) + v.BlockHash = newHexData(h.Hash()) + v.ParentHash = newHexData(h.ParentHash) + v.Sha3Uncles = newHexData(h.UncleHash) + v.Nonce = newHexData(h.Nonce[:]) + v.LogsBloom = newHexData(h.Bloom) + v.TransactionRoot = newHexData(h.TxHash) + v.StateRoot = newHexData(h.Root) + v.Miner = newHexData(h.Coinbase) + v.Difficulty = newHexNum(h.Difficulty) + v.ExtraData = newHexData(h.Extra) + v.GasLimit = newHexNum(h.GasLimit) + v.GasUsed = newHexNum(h.GasUsed) + v.UnixTimestamp = newHexNum(h.Time) + v.ReceiptHash = newHexData(h.ReceiptHash) + + return v +} + // type FilterLogRes struct { // Hash string `json:"hash"` // Address string `json:"address"` From 3e042317adc99438d6ffde0cbde4f0b40ad579c1 Mon Sep 17 00:00:00 2001 From: Taylor Gerring Date: Thu, 2 Apr 2015 20:37:51 +0200 Subject: [PATCH 10/10] Return nil if block does not exist --- rpc/api.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rpc/api.go b/rpc/api.go index b8207ea0d3..573f689a22 100644 --- a/rpc/api.go +++ b/rpc/api.go @@ -2,6 +2,7 @@ package rpc import ( "encoding/json" + // "fmt" "math/big" "sync" @@ -112,7 +113,11 @@ func (api *EthereumApi) GetRequestReply(req *RpcRequest, reply *interface{}) err } block := NewBlockRes(api.xeth().EthBlockByHash(args.Hash), false) - *reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes()) + if block == nil { + *reply = nil + } else { + *reply = common.ToHex(big.NewInt(int64(len(block.Transactions))).Bytes()) + } case "eth_getBlockTransactionCountByNumber": args := new(BlockNumArg) if err := json.Unmarshal(req.Params, &args); err != nil {