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