core/types: use gencodec for JSON marshaling code

pull/3756/head
Felix Lange 8 years ago
parent eee96a5bb7
commit 8cf08e4b25
  1. 127
      core/types/block.go
  2. 136
      core/types/gen_header_json.go
  3. 90
      core/types/gen_log_json.go
  4. 79
      core/types/gen_receipt_json.go
  5. 99
      core/types/gen_tx_json.go
  6. 99
      core/types/log.go
  7. 3
      core/types/log_test.go
  8. 78
      core/types/receipt.go
  9. 111
      core/types/transaction.go

@ -19,8 +19,6 @@ package types
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
@ -39,12 +37,6 @@ var (
EmptyUncleHash = CalcUncleHash(nil)
)
var (
errMissingHeaderMixDigest = errors.New("missing mixHash in JSON block header")
errMissingHeaderFields = errors.New("missing required JSON block header fields")
errBadNonceSize = errors.New("invalid block nonce size, want 8 bytes")
)
// A BlockNonce is a 64-bit hash which proves (combined with the
// mix-hash) that a sufficient amount of computation has been carried
// out on a block.
@ -72,41 +64,35 @@ func (n *BlockNonce) UnmarshalText(input []byte) error {
return hexutil.UnmarshalFixedText("BlockNonce", input, n[:])
}
//go:generate gencodec -type Header -field-override headerMarshaling -out gen_header_json.go
// Header represents a block header in the Ethereum blockchain.
type Header struct {
ParentHash common.Hash // Hash to the previous block
UncleHash common.Hash // Uncles of this block
Coinbase common.Address // The coin base address
Root common.Hash // Block Trie state
TxHash common.Hash // Tx sha
ReceiptHash common.Hash // Receipt sha
Bloom Bloom // Bloom
Difficulty *big.Int // Difficulty for the current block
Number *big.Int // The block number
GasLimit *big.Int // Gas limit
GasUsed *big.Int // Gas used
Time *big.Int // Creation time
Extra []byte // Extra data
MixDigest common.Hash // for quick difficulty verification
Nonce BlockNonce
}
type jsonHeader struct {
ParentHash *common.Hash `json:"parentHash"`
UncleHash *common.Hash `json:"sha3Uncles"`
Coinbase *common.Address `json:"miner"`
Root *common.Hash `json:"stateRoot"`
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom *Bloom `json:"logsBloom"`
Difficulty *hexutil.Big `json:"difficulty"`
Number *hexutil.Big `json:"number"`
GasLimit *hexutil.Big `json:"gasLimit"`
GasUsed *hexutil.Big `json:"gasUsed"`
Time *hexutil.Big `json:"timestamp"`
Extra *hexutil.Bytes `json:"extraData"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *BlockNonce `json:"nonce"`
ParentHash common.Hash `json:"parentHash"`
UncleHash common.Hash `json:"sha3Uncles"`
Coinbase common.Address `json:"miner"`
Root common.Hash `json:"stateRoot"`
TxHash common.Hash `json:"transactionsRoot"`
ReceiptHash common.Hash `json:"receiptsRoot"`
Bloom Bloom `json:"logsBloom"`
Difficulty *big.Int `json:"difficulty"`
Number *big.Int `json:"number"`
GasLimit *big.Int `json:"gasLimit"`
GasUsed *big.Int `json:"gasUsed"`
Time *big.Int `json:"timestamp"`
Extra []byte `json:"extraData"`
MixDigest common.Hash `json:"mixHash"`
Nonce BlockNonce `json:"nonce"`
}
// field type overrides for gencodec
type headerMarshaling struct {
Difficulty *hexutil.Big
Number *hexutil.Big
GasLimit *hexutil.Big
GasUsed *hexutil.Big
Time *hexutil.Big
Extra hexutil.Bytes
}
// Hash returns the block hash of the header, which is simply the keccak256 hash of its
@ -134,65 +120,6 @@ func (h *Header) HashNoNonce() common.Hash {
})
}
// MarshalJSON encodes headers into the web3 RPC response block format.
func (h *Header) MarshalJSON() ([]byte, error) {
return json.Marshal(&jsonHeader{
ParentHash: &h.ParentHash,
UncleHash: &h.UncleHash,
Coinbase: &h.Coinbase,
Root: &h.Root,
TxHash: &h.TxHash,
ReceiptHash: &h.ReceiptHash,
Bloom: &h.Bloom,
Difficulty: (*hexutil.Big)(h.Difficulty),
Number: (*hexutil.Big)(h.Number),
GasLimit: (*hexutil.Big)(h.GasLimit),
GasUsed: (*hexutil.Big)(h.GasUsed),
Time: (*hexutil.Big)(h.Time),
Extra: (*hexutil.Bytes)(&h.Extra),
MixDigest: &h.MixDigest,
Nonce: &h.Nonce,
})
}
// UnmarshalJSON decodes headers from the web3 RPC response block format.
func (h *Header) UnmarshalJSON(input []byte) error {
var dec jsonHeader
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
// Ensure that all fields are set. MixDigest is checked separately because
// it is a recent addition to the spec (as of August 2016) and older RPC server
// implementations might not provide it.
if dec.MixDigest == nil {
return errMissingHeaderMixDigest
}
if dec.ParentHash == nil || dec.UncleHash == nil || dec.Coinbase == nil ||
dec.Root == nil || dec.TxHash == nil || dec.ReceiptHash == nil ||
dec.Bloom == nil || dec.Difficulty == nil || dec.Number == nil ||
dec.GasLimit == nil || dec.GasUsed == nil || dec.Time == nil ||
dec.Extra == nil || dec.Nonce == nil {
return errMissingHeaderFields
}
// Assign all values.
h.ParentHash = *dec.ParentHash
h.UncleHash = *dec.UncleHash
h.Coinbase = *dec.Coinbase
h.Root = *dec.Root
h.TxHash = *dec.TxHash
h.ReceiptHash = *dec.ReceiptHash
h.Bloom = *dec.Bloom
h.Difficulty = (*big.Int)(dec.Difficulty)
h.Number = (*big.Int)(dec.Number)
h.GasLimit = (*big.Int)(dec.GasLimit)
h.GasUsed = (*big.Int)(dec.GasUsed)
h.Time = (*big.Int)(dec.Time)
h.Extra = *dec.Extra
h.MixDigest = *dec.MixDigest
h.Nonce = *dec.Nonce
return nil
}
func rlpHash(x interface{}) (h common.Hash) {
hw := sha3.NewKeccak256()
rlp.Encode(hw, x)

@ -0,0 +1,136 @@
// generated by github.com/fjl/gencodec, do not edit.
package types
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func (h *Header) MarshalJSON() ([]byte, error) {
type HeaderJSON struct {
ParentHash *common.Hash `json:"parentHash"`
UncleHash *common.Hash `json:"sha3Uncles"`
Coinbase *common.Address `json:"miner"`
Root *common.Hash `json:"stateRoot"`
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom *Bloom `json:"logsBloom"`
Difficulty *hexutil.Big `json:"difficulty"`
Number *hexutil.Big `json:"number"`
GasLimit *hexutil.Big `json:"gasLimit"`
GasUsed *hexutil.Big `json:"gasUsed"`
Time *hexutil.Big `json:"timestamp"`
Extra hexutil.Bytes `json:"extraData"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *BlockNonce `json:"nonce"`
}
var enc HeaderJSON
enc.ParentHash = &h.ParentHash
enc.UncleHash = &h.UncleHash
enc.Coinbase = &h.Coinbase
enc.Root = &h.Root
enc.TxHash = &h.TxHash
enc.ReceiptHash = &h.ReceiptHash
enc.Bloom = &h.Bloom
enc.Difficulty = (*hexutil.Big)(h.Difficulty)
enc.Number = (*hexutil.Big)(h.Number)
enc.GasLimit = (*hexutil.Big)(h.GasLimit)
enc.GasUsed = (*hexutil.Big)(h.GasUsed)
enc.Time = (*hexutil.Big)(h.Time)
enc.Extra = h.Extra
enc.MixDigest = &h.MixDigest
enc.Nonce = &h.Nonce
return json.Marshal(&enc)
}
func (h *Header) UnmarshalJSON(input []byte) error {
type HeaderJSON struct {
ParentHash *common.Hash `json:"parentHash"`
UncleHash *common.Hash `json:"sha3Uncles"`
Coinbase *common.Address `json:"miner"`
Root *common.Hash `json:"stateRoot"`
TxHash *common.Hash `json:"transactionsRoot"`
ReceiptHash *common.Hash `json:"receiptsRoot"`
Bloom *Bloom `json:"logsBloom"`
Difficulty *hexutil.Big `json:"difficulty"`
Number *hexutil.Big `json:"number"`
GasLimit *hexutil.Big `json:"gasLimit"`
GasUsed *hexutil.Big `json:"gasUsed"`
Time *hexutil.Big `json:"timestamp"`
Extra hexutil.Bytes `json:"extraData"`
MixDigest *common.Hash `json:"mixHash"`
Nonce *BlockNonce `json:"nonce"`
}
var dec HeaderJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x Header
if dec.ParentHash == nil {
return errors.New("missing required field 'parentHash' for Header")
}
x.ParentHash = *dec.ParentHash
if dec.UncleHash == nil {
return errors.New("missing required field 'sha3Uncles' for Header")
}
x.UncleHash = *dec.UncleHash
if dec.Coinbase == nil {
return errors.New("missing required field 'miner' for Header")
}
x.Coinbase = *dec.Coinbase
if dec.Root == nil {
return errors.New("missing required field 'stateRoot' for Header")
}
x.Root = *dec.Root
if dec.TxHash == nil {
return errors.New("missing required field 'transactionsRoot' for Header")
}
x.TxHash = *dec.TxHash
if dec.ReceiptHash == nil {
return errors.New("missing required field 'receiptsRoot' for Header")
}
x.ReceiptHash = *dec.ReceiptHash
if dec.Bloom == nil {
return errors.New("missing required field 'logsBloom' for Header")
}
x.Bloom = *dec.Bloom
if dec.Difficulty == nil {
return errors.New("missing required field 'difficulty' for Header")
}
x.Difficulty = (*big.Int)(dec.Difficulty)
if dec.Number == nil {
return errors.New("missing required field 'number' for Header")
}
x.Number = (*big.Int)(dec.Number)
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for Header")
}
x.GasLimit = (*big.Int)(dec.GasLimit)
if dec.GasUsed == nil {
return errors.New("missing required field 'gasUsed' for Header")
}
x.GasUsed = (*big.Int)(dec.GasUsed)
if dec.Time == nil {
return errors.New("missing required field 'timestamp' for Header")
}
x.Time = (*big.Int)(dec.Time)
if dec.Extra == nil {
return errors.New("missing required field 'extraData' for Header")
}
x.Extra = dec.Extra
if dec.MixDigest == nil {
return errors.New("missing required field 'mixHash' for Header")
}
x.MixDigest = *dec.MixDigest
if dec.Nonce == nil {
return errors.New("missing required field 'nonce' for Header")
}
x.Nonce = *dec.Nonce
*h = x
return nil
}

