aboutsummaryrefslogtreecommitdiffstats
path: root/core/types/transaction.go
diff options
context:
space:
mode:
Diffstat (limited to 'core/types/transaction.go')
-rw-r--r--core/types/transaction.go111
1 files changed, 39 insertions, 72 deletions
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
}