internal/ethapi: add missing output fields

- returned headers didn't include mixHash
- returned transactions didn't include signature fields
- empty transaction input was returned as "", but should be "0x"
- returned receipts didn't include the bloom filter
- "root" in receipts was missing 0x prefix
This commit is contained in:
Felix Lange 2016-08-04 01:40:50 +02:00
parent 704fde01e8
commit b0d9f7372a
3 changed files with 85 additions and 24 deletions

@ -588,24 +588,26 @@ func FormatLogs(structLogs []vm.StructLog) []StructLogRes {
// returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain // returned. When fullTx is true the returned block contains full transaction details, otherwise it will only contain
// transaction hashes. // transaction hashes.
func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) { func (s *PublicBlockChainAPI) rpcOutputBlock(b *types.Block, inclTx bool, fullTx bool) (map[string]interface{}, error) {
head := b.Header() // copies the header once
fields := map[string]interface{}{ fields := map[string]interface{}{
"number": rpc.NewHexNumber(b.Number()), "number": rpc.NewHexNumber(head.Number),
"hash": b.Hash(), "hash": b.Hash(),
"parentHash": b.ParentHash(), "parentHash": head.ParentHash,
"nonce": b.Header().Nonce, "nonce": head.Nonce,
"sha3Uncles": b.UncleHash(), "mixHash": head.MixDigest,
"logsBloom": b.Bloom(), "sha3Uncles": head.UncleHash,
"stateRoot": b.Root(), "logsBloom": head.Bloom,
"miner": b.Coinbase(), "stateRoot": head.Root,
"difficulty": rpc.NewHexNumber(b.Difficulty()), "miner": head.Coinbase,
"difficulty": rpc.NewHexNumber(head.Difficulty),
"totalDifficulty": rpc.NewHexNumber(s.b.GetTd(b.Hash())), "totalDifficulty": rpc.NewHexNumber(s.b.GetTd(b.Hash())),
"extraData": fmt.Sprintf("0x%x", b.Extra()), "extraData": rpc.HexBytes(head.Extra),
"size": rpc.NewHexNumber(b.Size().Int64()), "size": rpc.NewHexNumber(b.Size().Int64()),
"gasLimit": rpc.NewHexNumber(b.GasLimit()), "gasLimit": rpc.NewHexNumber(head.GasLimit),
"gasUsed": rpc.NewHexNumber(b.GasUsed()), "gasUsed": rpc.NewHexNumber(head.GasUsed),
"timestamp": rpc.NewHexNumber(b.Time()), "timestamp": rpc.NewHexNumber(head.Time),
"transactionsRoot": b.TxHash(), "transactionsRoot": head.TxHash,
"receiptRoot": b.ReceiptHash(), "receiptRoot": head.ReceiptHash,
} }
if inclTx { if inclTx {
@ -648,26 +650,32 @@ type RPCTransaction struct {
Gas *rpc.HexNumber `json:"gas"` Gas *rpc.HexNumber `json:"gas"`
GasPrice *rpc.HexNumber `json:"gasPrice"` GasPrice *rpc.HexNumber `json:"gasPrice"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
Input string `json:"input"` Input rpc.HexBytes `json:"input"`
Nonce *rpc.HexNumber `json:"nonce"` Nonce *rpc.HexNumber `json:"nonce"`
To *common.Address `json:"to"` To *common.Address `json:"to"`
TransactionIndex *rpc.HexNumber `json:"transactionIndex"` TransactionIndex *rpc.HexNumber `json:"transactionIndex"`
Value *rpc.HexNumber `json:"value"` Value *rpc.HexNumber `json:"value"`
V *rpc.HexNumber `json:"v"`
R *rpc.HexNumber `json:"r"`
S *rpc.HexNumber `json:"s"`
} }
// newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation // newRPCPendingTransaction returns a pending transaction that will serialize to the RPC representation
func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction { func newRPCPendingTransaction(tx *types.Transaction) *RPCTransaction {
from, _ := tx.FromFrontier() from, _ := tx.FromFrontier()
v, r, s := tx.SignatureValues()
return &RPCTransaction{ return &RPCTransaction{
From: from, From: from,
Gas: rpc.NewHexNumber(tx.Gas()), Gas: rpc.NewHexNumber(tx.Gas()),
GasPrice: rpc.NewHexNumber(tx.GasPrice()), GasPrice: rpc.NewHexNumber(tx.GasPrice()),
Hash: tx.Hash(), Hash: tx.Hash(),
Input: fmt.Sprintf("0x%x", tx.Data()), Input: rpc.HexBytes(tx.Data()),
Nonce: rpc.NewHexNumber(tx.Nonce()), Nonce: rpc.NewHexNumber(tx.Nonce()),
To: tx.To(), To: tx.To(),
Value: rpc.NewHexNumber(tx.Value()), Value: rpc.NewHexNumber(tx.Value()),
V: rpc.NewHexNumber(v),
R: rpc.NewHexNumber(r),
S: rpc.NewHexNumber(s),
} }
} }
@ -679,7 +687,7 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti
if err != nil { if err != nil {
return nil, err return nil, err
} }
v, r, s := tx.SignatureValues()
return &RPCTransaction{ return &RPCTransaction{
BlockHash: b.Hash(), BlockHash: b.Hash(),
BlockNumber: rpc.NewHexNumber(b.Number()), BlockNumber: rpc.NewHexNumber(b.Number()),
@ -687,11 +695,14 @@ func newRPCTransactionFromBlockIndex(b *types.Block, txIndex int) (*RPCTransacti
Gas: rpc.NewHexNumber(tx.Gas()), Gas: rpc.NewHexNumber(tx.Gas()),
GasPrice: rpc.NewHexNumber(tx.GasPrice()), GasPrice: rpc.NewHexNumber(tx.GasPrice()),
Hash: tx.Hash(), Hash: tx.Hash(),
Input: fmt.Sprintf("0x%x", tx.Data()), Input: rpc.HexBytes(tx.Data()),
Nonce: rpc.NewHexNumber(tx.Nonce()), Nonce: rpc.NewHexNumber(tx.Nonce()),
To: tx.To(), To: tx.To(),
TransactionIndex: rpc.NewHexNumber(txIndex), TransactionIndex: rpc.NewHexNumber(txIndex),
Value: rpc.NewHexNumber(tx.Value()), Value: rpc.NewHexNumber(tx.Value()),
V: rpc.NewHexNumber(v),
R: rpc.NewHexNumber(r),
S: rpc.NewHexNumber(s),
}, nil }, nil
} }
@ -861,7 +872,7 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
} }
fields := map[string]interface{}{ fields := map[string]interface{}{
"root": common.Bytes2Hex(receipt.PostState), "root": rpc.HexBytes(receipt.PostState),
"blockHash": txBlock, "blockHash": txBlock,
"blockNumber": rpc.NewHexNumber(blockIndex), "blockNumber": rpc.NewHexNumber(blockIndex),
"transactionHash": txHash, "transactionHash": txHash,
@ -872,17 +883,15 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(txHash common.Hash) (ma
"cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed), "cumulativeGasUsed": rpc.NewHexNumber(receipt.CumulativeGasUsed),
"contractAddress": nil, "contractAddress": nil,
"logs": receipt.Logs, "logs": receipt.Logs,
"logsBloom": receipt.Bloom,
} }
if receipt.Logs == nil { if receipt.Logs == nil {
fields["logs"] = []vm.Logs{} fields["logs"] = []vm.Logs{}
} }
// If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation // If the ContractAddress is 20 0x0 bytes, assume it is not a contract creation
if bytes.Compare(receipt.ContractAddress.Bytes(), bytes.Repeat([]byte{0}, 20)) != 0 { if receipt.ContractAddress != (common.Address{}) {
fields["contractAddress"] = receipt.ContractAddress fields["contractAddress"] = receipt.ContractAddress
} }
return fields, nil return fields, nil
} }

@ -17,6 +17,8 @@
package rpc package rpc
import ( import (
"bytes"
"encoding/hex"
"fmt" "fmt"
"math" "math"
"math/big" "math/big"
@ -272,3 +274,31 @@ func (bn *BlockNumber) UnmarshalJSON(data []byte) error {
func (bn BlockNumber) Int64() int64 { func (bn BlockNumber) Int64() int64 {
return (int64)(bn) return (int64)(bn)
} }
// HexBytes JSON-encodes as hex with 0x prefix.
type HexBytes []byte
func (b HexBytes) MarshalJSON() ([]byte, error) {
result := make([]byte, len(b)*2+4)
copy(result, `"0x`)
hex.Encode(result[3:], b)
result[len(result)-1] = '"'
return result, nil
}
func (b *HexBytes) UnmarshalJSON(input []byte) error {
if len(input) >= 2 && input[0] == '"' && input[len(input)-1] == '"' {
input = input[1 : len(input)-1]
}
if !bytes.HasPrefix(input, []byte("0x")) {
return fmt.Errorf("missing 0x prefix for hex byte array")
}
input = input[2:]
if len(input) == 0 {
*b = nil
return nil
}
*b = make([]byte, len(input)/2)
_, err := hex.Decode(*b, input)
return err
}

@ -71,3 +71,25 @@ func TestHexNumberMarshalJSON(t *testing.T) {
t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got) t.Fatalf("Invalid json.Marshal, expected '%s', got '%s'", exp, got)
} }
} }
var hexBytesTests = []struct{ in, out []byte }{
{in: []byte(`"0x"`), out: []byte{}},
{in: []byte(`"0x00"`), out: []byte{0}},
{in: []byte(`"0x01ff"`), out: []byte{0x01, 0xFF}},
}
func TestHexBytes(t *testing.T) {
for i, test := range hexBytesTests {
var dec HexBytes
if err := json.Unmarshal(test.in, &dec); err != nil {
t.Fatalf("test %d: can't decode: %v", i, err)
}
enc, _ := json.Marshal(HexBytes(test.out))
if !bytes.Equal(dec, test.out) {
t.Errorf("test %d: wrong decoded value 0x%x", i, dec)
}
if !bytes.Equal(enc, test.in) {
t.Errorf("test %d: wrong encoded value %#q", i, enc)
}
}
}