@ -0,0 +1,90 @@
// generated by github.com/fjl/gencodec, do not edit.
package types
import (
"encoding/json"
"errors"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func (l *Log) MarshalJSON() ([]byte, error) {
type LogJSON struct {
Address *common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
BlockNumber *hexutil.Uint64 `json:"blockNumber" optional:"yes"`
TxHash *common.Hash `json:"transactionHash"`
TxIndex *hexutil.Uint `json:"transactionIndex"`
BlockHash *common.Hash `json:"blockHash" optional:"yes"`
Index *hexutil.Uint `json:"logIndex"`
Removed *bool `json:"removed" optional:"yes"`
}
var enc LogJSON
enc.Address = &l.Address
enc.Topics = l.Topics
enc.Data = l.Data
enc.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
enc.TxHash = &l.TxHash
enc.TxIndex = (*hexutil.Uint)(&l.TxIndex)
enc.BlockHash = &l.BlockHash
enc.Index = (*hexutil.Uint)(&l.Index)
enc.Removed = &l.Removed
return json.Marshal(&enc)
}
func (l *Log) UnmarshalJSON(input []byte) error {
type LogJSON struct {
Address *common.Address `json:"address"`
Topics []common.Hash `json:"topics"`
Data hexutil.Bytes `json:"data"`
BlockNumber *hexutil.Uint64 `json:"blockNumber" optional:"yes"`
TxHash *common.Hash `json:"transactionHash"`
TxIndex *hexutil.Uint `json:"transactionIndex"`
BlockHash *common.Hash `json:"blockHash" optional:"yes"`
Index *hexutil.Uint `json:"logIndex"`
Removed *bool `json:"removed" optional:"yes"`
}
var dec LogJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x Log
if dec.Address == nil {
return errors.New("missing required field 'address' for Log")
}
x.Address = *dec.Address
if dec.Topics == nil {
return errors.New("missing required field 'topics' for Log")
}
x.Topics = dec.Topics
if dec.Data == nil {
return errors.New("missing required field 'data' for Log")
}
x.Data = dec.Data
if dec.BlockNumber != nil {
x.BlockNumber = uint64(*dec.BlockNumber)
}
if dec.TxHash == nil {
return errors.New("missing required field 'transactionHash' for Log")
}
x.TxHash = *dec.TxHash
if dec.TxIndex == nil {
return errors.New("missing required field 'transactionIndex' for Log")
}
x.TxIndex = uint(*dec.TxIndex)
if dec.BlockHash != nil {
x.BlockHash = *dec.BlockHash
}
if dec.Index == nil {
return errors.New("missing required field 'logIndex' for Log")
}
x.Index = uint(*dec.Index)
if dec.Removed != nil {
x.Removed = *dec.Removed
}
*l = x
return nil
}

@ -0,0 +1,79 @@
// generated by github.com/fjl/gencodec, do not edit.
package types
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func (r *Receipt) MarshalJSON() ([]byte, error) {
type ReceiptJSON struct {
PostState hexutil.Bytes `json:"root"`
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
Bloom *Bloom `json:"logsBloom"`
Logs []*Log `json:"logs"`
TxHash *common.Hash `json:"transactionHash"`
ContractAddress *common.Address `json:"contractAddress" optional:"true"`
GasUsed *hexutil.Big `json:"gasUsed"`
}
var enc ReceiptJSON
enc.PostState = r.PostState
enc.CumulativeGasUsed = (*hexutil.Big)(r.CumulativeGasUsed)
enc.Bloom = &r.Bloom
enc.Logs = r.Logs
enc.TxHash = &r.TxHash
enc.ContractAddress = &r.ContractAddress
enc.GasUsed = (*hexutil.Big)(r.GasUsed)
return json.Marshal(&enc)
}
func (r *Receipt) UnmarshalJSON(input []byte) error {
type ReceiptJSON struct {
PostState hexutil.Bytes `json:"root"`
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
Bloom *Bloom `json:"logsBloom"`
Logs []*Log `json:"logs"`
TxHash *common.Hash `json:"transactionHash"`
ContractAddress *common.Address `json:"contractAddress" optional:"true"`
GasUsed *hexutil.Big `json:"gasUsed"`
}
var dec ReceiptJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x Receipt
if dec.PostState == nil {
return errors.New("missing required field 'root' for Receipt")
}
x.PostState = dec.PostState
if dec.CumulativeGasUsed == nil {
return errors.New("missing required field 'cumulativeGasUsed' for Receipt")
}
x.CumulativeGasUsed = (*big.Int)(dec.CumulativeGasUsed)
if dec.Bloom == nil {
return errors.New("missing required field 'logsBloom' for Receipt")
}
x.Bloom = *dec.Bloom
if dec.Logs == nil {
return errors.New("missing required field 'logs' for Receipt")
}
x.Logs = dec.Logs
if dec.TxHash == nil {
return errors.New("missing required field 'transactionHash' for Receipt")
}
x.TxHash = *dec.TxHash
if dec.ContractAddress != nil {
x.ContractAddress = *dec.ContractAddress
}
if dec.GasUsed == nil {
return errors.New("missing required field 'gasUsed' for Receipt")
}
x.GasUsed = (*big.Int)(dec.GasUsed)
*r = x
return nil
}

@ -0,0 +1,99 @@
// generated by github.com/fjl/gencodec, do not edit.
package types
import (
"encoding/json"
"errors"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
)
func (t *txdata) MarshalJSON() ([]byte, error) {
type txdataJSON struct {
AccountNonce *hexutil.Uint64 `json:"nonce"`
Price *hexutil.Big `json:"gasPrice"`
GasLimit *hexutil.Big `json:"gasLimit"`
Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"`
Amount *hexutil.Big `json:"value"`
Payload hexutil.Bytes `json:"input"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
}
var enc txdataJSON
enc.AccountNonce = (*hexutil.Uint64)(&t.AccountNonce)
enc.Price = (*hexutil.Big)(t.Price)
enc.GasLimit = (*hexutil.Big)(t.GasLimit)
enc.Recipient = t.Recipient
enc.Amount = (*hexutil.Big)(t.Amount)
enc.Payload = t.Payload
enc.V = (*hexutil.Big)(t.V)
enc.R = (*hexutil.Big)(t.R)
enc.S = (*hexutil.Big)(t.S)
enc.Hash = t.Hash
return json.Marshal(&enc)
}
func (t *txdata) UnmarshalJSON(input []byte) error {
type txdataJSON struct {
AccountNonce *hexutil.Uint64 `json:"nonce"`
Price *hexutil.Big `json:"gasPrice"`
GasLimit *hexutil.Big `json:"gasLimit"`
Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"`
Amount *hexutil.Big `json:"value"`
Payload hexutil.Bytes `json:"input"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
}
var dec txdataJSON
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
var x txdata
if dec.AccountNonce == nil {
return errors.New("missing required field 'nonce' for txdata")
}
x.AccountNonce = uint64(*dec.AccountNonce)
if dec.Price == nil {
return errors.New("missing required field 'gasPrice' for txdata")
}
x.Price = (*big.Int)(dec.Price)
if dec.GasLimit == nil {
return errors.New("missing required field 'gasLimit' for txdata")
}
x.GasLimit = (*big.Int)(dec.GasLimit)
if dec.Recipient != nil {
x.Recipient = dec.Recipient
}
if dec.Amount == nil {
return errors.New("missing required field 'value' for txdata")
}
x.Amount = (*big.Int)(dec.Amount)
if dec.Payload == nil {
return errors.New("missing required field 'input' for txdata")
}
x.Payload = dec.Payload
if dec.V == nil {
return errors.New("missing required field 'v' for txdata")
}
x.V = (*big.Int)(dec.V)
if dec.R == nil {
return errors.New("missing required field 'r' for txdata")
}
x.R = (*big.Int)(dec.R)
if dec.S == nil {
return errors.New("missing required field 's' for txdata")
}
x.S = (*big.Int)(dec.S)
if dec.Hash != nil {
x.Hash = dec.Hash
}
*t = x
return nil
}

@ -17,8 +17,6 @@
package types
import (
"encoding/json"
"errors"
"fmt"
"io"
@ -27,27 +25,42 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
var errMissingLogFields = errors.New("missing required JSON log fields")
//go:generate gencodec -type Log -field-override logMarshaling -out gen_log_json.go
// Log represents a contract log event. These events are generated by the LOG opcode and
// stored/indexed by the node.
type Log struct {
// Consensus fields.
Address common.Address // address of the contract that generated the event
Topics []common.Hash // list of topics provided by the contract.
Data []byte // supplied by the contract, usually ABI-encoded
// Consensus fields:
// address of the contract that generated the event
Address common.Address `json:"address"`
// list of topics provided by the contract.
Topics []common.Hash `json:"topics"`
// supplied by the contract, usually ABI-encoded
Data []byte `json:"data"`
// Derived fields. These fields are filled in by the node
// but not secured by consensus.
BlockNumber uint64 // block in which the transaction was included
TxHash common.Hash // hash of the transaction
TxIndex uint // index of the transaction in the block
BlockHash common.Hash // hash of the block in which the transaction was included
Index uint // index of the log in the receipt
// block in which the transaction was included
BlockNumber uint64 `json:"blockNumber" optional:"yes"`
// hash of the transaction
TxHash common.Hash `json:"transactionHash"`
// index of the transaction in the block
TxIndex uint `json:"transactionIndex"`
// hash of the block in which the transaction was included
BlockHash common.Hash `json:"blockHash" optional:"yes"`
// index of the log in the receipt
Index uint `json:"logIndex"`
// The Removed field is true if this log was reverted due to a chain reorganisation.
// You must pay attention to this field if you receive logs through a filter query.
Removed bool
Removed bool `json:"removed" optional:"yes"`
}
type logMarshaling struct {
Data hexutil.Bytes
BlockNumber hexutil.Uint64
TxIndex hexutil.Uint
Index hexutil.Uint
}
type rlpLog struct {
@ -67,18 +80,6 @@ type rlpStorageLog struct {
Index uint
}
type jsonLog struct {
Address *common.Address `json:"address"`
Topics *[]common.Hash `json:"topics"`
Data *hexutil.Bytes `json:"data"`
BlockNumber *hexutil.Uint64 `json:"blockNumber"`
TxIndex *hexutil.Uint `json:"transactionIndex"`
TxHash *common.Hash `json:"transactionHash"`
BlockHash *common.Hash `json:"blockHash"`
Index *hexutil.Uint `json:"logIndex"`
Removed bool `json:"removed"`
}
// EncodeRLP implements rlp.Encoder.
func (l *Log) EncodeRLP(w io.Writer) error {
return rlp.Encode(w, rlpLog{Address: l.Address, Topics: l.Topics, Data: l.Data})
@ -98,54 +99,6 @@ func (l *Log) String() string {
return fmt.Sprintf(`log: %x %x %x %x %d %x %d`, l.Address, l.Topics, l.Data, l.TxHash, l.TxIndex, l.BlockHash, l.Index)
}
// MarshalJSON implements json.Marshaler.
func (l *Log) MarshalJSON() ([]byte, error) {
jslog := &jsonLog{
Address: &l.Address,
Topics: &l.Topics,
Data: (*hexutil.Bytes)(&l.Data),
TxIndex: (*hexutil.Uint)(&l.TxIndex),
TxHash: &l.TxHash,
Index: (*hexutil.Uint)(&l.Index),
Removed: l.Removed,
}
// Set block information for mined logs.
if (l.BlockHash != common.Hash{}) {
jslog.BlockHash = &l.BlockHash
jslog.BlockNumber = (*hexutil.Uint64)(&l.BlockNumber)
}
return json.Marshal(jslog)
}
// UnmarshalJSON implements json.Umarshaler.
func (l *Log) UnmarshalJSON(input []byte) error {
var dec jsonLog
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
if dec.Address == nil || dec.Topics == nil || dec.Data == nil ||
dec.TxIndex == nil || dec.TxHash == nil || dec.Index == nil {
return errMissingLogFields
}
declog := Log{
Address: *dec.Address,
Topics: *dec.Topics,
Data: *dec.Data,
TxHash: *dec.TxHash,
TxIndex: uint(*dec.TxIndex),
Index: uint(*dec.Index),
Removed: dec.Removed,
}
// Block information may be missing if the log is received through
// the pending log filter, so it's handled specially here.
if dec.BlockHash != nil && dec.BlockNumber != nil {
declog.BlockHash = *dec.BlockHash
declog.BlockNumber = uint64(*dec.BlockNumber)
}
*l = declog
return nil
}
// LogForStorage is a wrapper around a Log that flattens and parses the entire content of
// a log including non-consensus fields.
type LogForStorage Log

@ -18,6 +18,7 @@ package types
import (
"encoding/json"
"fmt"
"reflect"
"testing"
@ -96,7 +97,7 @@ var unmarshalLogTests = map[string]struct {
},
"missing data": {
input: `{"address":"0xecf8f87f810ecf450940c9f60066b4a7a501d6a7","blockHash":"0x656c34545f90a730a19008c0e7a7cd4fb3895064b48d6d69761bd5abad681056","blockNumber":"0x1ecfa4","logIndex":"0x2","topics":["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef","0x00000000000000000000000080b2c9d7cbbf30a1b0fc8983c647d754c6525615","0x000000000000000000000000f9dff387dcb5cc4cca5b91adb07a95f54e9f1bb6"],"transactionHash":"0x3b198bfd5d2907285af009e9ae84a0ecd63677110d89d7e030251acb87f6487e","transactionIndex":"0x3"}`,
wantError: errMissingLogFields,
wantError: fmt.Errorf("missing required field 'data' for Log"),
},
}

@ -17,8 +17,6 @@
package types
import (
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
@ -28,33 +26,26 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
var (
errMissingReceiptPostState = errors.New("missing post state root in JSON receipt")
errMissingReceiptFields = errors.New("missing required JSON receipt fields")
)
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
// Receipt represents the results of a transaction.
type Receipt struct {
// Consensus fields
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
PostState []byte `json:"root"`
CumulativeGasUsed *big.Int `json:"cumulativeGasUsed"`
Bloom Bloom `json:"logsBloom"`
Logs []*Log `json:"logs"`
// Implementation fields (don't reorder!)
TxHash common.Hash
ContractAddress common.Address
GasUsed *big.Int
TxHash common.Hash `json:"transactionHash"`
ContractAddress common.Address `json:"contractAddress" optional:"true"`
GasUsed *big.Int `json:"gasUsed"`
}
type jsonReceipt struct {
PostState *common.Hash `json:"root"`
CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed"`
Bloom *Bloom `json:"logsBloom"`
Logs []*Log `json:"logs"`
TxHash *common.Hash `json:"transactionHash"`
ContractAddress *common.Address `json:"contractAddress"`
GasUsed *hexutil.Big `json:"gasUsed"`
type receiptMarshaling struct {
PostState hexutil.Bytes
CumulativeGasUsed *hexutil.Big
GasUsed *hexutil.Big
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@ -84,51 +75,6 @@ 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: (*hexutil.Big)(r.CumulativeGasUsed),
Bloom: &r.Bloom,
Logs: r.Logs,
TxHash: &r.TxHash,
ContractAddress: &r.ContractAddress,
GasUsed: (*hexutil.Big)(r.GasUsed),
})
}
// UnmarshalJSON decodes the web3 RPC receipt format.
func (r *Receipt) UnmarshalJSON(input []byte) error {
var dec jsonReceipt
if err := json.Unmarshal(input, &dec); err != nil {
return err
}
// Ensure that all fields are set. PostState is checked separately because it is a
// recent addition to the RPC spec (as of August 2016) and older implementations might
// not provide it. Note that ContractAddress is not checked because it can be null.
if dec.PostState == nil {
return errMissingReceiptPostState
}
if dec.CumulativeGasUsed == nil || dec.Bloom == nil ||
dec.Logs == nil || dec.TxHash == nil || dec.GasUsed == nil {
return errMissingReceiptFields
}
*r = Receipt{
PostState: (*dec.PostState)[:],
CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
Bloom: *dec.Bloom,
Logs: dec.Logs,
TxHash: *dec.TxHash,
GasUsed: (*big.Int)(dec.GasUsed),
}
if dec.ContractAddress != nil {
r.ContractAddress = *dec.ContractAddress
}
return nil
}
// String implements the Stringer interface.
func (r *Receipt) String() string {
return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)

@ -18,7 +18,6 @@ package types
import (
"container/heap"
"encoding/json"
"errors"
"fmt"
"io"
@ -32,12 +31,11 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
var ErrInvalidSig = errors.New("invalid transaction v, r, s values")
//go:generate gencodec -type txdata -field-override txdataMarshaling -out gen_tx_json.go
var (
errMissingTxSignatureFields = errors.New("missing required JSON transaction signature fields")
errMissingTxFields = errors.New("missing required JSON transaction fields")
errNoSigner = errors.New("missing signing methods")
ErrInvalidSig = errors.New("invalid transaction v, r, s values")
errNoSigner = errors.New("missing signing methods")
)
// deriveSigner makes a *best* guess about which signer to use.
@ -58,26 +56,31 @@ type Transaction struct {
}
type txdata struct {
AccountNonce uint64
Price, GasLimit *big.Int
Recipient *common.Address `rlp:"nil"` // nil means contract creation
Amount *big.Int
Payload []byte
V *big.Int // signature
R, S *big.Int // signature
}
type jsonTransaction struct {
Hash *common.Hash `json:"hash"`
AccountNonce *hexutil.Uint64 `json:"nonce"`
Price *hexutil.Big `json:"gasPrice"`
GasLimit *hexutil.Big `json:"gas"`
Recipient *common.Address `json:"to"`
Amount *hexutil.Big `json:"value"`
Payload *hexutil.Bytes `json:"input"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
AccountNonce uint64 `json:"nonce"`
Price *big.Int `json:"gasPrice"`
GasLimit *big.Int `json:"gasLimit"`
Recipient *common.Address `json:"to" optional:"yes" rlp:"nil"` // nil means contract creation
Amount *big.Int `json:"value"`
Payload []byte `json:"input"`
// Signature values
V *big.Int `json:"v"`
R *big.Int `json:"r"`
S *big.Int `json:"s"`
// This is only used when marshaling to JSON.
Hash *common.Hash `json:"hash" optional:"yes" rlp:"-"`
}
type txdataMarshaling struct {
AccountNonce hexutil.Uint64
Price *hexutil.Big
GasLimit *hexutil.Big
Amount *hexutil.Big
Payload hexutil.Bytes
V *hexutil.Big
R *hexutil.Big
S *hexutil.Big
}
func NewTransaction(nonce uint64, to common.Address, amount, gasLimit, gasPrice *big.Int, data []byte) *Transaction {
@ -164,66 +167,30 @@ 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 := tx.Hash()
return json.Marshal(&jsonTransaction{
Hash: &hash,
AccountNonce: (*hexutil.Uint64)(&tx.data.AccountNonce),
Price: (*hexutil.Big)(tx.data.Price),
GasLimit: (*hexutil.Big)(tx.data.GasLimit),
Recipient: tx.data.Recipient,
Amount: (*hexutil.Big)(tx.data.Amount),
Payload: (*hexutil.Bytes)(&tx.data.Payload),
V: (*hexutil.Big)(tx.data.V),
R: (*hexutil.Big)(tx.data.R),
S: (*hexutil.Big)(tx.data.S),
})
data := tx.data
data.Hash = &hash
return data.MarshalJSON()
}
// UnmarshalJSON decodes the web3 RPC transaction format.
func (tx *Transaction) UnmarshalJSON(input []byte) error {
var dec jsonTransaction
if err := json.Unmarshal(input, &dec); err != nil {
var dec txdata
if err := dec.UnmarshalJSON(input); err != nil {
return err
}
// Ensure that all fields are set. V, R, S are checked separately because they're a
// recent addition to the RPC spec (as of August 2016) and older implementations might
// not provide them. Note that Recipient is not checked because it can be missing for
// contract creations.
if dec.V == nil || dec.R == nil || dec.S == nil {
return errMissingTxSignatureFields
}
var V byte
if isProtectedV((*big.Int)(dec.V)) {
chainId := deriveChainId((*big.Int)(dec.V)).Uint64()
V = byte(dec.V.ToInt().Uint64() - 35 - 2*chainId)
if isProtectedV(dec.V) {
chainId := deriveChainId(dec.V).Uint64()
V = byte(dec.V.Uint64() - 35 - 2*chainId)
} else {
V = byte(((*big.Int)(dec.V)).Uint64() - 27)
V = byte(dec.V.Uint64() - 27)
}
if !crypto.ValidateSignatureValues(V, (*big.Int)(dec.R), (*big.Int)(dec.S), false) {
if !crypto.ValidateSignatureValues(V, dec.R, dec.S, false) {
return ErrInvalidSig
}
if dec.AccountNonce == nil || dec.Price == nil || dec.GasLimit == nil || dec.Amount == nil || dec.Payload == nil {
return errMissingTxFields
}
// Assign the fields. This is not atomic but reusing transactions
// for decoding isn't thread safe anyway.
*tx = Transaction{}
tx.data = txdata{
AccountNonce: uint64(*dec.AccountNonce),
Recipient: dec.Recipient,
Amount: (*big.Int)(dec.Amount),
GasLimit: (*big.Int)(dec.GasLimit),
Price: (*big.Int)(dec.Price),
Payload: *dec.Payload,
V: (*big.Int)(dec.V),
R: (*big.Int)(dec.R),
S: (*big.Int)(dec.S),
}
*tx = Transaction{data: dec}
return nil
}

Loading…
Cancel
Save