core/types, core/vm: improve docs, add JSON marshaling methods

In this commit, core/types's types learn how to encode and decode
themselves as JSON. The encoding is very similar to what the RPC API
uses. The RPC API is missing some output fields (e.g. transaction
signature values) which will be added to the API in a later commit. Some
fields that the API generates are ignored by the decoder methods here.
This commit is contained in:
Felix Lange
2016-08-04 03:55:33 +02:00
parent 0c9a858f2d
commit 704fde01e8
8 changed files with 590 additions and 100 deletions

View File

@ -18,6 +18,7 @@ package vm
import (
"encoding/json"
"errors"
"fmt"
"io"
@ -25,18 +26,33 @@ import (
"github.com/ethereum/go-ethereum/rlp"
)
type Log struct {
// Consensus fields
Address common.Address
Topics []common.Hash
Data []byte
var errMissingLogFields = errors.New("missing required JSON log fields")
// Derived fields (don't reorder!)
BlockNumber uint64
TxHash common.Hash
TxIndex uint
BlockHash common.Hash
Index uint
// 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
// Derived fields (don't reorder!).
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
}
type jsonLog struct {
Address *common.Address `json:"address"`
Topics *[]common.Hash `json:"topics"`
Data string `json:"data"`
BlockNumber string `json:"blockNumber"`
TxIndex string `json:"transactionIndex"`
TxHash *common.Hash `json:"transactionHash"`
BlockHash *common.Hash `json:"blockHash"`
Index string `json:"logIndex"`
}
func NewLog(address common.Address, topics []common.Hash, data []byte, number uint64) *Log {
@ -64,19 +80,50 @@ 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 (r *Log) MarshalJSON() ([]byte, error) {
fields := map[string]interface{}{
"address": r.Address,
"data": fmt.Sprintf("%#x", r.Data),
"blockNumber": fmt.Sprintf("%#x", r.BlockNumber),
"logIndex": fmt.Sprintf("%#x", r.Index),
"blockHash": r.BlockHash,
"transactionHash": r.TxHash,
"transactionIndex": fmt.Sprintf("%#x", r.TxIndex),
"topics": r.Topics,
}
return json.Marshal(&jsonLog{
Address: &r.Address,
Topics: &r.Topics,
Data: fmt.Sprintf("0x%x", r.Data),
BlockNumber: fmt.Sprintf("0x%x", r.BlockNumber),
TxIndex: fmt.Sprintf("0x%x", r.TxIndex),
TxHash: &r.TxHash,
BlockHash: &r.BlockHash,
Index: fmt.Sprintf("0x%x", r.Index),
})
}
return json.Marshal(fields)
// UnmarshalJSON implements json.Umarshaler.
func (r *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 == "" || dec.BlockNumber == "" ||
dec.TxIndex == "" || dec.TxHash == nil || dec.BlockHash == nil || dec.Index == "" {
return errMissingLogFields
}
declog := Log{
Address: *dec.Address,
Topics: *dec.Topics,
TxHash: *dec.TxHash,
BlockHash: *dec.BlockHash,
}
if _, err := fmt.Sscanf(dec.Data, "0x%x", &declog.Data); err != nil {
return fmt.Errorf("invalid hex log data")
}
if _, err := fmt.Sscanf(dec.BlockNumber, "0x%x", &declog.BlockNumber); err != nil {
return fmt.Errorf("invalid hex log block number")
}
if _, err := fmt.Sscanf(dec.TxIndex, "0x%x", &declog.TxIndex); err != nil {
return fmt.Errorf("invalid hex log tx index")
}
if _, err := fmt.Sscanf(dec.Index, "0x%x", &declog.Index); err != nil {
return fmt.Errorf("invalid hex log index")
}
*r = declog
return nil
}
type Logs []*Log