diff options
-rw-r--r-- | core/types/json.go | 21 | ||||
-rw-r--r-- | core/types/json_test.go | 77 | ||||
-rw-r--r-- | core/types/receipt.go | 15 | ||||
-rw-r--r-- | core/types/transaction.go | 18 | ||||
-rw-r--r-- | ethclient/ethclient.go | 2 | ||||
-rw-r--r-- | rpc/utils.go | 11 | ||||
-rw-r--r-- | rpc/utils_test.go | 43 |
7 files changed, 185 insertions, 2 deletions
diff --git a/core/types/json.go b/core/types/json.go index 403e79899..d2718a96d 100644 --- a/core/types/json.go +++ b/core/types/json.go @@ -26,6 +26,13 @@ import ( type hexBytes []byte +func (b *hexBytes) MarshalJSON() ([]byte, error) { + if b != nil { + return []byte(fmt.Sprintf(`"0x%x"`, []byte(*b))), nil + } + return nil, nil +} + func (b *hexBytes) UnmarshalJSON(input []byte) error { if len(input) < 2 || input[0] != '"' || input[len(input)-1] != '"' { return fmt.Errorf("cannot unmarshal non-string into hexBytes") @@ -44,6 +51,13 @@ func (b *hexBytes) UnmarshalJSON(input []byte) error { type hexBig big.Int +func (b *hexBig) MarshalJSON() ([]byte, error) { + if b != nil { + return []byte(fmt.Sprintf(`"0x%x"`, (*big.Int)(b))), nil + } + return nil, nil +} + func (b *hexBig) UnmarshalJSON(input []byte) error { raw, err := checkHexNumber(input) if err != nil { @@ -59,6 +73,13 @@ func (b *hexBig) UnmarshalJSON(input []byte) error { type hexUint64 uint64 +func (b *hexUint64) MarshalJSON() ([]byte, error) { + if b != nil { + return []byte(fmt.Sprintf(`"0x%x"`, *(*uint64)(b))), nil + } + return nil, nil +} + func (b *hexUint64) UnmarshalJSON(input []byte) error { raw, err := checkHexNumber(input) if err != nil { diff --git a/core/types/json_test.go b/core/types/json_test.go index 5f422b873..605c2b564 100644 --- a/core/types/json_test.go +++ b/core/types/json_test.go @@ -2,6 +2,7 @@ package types import ( "encoding/json" + "reflect" "testing" "github.com/ethereum/go-ethereum/common" @@ -44,6 +45,31 @@ func TestUnmarshalHeader(t *testing.T) { } } +func TestMarshalHeader(t *testing.T) { + for name, test := range unmarshalHeaderTests { + if test.wantError != nil { + continue + } + var original *Header + json.Unmarshal([]byte(test.input), &original) + + blob, err := json.Marshal(original) + if err != nil { + t.Errorf("test %q: failed to marshal header: %v", name, err) + continue + } + var proced *Header + if err := json.Unmarshal(blob, &proced); err != nil { + t.Errorf("Test %q: failed to unmarshal marhsalled header: %v", name, err) + continue + } + if !reflect.DeepEqual(original, proced) { + t.Errorf("test %q: header mismatch: have %+v, want %+v", name, proced, original) + continue + } + } +} + var unmarshalTransactionTests = map[string]struct { input string wantHash common.Hash @@ -94,6 +120,32 @@ func TestUnmarshalTransaction(t *testing.T) { } } +func TestMarshalTransaction(t *testing.T) { + for name, test := range unmarshalTransactionTests { + if test.wantError != nil { + continue + } + var original *Transaction + json.Unmarshal([]byte(test.input), &original) + + blob, err := json.Marshal(original) + if err != nil { + t.Errorf("test %q: failed to marshal transaction: %v", name, err) + continue + } + var proced *Transaction + if err := json.Unmarshal(blob, &proced); err != nil { + t.Errorf("Test %q: failed to unmarshal marhsalled transaction: %v", name, err) + continue + } + proced.Hash() // hack private fields to pass deep equal + if !reflect.DeepEqual(original, proced) { + t.Errorf("test %q: transaction mismatch: have %+v, want %+v", name, proced, original) + continue + } + } +} + var unmarshalReceiptTests = map[string]struct { input string wantError error @@ -119,6 +171,31 @@ func TestUnmarshalReceipt(t *testing.T) { } } +func TestMarshalReceipt(t *testing.T) { + for name, test := range unmarshalReceiptTests { + if test.wantError != nil { + continue + } + var original *Receipt + json.Unmarshal([]byte(test.input), &original) + + blob, err := json.Marshal(original) + if err != nil { + t.Errorf("test %q: failed to marshal receipt: %v", name, err) + continue + } + var proced *Receipt + if err := json.Unmarshal(blob, &proced); err != nil { + t.Errorf("Test %q: failed to unmarshal marhsalled receipt: %v", name, err) + continue + } + if !reflect.DeepEqual(original, proced) { + t.Errorf("test %q: receipt mismatch: have %+v, want %+v", name, proced, original) + continue + } + } +} + func checkError(t *testing.T, testname string, got, want error) bool { if got == nil { if want != nil { diff --git a/core/types/receipt.go b/core/types/receipt.go index 9f820eb18..b00fdabff 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -84,6 +84,21 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { return nil } +// MarshalJSON encodes receipts into the web3 RPC response block format. +func (r *Receipt) MarshalJSON() ([]byte, error) { + root := common.BytesToHash(r.PostState) + + return json.Marshal(&jsonReceipt{ + PostState: &root, + CumulativeGasUsed: (*hexBig)(r.CumulativeGasUsed), + Bloom: &r.Bloom, + Logs: &r.Logs, + TxHash: &r.TxHash, + ContractAddress: &r.ContractAddress, + GasUsed: (*hexBig)(r.GasUsed), + }) +} + // UnmarshalJSON decodes the web3 RPC receipt format. func (r *Receipt) UnmarshalJSON(input []byte) error { var dec jsonReceipt diff --git a/core/types/transaction.go b/core/types/transaction.go index 5bb599479..f0512ae7e 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -128,6 +128,24 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error { return err } +// MarshalJSON encodes transactions into the web3 RPC response block format. +func (tx *Transaction) MarshalJSON() ([]byte, error) { + hash, v := tx.Hash(), uint64(tx.data.V) + + return json.Marshal(&jsonTransaction{ + Hash: &hash, + AccountNonce: (*hexUint64)(&tx.data.AccountNonce), + Price: (*hexBig)(tx.data.Price), + GasLimit: (*hexBig)(tx.data.GasLimit), + Recipient: tx.data.Recipient, + Amount: (*hexBig)(tx.data.Amount), + Payload: (*hexBytes)(&tx.data.Payload), + V: (*hexUint64)(&v), + R: (*hexBig)(tx.data.R), + S: (*hexBig)(tx.data.S), + }) +} + // UnmarshalJSON decodes the web3 RPC transaction format. func (tx *Transaction) UnmarshalJSON(input []byte) error { var dec jsonTransaction diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 50346f6ae..ffa8228cc 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -227,7 +227,7 @@ func (ec *Client) SyncProgress(ctx context.Context) (*ethereum.SyncProgress, err // SubscribeNewHead subscribes to notifications about the current blockchain head // on the given channel. func (ec *Client) SubscribeNewHead(ctx context.Context, ch chan<- *types.Header) (ethereum.Subscription, error) { - return ec.c.EthSubscribe(ctx, ch, "newBlocks", map[string]struct{}{}) + return ec.c.EthSubscribe(ctx, ch, "newHeads", map[string]struct{}{}) } // State Access diff --git a/rpc/utils.go b/rpc/utils.go index b590ba62f..c249e9b4a 100644 --- a/rpc/utils.go +++ b/rpc/utils.go @@ -24,6 +24,7 @@ import ( "math/big" "math/rand" "reflect" + "strings" "sync" "time" "unicode" @@ -250,5 +251,13 @@ func NewID() ID { val >>= 8 } } - return ID("0x" + hex.EncodeToString(id)) + + rpcId := hex.EncodeToString(id) + // rpc ID's are RPC quantities, no leading zero's and 0 is 0x0 + rpcId = strings.TrimLeft(rpcId, "0") + if rpcId == "" { + rpcId = "0" + } + + return ID("0x" + rpcId) } diff --git a/rpc/utils_test.go b/rpc/utils_test.go new file mode 100644 index 000000000..e0e063f60 --- /dev/null +++ b/rpc/utils_test.go @@ -0,0 +1,43 @@ +// Copyright 2016 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. + +package rpc + +import ( + "strings" + "testing" +) + +func TestNewID(t *testing.T) { + hexchars := "0123456789ABCDEFabcdef" + for i := 0; i < 100; i++ { + id := string(NewID()) + if !strings.HasPrefix(id, "0x") { + t.Fatalf("invalid ID prefix, want '0x...', got %s", id) + } + + id = id[2:] + if len(id) == 0 || len(id) > 32 { + t.Fatalf("invalid ID length, want len(id) > 0 && len(id) <= 32), got %d", len(id)) + } + + for i := 0; i < len(id); i++ { + if strings.IndexByte(hexchars, id[i]) == -1 { + t.Fatalf("unexpected byte, want any valid hex char, got %c", id[i]) + } + } + } +} |