core/types: support yParity field in JSON transactions (#27744)
This adds support for the "yParity" field in transaction objects returned by RPC APIs. We somehow forgot to add this field even though it has been in the spec for a long time.
This commit is contained in:
parent
57cdbaef30
commit
bb148dd342
|
@ -45,11 +45,32 @@ type txJSON struct {
|
|||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
|
||||
// Only used for encoding:
|
||||
Hash common.Hash `json:"hash"`
|
||||
}
|
||||
|
||||
// yParityValue returns the YParity value from JSON. For backwards-compatibility reasons,
|
||||
// this can be given in the 'v' field or the 'yParity' field. If both exist, they must match.
|
||||
func (tx *txJSON) yParityValue() (*big.Int, error) {
|
||||
if tx.YParity != nil {
|
||||
val := uint64(*tx.YParity)
|
||||
if val != 0 && val != 1 {
|
||||
return nil, errors.New("'yParity' field must be 0 or 1")
|
||||
}
|
||||
bigval := new(big.Int).SetUint64(val)
|
||||
if tx.V != nil && tx.V.ToInt().Cmp(bigval) != 0 {
|
||||
return nil, errors.New("'v' and 'yParity' fields do not match")
|
||||
}
|
||||
return bigval, nil
|
||||
}
|
||||
if tx.V != nil {
|
||||
return tx.V.ToInt(), nil
|
||||
}
|
||||
return nil, errors.New("missing 'yParity' or 'v' field in transaction")
|
||||
}
|
||||
|
||||
// MarshalJSON marshals as JSON with a hash.
|
||||
func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
||||
var enc txJSON
|
||||
|
@ -85,6 +106,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
enc.V = (*hexutil.Big)(itx.V)
|
||||
enc.R = (*hexutil.Big)(itx.R)
|
||||
enc.S = (*hexutil.Big)(itx.S)
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
|
||||
case *DynamicFeeTx:
|
||||
enc.ChainID = (*hexutil.Big)(itx.ChainID)
|
||||
|
@ -99,6 +122,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
enc.V = (*hexutil.Big)(itx.V)
|
||||
enc.R = (*hexutil.Big)(itx.R)
|
||||
enc.S = (*hexutil.Big)(itx.S)
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
|
||||
case *BlobTx:
|
||||
enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig())
|
||||
|
@ -115,6 +140,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
enc.V = (*hexutil.Big)(itx.V.ToBig())
|
||||
enc.R = (*hexutil.Big)(itx.R.ToBig())
|
||||
enc.S = (*hexutil.Big)(itx.S.ToBig())
|
||||
yparity := itx.V.Uint64()
|
||||
enc.YParity = (*hexutil.Uint64)(&yparity)
|
||||
}
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
@ -122,7 +149,8 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
|
|||
// UnmarshalJSON unmarshals from JSON.
|
||||
func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
||||
var dec txJSON
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
err := json.Unmarshal(input, &dec)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -155,20 +183,23 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
return errors.New("missing required field 'input' in transaction")
|
||||
}
|
||||
itx.Data = *dec.Input
|
||||
if dec.V == nil {
|
||||
return errors.New("missing required field 'v' in transaction")
|
||||
}
|
||||
itx.V = (*big.Int)(dec.V)
|
||||
|
||||
// signature R
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' in transaction")
|
||||
}
|
||||
itx.R = (*big.Int)(dec.R)
|
||||
// signature S
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' in transaction")
|
||||
}
|
||||
itx.S = (*big.Int)(dec.S)
|
||||
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
|
||||
if withSignature {
|
||||
// signature V
|
||||
if dec.V == nil {
|
||||
return errors.New("missing required field 'v' in transaction")
|
||||
}
|
||||
itx.V = (*big.Int)(dec.V)
|
||||
if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 {
|
||||
if err := sanityCheckSignature(itx.V, itx.R, itx.S, true); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -204,23 +235,26 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
return errors.New("missing required field 'input' in transaction")
|
||||
}
|
||||
itx.Data = *dec.Input
|
||||
if dec.V == nil {
|
||||
return errors.New("missing required field 'v' in transaction")
|
||||
}
|
||||
if dec.AccessList != nil {
|
||||
itx.AccessList = *dec.AccessList
|
||||
}
|
||||
itx.V = (*big.Int)(dec.V)
|
||||
|
||||
// signature R
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' in transaction")
|
||||
}
|
||||
itx.R = (*big.Int)(dec.R)
|
||||
// signature S
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' in transaction")
|
||||
}
|
||||
itx.S = (*big.Int)(dec.S)
|
||||
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
|
||||
if withSignature {
|
||||
// signature V
|
||||
itx.V, err = dec.yParityValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 {
|
||||
if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -266,17 +300,23 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
if dec.AccessList != nil {
|
||||
itx.AccessList = *dec.AccessList
|
||||
}
|
||||
itx.V = (*big.Int)(dec.V)
|
||||
|
||||
// signature R
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' in transaction")
|
||||
}
|
||||
itx.R = (*big.Int)(dec.R)
|
||||
// signature S
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' in transaction")
|
||||
}
|
||||
itx.S = (*big.Int)(dec.S)
|
||||
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
|
||||
if withSignature {
|
||||
// signature V
|
||||
itx.V, err = dec.yParityValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 {
|
||||
if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -331,18 +371,35 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
|
|||
return errors.New("missing required field 'blobVersionedHashes' in transaction")
|
||||
}
|
||||
itx.BlobHashes = dec.BlobVersionedHashes
|
||||
itx.V = uint256.MustFromBig((*big.Int)(dec.V))
|
||||
|
||||
// signature R
|
||||
var ok bool
|
||||
if dec.R == nil {
|
||||
return errors.New("missing required field 'r' in transaction")
|
||||
}
|
||||
itx.R = uint256.MustFromBig((*big.Int)(dec.R))
|
||||
itx.R, ok = uint256.FromBig((*big.Int)(dec.R))
|
||||
if !ok {
|
||||
return errors.New("'r' value overflows uint256")
|
||||
}
|
||||
// signature S
|
||||
if dec.S == nil {
|
||||
return errors.New("missing required field 's' in transaction")
|
||||
}
|
||||
itx.S = uint256.MustFromBig((*big.Int)(dec.S))
|
||||
withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0
|
||||
if withSignature {
|
||||
if err := sanityCheckSignature(itx.V.ToBig(), itx.R.ToBig(), itx.S.ToBig(), false); err != nil {
|
||||
itx.S, ok = uint256.FromBig((*big.Int)(dec.S))
|
||||
if !ok {
|
||||
return errors.New("'s' value overflows uint256")
|
||||
}
|
||||
// signature V
|
||||
vbig, err := dec.yParityValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
itx.V, ok = uint256.FromBig(vbig)
|
||||
if !ok {
|
||||
return errors.New("'v' value overflows uint256")
|
||||
}
|
||||
if itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 {
|
||||
if err := sanityCheckSignature(vbig, itx.R.ToBig(), itx.S.ToBig(), false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1375,6 +1375,7 @@ type RPCTransaction struct {
|
|||
V *hexutil.Big `json:"v"`
|
||||
R *hexutil.Big `json:"r"`
|
||||
S *hexutil.Big `json:"s"`
|
||||
YParity *hexutil.Uint64 `json:"yParity,omitempty"`
|
||||
}
|
||||
|
||||
// newRPCTransaction returns a transaction that will serialize to the RPC
|
||||
|
@ -1402,20 +1403,27 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
|
|||
result.BlockNumber = (*hexutil.Big)(new(big.Int).SetUint64(blockNumber))
|
||||
result.TransactionIndex = (*hexutil.Uint64)(&index)
|
||||
}
|
||||
|
||||
switch tx.Type() {
|
||||
case types.LegacyTxType:
|
||||
// if a legacy transaction has an EIP-155 chain id, include it explicitly
|
||||
if id := tx.ChainId(); id.Sign() != 0 {
|
||||
result.ChainID = (*hexutil.Big)(id)
|
||||
}
|
||||
|
||||
case types.AccessListTxType:
|
||||
al := tx.AccessList()
|
||||
yparity := hexutil.Uint64(v.Sign())
|
||||
result.Accesses = &al
|
||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||
result.YParity = &yparity
|
||||
|
||||
case types.DynamicFeeTxType:
|
||||
al := tx.AccessList()
|
||||
yparity := hexutil.Uint64(v.Sign())
|
||||
result.Accesses = &al
|
||||
result.ChainID = (*hexutil.Big)(tx.ChainId())
|
||||
result.YParity = &yparity
|
||||
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
|
||||
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
|
||||
// if the transaction has been mined, compute the effective gas price
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue