New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
core/types: support yParity field in JSON transactions #27744
Changes from all commits
0fab0ae
6521309
4ac5f8c
5e96fd7
2a3bc6f
eb2188c
00679a8
ea208a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -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,14 +140,17 @@ 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) | ||||||||
} | ||||||||
|
||||||||
// 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 { | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. So before this change, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have restored this behavior now, but I don't really get it. The signature values are mandatory, but all-zero is OK? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only place I am aware this functionality is used is in t8n to denote that the transaction should be signed using the provided go-ethereum/cmd/evm/testdata/8/txs.json Lines 19 to 21 in 7f756dc
Would probably be good to get rid of all-zero values at some point, but I'm not sure what else depends on this behavior. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Either way it doesn't matter since an all zero signature will be invalid anyway. |
||||||||
// 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 | ||||||||
} | ||||||||
} | ||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why change the ordering?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seemed to look better to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels weird to have them out of order.
v
,r
,s
ordering is pretty widely understood.