aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@users.noreply.github.com>2017-03-22 08:36:22 +0800
committerGitHub <noreply@github.com>2017-03-22 08:36:22 +0800
commit06d6685eb58f6cb0eda4d7adc8ae91e5cdb88462 (patch)
treed764690055f2ee7d880bcce2e413a3665fc1e7e9
parent1dfd65f6d047407585845dfe9be2ff52a8b9f3ab (diff)
parent8cf08e4b25c4cd0e0955598342394f34feecca0c (diff)
downloadgo-tangerine-06d6685eb58f6cb0eda4d7adc8ae91e5cdb88462.tar.gz
go-tangerine-06d6685eb58f6cb0eda4d7adc8ae91e5cdb88462.tar.zst
go-tangerine-06d6685eb58f6cb0eda4d7adc8ae91e5cdb88462.zip
Merge pull request #3756 from fjl/core-types-gencodec
core/types: use gencodec for JSON marshaling code
-rw-r--r--Makefile9
-rw-r--r--core/types/block.go127
-rw-r--r--core/types/gen_header_json.go136
-rw-r--r--core/types/gen_log_json.go90
-rw-r--r--core/types/gen_receipt_json.go79
-rw-r--r--core/types/gen_tx_json.go99
-rw-r--r--core/types/log.go99
-rw-r--r--core/types/log_test.go3
-rw-r--r--core/types/receipt.go78
-rw-r--r--core/types/transaction.go111
-rw-r--r--internal/jsre/deps/bindata.go4
-rw-r--r--internal/jsre/deps/deps.go3
-rw-r--r--rlp/decode.go16
-rw-r--r--rlp/decode_test.go13
-rw-r--r--rlp/encode_test.go1
-rw-r--r--rlp/typecache.go8
16 files changed, 554 insertions, 322 deletions
diff --git a/Makefile b/Makefile
index 4bd5612be..07bacba65 100644
--- a/Makefile
+++ b/Makefile
@@ -40,6 +40,15 @@ test: all
clean:
rm -fr build/_workspace/pkg/ $(GOBIN)/*
+# The devtools target installs tools required for 'go generate'.
+# You need to put $GOBIN (or $GOPATH/bin) in your PATH to use 'go generate'.
+
+devtools:
+ go get -u golang.org/x/tools/cmd/stringer
+ go get -u github.com/jteeuwen/go-bindata/go-bindata
+ go get -u github.com/fjl/gencodec
+ go install ./cmd/abigen
+
# Cross Compilation Targets (xgo)
geth-cross: geth-linux geth-darwin geth-windows geth-android geth-ios
diff --git a/core/types/block.go b/core/types/block.go
index 1dae87962..b699ba686 100644
--- a/core/types/block.go
+++ b/core/types/block.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)
diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go
new file mode 100644
index 000000000..860622e6e
--- /dev/null
+++ b/core/types/gen_header_json.go
@@ -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
+}
diff --git a/core/types/gen_log_json.go b/core/types/gen_log_json.go
new file mode 100644
index 000000000..ef2cdfd89
--- /dev/null
+++ b/core/types/gen_log_json.go
@@ -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
+}
diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go
new file mode 100644
index 000000000..b9e9bee26
--- /dev/null
+++ b/core/types/gen_receipt_json.go
@@ -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
+}
diff --git a/core/types/gen_tx_json.go b/core/types/gen_tx_json.go
new file mode 100644
index 000000000..8bbe629d7
--- /dev/null
+++ b/core/types/gen_tx_json.go
@@ -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
+}
diff --git a/core/types/log.go b/core/types/log.go
index 7efb06b5c..57fc7b363 100644
--- a/core/types/log.go
+++ b/core/types/log.go
@@ -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
diff --git a/core/types/log_test.go b/core/types/log_test.go
index bf742ccac..0e56acfe4 100644
--- a/core/types/log_test.go
+++ b/core/types/log_test.go
@@ -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"),
},
}
diff --git a/core/types/receipt.go b/core/types/receipt.go
index 0a6a35e33..5bfcb15fc 100644
--- a/core/types/receipt.go
+++ b/core/types/receipt.go
@@ -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)
diff --git a/core/types/transaction.go b/core/types/transaction.go
index ab0bba4dc..a02f9ed00 100644
--- a/core/types/transaction.go
+++ b/core/types/transaction.go
@@ -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
}
diff --git a/internal/jsre/deps/bindata.go b/internal/jsre/deps/bindata.go
index 5f6a2b873..782d4df80 100644
--- a/internal/jsre/deps/bindata.go
+++ b/internal/jsre/deps/bindata.go
@@ -84,7 +84,7 @@ func bignumberJs() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "bignumber.js", size: 17314, mode: os.FileMode(420), modTime: time.Unix(1484232218, 0)}
+ info := bindataFileInfo{name: "bignumber.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
@@ -104,7 +104,7 @@ func web3Js() (*asset, error) {
return nil, err
}
- info := bindataFileInfo{name: "web3.js", size: 491740, mode: os.FileMode(420), modTime: time.Unix(1484232456, 0)}
+ info := bindataFileInfo{name: "web3.js", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
diff --git a/internal/jsre/deps/deps.go b/internal/jsre/deps/deps.go
index 8d0e1a400..fe2e6f2fa 100644
--- a/internal/jsre/deps/deps.go
+++ b/internal/jsre/deps/deps.go
@@ -17,4 +17,5 @@
// Package deps contains the console JavaScript dependencies Go embedded.
package deps
-//go:generate go-bindata -o bindata.go bignumber.js web3.js
+//go:generate go-bindata -nometadata -pkg deps -o bindata.go bignumber.js web3.js
+//go:generate gofmt -w -s bindata.go
diff --git a/rlp/decode.go b/rlp/decode.go
index c4e5869cc..ee0b7dbcd 100644
--- a/rlp/decode.go
+++ b/rlp/decode.go
@@ -63,12 +63,16 @@ type Decoder interface {
// must contain an element for each decoded field. Decode returns an
// error if there are too few or too many elements.
//
-// The decoding of struct fields honours two struct tags, "tail" and
-// "nil". For an explanation of "tail", see the example.
-// The "nil" tag applies to pointer-typed fields and changes the
-// decoding rules for the field such that input values of size zero
-// decode as a nil pointer. This tag can be useful when decoding
-// recursive types.
+// The decoding of struct fields honours certain struct tags, "tail",
+// "nil" and "-".
+//
+// The "-" tag ignores fields.
+//
+// For an explanation of "tail", see the example.
+//
+// The "nil" tag applies to pointer-typed fields and changes the decoding
+// rules for the field such that input values of size zero decode as a nil
+// pointer. This tag can be useful when decoding recursive types.
//
// type StructWithEmptyOK struct {
// Foo *[20]byte `rlp:"nil"`
diff --git a/rlp/decode_test.go b/rlp/decode_test.go
index 2d465b74d..d762e195d 100644
--- a/rlp/decode_test.go
+++ b/rlp/decode_test.go
@@ -339,6 +339,12 @@ var (
)
)
+type hasIgnoredField struct {
+ A uint
+ B uint `rlp:"-"`
+ C uint
+}
+
var decodeTests = []decodeTest{
// booleans
{input: "01", ptr: new(bool), value: true},
@@ -490,6 +496,13 @@ var decodeTests = []decodeTest{
value: tailRaw{A: 1, Tail: []RawValue{}},
},
+ // struct tag "-"
+ {
+ input: "C20102",
+ ptr: new(hasIgnoredField),
+ value: hasIgnoredField{A: 1, C: 2},
+ },
+
// RawValue
{input: "01", ptr: new(RawValue), value: RawValue(unhex("01"))},
{input: "82FFFF", ptr: new(RawValue), value: RawValue(unhex("82FFFF"))},
diff --git a/rlp/encode_test.go b/rlp/encode_test.go
index 6f38294e4..827960f7c 100644
--- a/rlp/encode_test.go
+++ b/rlp/encode_test.go
@@ -218,6 +218,7 @@ var encTests = []encTest{
{val: &tailRaw{A: 1, Tail: []RawValue{unhex("02")}}, output: "C20102"},
{val: &tailRaw{A: 1, Tail: []RawValue{}}, output: "C101"},
{val: &tailRaw{A: 1, Tail: nil}, output: "C101"},
+ {val: &hasIgnoredField{A: 1, B: 2, C: 3}, output: "C20103"},
// nil
{val: (*uint)(nil), output: "80"},
diff --git a/rlp/typecache.go b/rlp/typecache.go
index a2f217c66..3df799e1e 100644
--- a/rlp/typecache.go
+++ b/rlp/typecache.go
@@ -37,11 +37,12 @@ type typeinfo struct {
type tags struct {
// rlp:"nil" controls whether empty input results in a nil pointer.
nilOK bool
-
// rlp:"tail" controls whether this field swallows additional list
// elements. It can only be set for the last field, which must be
// of slice type.
tail bool
+ // rlp:"-" ignores fields.
+ ignored bool
}
type typekey struct {
@@ -101,6 +102,9 @@ func structFields(typ reflect.Type) (fields []field, err error) {
if err != nil {
return nil, err
}
+ if tags.ignored {
+ continue
+ }
info, err := cachedTypeInfo1(f.Type, tags)
if err != nil {
return nil, err
@@ -117,6 +121,8 @@ func parseStructTag(typ reflect.Type, fi int) (tags, error) {
for _, t := range strings.Split(f.Tag.Get("rlp"), ",") {
switch t = strings.TrimSpace(t); t {
case "":
+ case "-":
+ ts.ignored = true
case "nil":
ts.nilOK = true
case "tail":