core/types: change SetCodeTx.ChainID to uint256 (#30982)

We still need to decide how to handle non-specfic `chainId` in the JSON
encoding of authorizations. With `chainId` being a uint64, the previous
implementation just used value zero. However, it might actually be more
correct to use the value `null` for this case.
This commit is contained in:
Felix Lange 2025-01-14 14:42:18 +01:00 committed by GitHub
parent 1843f27766
commit 04a336aee8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 44 additions and 38 deletions

View File

@ -4265,12 +4265,11 @@ func TestEIP7702(t *testing.T) {
// 2. addr1:0xaaaa calls into addr2:0xbbbb // 2. addr1:0xaaaa calls into addr2:0xbbbb
// 3. addr2:0xbbbb writes to storage // 3. addr2:0xbbbb writes to storage
auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{ auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: gspec.Config.ChainID.Uint64(), ChainID: *uint256.MustFromBig(gspec.Config.ChainID),
Address: aa, Address: aa,
Nonce: 1, Nonce: 1,
}) })
auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{ auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
ChainID: 0,
Address: bb, Address: bb,
Nonce: 0, Nonce: 0,
}) })
@ -4278,7 +4277,7 @@ func TestEIP7702(t *testing.T) {
_, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) { _, blocks, _ := GenerateChainWithGenesis(gspec, engine, 1, func(i int, b *BlockGen) {
b.SetCoinbase(aa) b.SetCoinbase(aa)
txdata := &types.SetCodeTx{ txdata := &types.SetCodeTx{
ChainID: gspec.Config.ChainID.Uint64(), ChainID: uint256.MustFromBig(gspec.Config.ChainID),
Nonce: 0, Nonce: 0,
To: addr1, To: addr1,
Gas: 500000, Gas: 500000,

View File

@ -529,8 +529,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// validateAuthorization validates an EIP-7702 authorization against the state. // validateAuthorization validates an EIP-7702 authorization against the state.
func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) { func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorization) (authority common.Address, err error) {
// Verify chain ID is 0 or equal to current chain ID. // Verify chain ID is null or equal to current chain ID.
if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { if !auth.ChainID.IsZero() && auth.ChainID.CmpBig(st.evm.ChainConfig().ChainID) != 0 {
return authority, ErrAuthorizationWrongChainID return authority, ErrAuthorizationWrongChainID
} }
// Limit nonce to 2^64-1 per EIP-2681. // Limit nonce to 2^64-1 per EIP-2681.

View File

@ -16,7 +16,7 @@ var _ = (*authorizationMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) { func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
type SetCodeAuthorization struct { type SetCodeAuthorization struct {
ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` ChainID hexutil.U256 `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"`
Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"` Nonce hexutil.Uint64 `json:"nonce" gencodec:"required"`
V hexutil.Uint64 `json:"yParity" gencodec:"required"` V hexutil.Uint64 `json:"yParity" gencodec:"required"`
@ -24,7 +24,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
S hexutil.U256 `json:"s" gencodec:"required"` S hexutil.U256 `json:"s" gencodec:"required"`
} }
var enc SetCodeAuthorization var enc SetCodeAuthorization
enc.ChainID = hexutil.Uint64(s.ChainID) enc.ChainID = hexutil.U256(s.ChainID)
enc.Address = s.Address enc.Address = s.Address
enc.Nonce = hexutil.Uint64(s.Nonce) enc.Nonce = hexutil.Uint64(s.Nonce)
enc.V = hexutil.Uint64(s.V) enc.V = hexutil.Uint64(s.V)
@ -36,7 +36,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error { func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error {
type SetCodeAuthorization struct { type SetCodeAuthorization struct {
ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` ChainID *hexutil.U256 `json:"chainId" gencodec:"required"`
Address *common.Address `json:"address" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"`
Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"` Nonce *hexutil.Uint64 `json:"nonce" gencodec:"required"`
V *hexutil.Uint64 `json:"yParity" gencodec:"required"` V *hexutil.Uint64 `json:"yParity" gencodec:"required"`
@ -50,7 +50,7 @@ func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error {
if dec.ChainID == nil { if dec.ChainID == nil {
return errors.New("missing required field 'chainId' for SetCodeAuthorization") return errors.New("missing required field 'chainId' for SetCodeAuthorization")
} }
s.ChainID = uint64(*dec.ChainID) s.ChainID = uint256.Int(*dec.ChainID)
if dec.Address == nil { if dec.Address == nil {
return errors.New("missing required field 'address' for SetCodeAuthorization") return errors.New("missing required field 'address' for SetCodeAuthorization")
} }

View File

@ -155,7 +155,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) {
enc.Proofs = itx.Sidecar.Proofs enc.Proofs = itx.Sidecar.Proofs
} }
case *SetCodeTx: case *SetCodeTx:
enc.ChainID = (*hexutil.Big)(new(big.Int).SetUint64(itx.ChainID)) enc.ChainID = (*hexutil.Big)(itx.ChainID.ToBig())
enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.Nonce = (*hexutil.Uint64)(&itx.Nonce)
enc.To = tx.To() enc.To = tx.To()
enc.Gas = (*hexutil.Uint64)(&itx.Gas) enc.Gas = (*hexutil.Uint64)(&itx.Gas)
@ -353,7 +353,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
if dec.ChainID == nil { if dec.ChainID == nil {
return errors.New("missing required field 'chainId' in transaction") return errors.New("missing required field 'chainId' in transaction")
} }
itx.ChainID = uint256.MustFromBig((*big.Int)(dec.ChainID)) var overflow bool
itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt())
if overflow {
return errors.New("'chainId' value overflows uint256")
}
if dec.Nonce == nil { if dec.Nonce == nil {
return errors.New("missing required field 'nonce' in transaction") return errors.New("missing required field 'nonce' in transaction")
} }
@ -395,7 +399,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
itx.BlobHashes = dec.BlobVersionedHashes itx.BlobHashes = dec.BlobVersionedHashes
// signature R // signature R
var overflow bool
if dec.R == nil { if dec.R == nil {
return errors.New("missing required field 'r' in transaction") return errors.New("missing required field 'r' in transaction")
} }
@ -432,7 +435,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
if dec.ChainID == nil { if dec.ChainID == nil {
return errors.New("missing required field 'chainId' in transaction") return errors.New("missing required field 'chainId' in transaction")
} }
itx.ChainID = dec.ChainID.ToInt().Uint64() var overflow bool
itx.ChainID, overflow = uint256.FromBig(dec.ChainID.ToInt())
if overflow {
return errors.New("'chainId' value overflows uint256")
}
if dec.Nonce == nil { if dec.Nonce == nil {
return errors.New("missing required field 'nonce' in transaction") return errors.New("missing required field 'nonce' in transaction")
} }
@ -470,7 +477,6 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error {
itx.AuthList = dec.AuthorizationList itx.AuthList = dec.AuthorizationList
// signature R // signature R
var overflow bool
if dec.R == nil { if dec.R == nil {
return errors.New("missing required field 'r' in transaction") return errors.New("missing required field 'r' in transaction")
} }

View File

@ -219,7 +219,7 @@ func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
} }
// Check that chain ID of tx matches the signer. We also accept ID zero here, // Check that chain ID of tx matches the signer. We also accept ID zero here,
// because it indicates that the chain ID was not specified in the tx. // because it indicates that the chain ID was not specified in the tx.
if txdata.ChainID != 0 && new(big.Int).SetUint64(txdata.ChainID).Cmp(s.chainId) != 0 { if txdata.ChainID != nil && txdata.ChainID.CmpBig(s.chainId) != 0 {
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
} }
R, S, _ = decodeSignature(sig) R, S, _ = decodeSignature(sig)

View File

@ -47,9 +47,9 @@ type BlobTx struct {
Sidecar *BlobTxSidecar `rlp:"-"` Sidecar *BlobTxSidecar `rlp:"-"`
// Signature values // Signature values
V *uint256.Int `json:"v" gencodec:"required"` V *uint256.Int
R *uint256.Int `json:"r" gencodec:"required"` R *uint256.Int
S *uint256.Int `json:"s" gencodec:"required"` S *uint256.Int
} }
// BlobTxSidecar contains the blobs of a blob transaction. // BlobTxSidecar contains the blobs of a blob transaction.

View File

@ -37,9 +37,9 @@ type DynamicFeeTx struct {
AccessList AccessList AccessList AccessList
// Signature values // Signature values
V *big.Int `json:"v" gencodec:"required"` V *big.Int
R *big.Int `json:"r" gencodec:"required"` R *big.Int
S *big.Int `json:"s" gencodec:"required"` S *big.Int
} }
// copy creates a deep copy of the transaction data and initializes all fields. // copy creates a deep copy of the transaction data and initializes all fields.

View File

@ -49,7 +49,7 @@ func AddressToDelegation(addr common.Address) []byte {
// SetCodeTx implements the EIP-7702 transaction type which temporarily installs // SetCodeTx implements the EIP-7702 transaction type which temporarily installs
// the code at the signer's address. // the code at the signer's address.
type SetCodeTx struct { type SetCodeTx struct {
ChainID uint64 ChainID *uint256.Int
Nonce uint64 Nonce uint64
GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas GasTipCap *uint256.Int // a.k.a. maxPriorityFeePerGas
GasFeeCap *uint256.Int // a.k.a. maxFeePerGas GasFeeCap *uint256.Int // a.k.a. maxFeePerGas
@ -61,16 +61,16 @@ type SetCodeTx struct {
AuthList []SetCodeAuthorization AuthList []SetCodeAuthorization
// Signature values // Signature values
V *uint256.Int `json:"v" gencodec:"required"` V *uint256.Int
R *uint256.Int `json:"r" gencodec:"required"` R *uint256.Int
S *uint256.Int `json:"s" gencodec:"required"` S *uint256.Int
} }
//go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go //go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go
// SetCodeAuthorization is an authorization from an account to deploy code at its address. // SetCodeAuthorization is an authorization from an account to deploy code at its address.
type SetCodeAuthorization struct { type SetCodeAuthorization struct {
ChainID uint64 `json:"chainId" gencodec:"required"` ChainID uint256.Int `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"`
Nonce uint64 `json:"nonce" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"`
V uint8 `json:"yParity" gencodec:"required"` V uint8 `json:"yParity" gencodec:"required"`
@ -80,7 +80,7 @@ type SetCodeAuthorization struct {
// field type overrides for gencodec // field type overrides for gencodec
type authorizationMarshaling struct { type authorizationMarshaling struct {
ChainID hexutil.Uint64 ChainID hexutil.U256
Nonce hexutil.Uint64 Nonce hexutil.Uint64
V hexutil.Uint64 V hexutil.Uint64
R hexutil.U256 R hexutil.U256
@ -180,7 +180,7 @@ func (tx *SetCodeTx) copy() TxData {
// accessors for innerTx. // accessors for innerTx.
func (tx *SetCodeTx) txType() byte { return SetCodeTxType } func (tx *SetCodeTx) txType() byte { return SetCodeTxType }
func (tx *SetCodeTx) chainID() *big.Int { return big.NewInt(int64(tx.ChainID)) } func (tx *SetCodeTx) chainID() *big.Int { return tx.ChainID.ToBig() }
func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList } func (tx *SetCodeTx) accessList() AccessList { return tx.AccessList }
func (tx *SetCodeTx) data() []byte { return tx.Data } func (tx *SetCodeTx) data() []byte { return tx.Data }
func (tx *SetCodeTx) gas() uint64 { return tx.Gas } func (tx *SetCodeTx) gas() uint64 { return tx.Gas }
@ -207,7 +207,7 @@ func (tx *SetCodeTx) rawSignatureValues() (v, r, s *big.Int) {
} }
func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) { func (tx *SetCodeTx) setSignatureValues(chainID, v, r, s *big.Int) {
tx.ChainID = chainID.Uint64() tx.ChainID = uint256.MustFromBig(chainID)
tx.V.SetFromBig(v) tx.V.SetFromBig(v)
tx.R.SetFromBig(r) tx.R.SetFromBig(r)
tx.S.SetFromBig(s) tx.S.SetFromBig(s)

View File

@ -503,7 +503,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
} }
data = &types.SetCodeTx{ data = &types.SetCodeTx{
To: *args.To, To: *args.To,
ChainID: args.ChainID.ToInt().Uint64(), ChainID: uint256.MustFromBig(args.ChainID.ToInt()),
Nonce: uint64(*args.Nonce), Nonce: uint64(*args.Nonce),
Gas: uint64(*args.Gas), Gas: uint64(*args.Gas),
GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)), GasFeeCap: uint256.MustFromBig((*big.Int)(args.MaxFeePerGas)),

View File

@ -16,7 +16,7 @@ var _ = (*stAuthorizationMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (s stAuthorization) MarshalJSON() ([]byte, error) { func (s stAuthorization) MarshalJSON() ([]byte, error) {
type stAuthorization struct { type stAuthorization struct {
ChainID math.HexOrDecimal64 ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"`
Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"` Nonce math.HexOrDecimal64 `json:"nonce" gencodec:"required"`
V math.HexOrDecimal64 `json:"v" gencodec:"required"` V math.HexOrDecimal64 `json:"v" gencodec:"required"`
@ -24,7 +24,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) {
S *math.HexOrDecimal256 `json:"s" gencodec:"required"` S *math.HexOrDecimal256 `json:"s" gencodec:"required"`
} }
var enc stAuthorization var enc stAuthorization
enc.ChainID = math.HexOrDecimal64(s.ChainID) enc.ChainID = (*math.HexOrDecimal256)(s.ChainID)
enc.Address = s.Address enc.Address = s.Address
enc.Nonce = math.HexOrDecimal64(s.Nonce) enc.Nonce = math.HexOrDecimal64(s.Nonce)
enc.V = math.HexOrDecimal64(s.V) enc.V = math.HexOrDecimal64(s.V)
@ -36,7 +36,7 @@ func (s stAuthorization) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (s *stAuthorization) UnmarshalJSON(input []byte) error { func (s *stAuthorization) UnmarshalJSON(input []byte) error {
type stAuthorization struct { type stAuthorization struct {
ChainID *math.HexOrDecimal64 ChainID *math.HexOrDecimal256 `json:"chainId" gencodec:"required"`
Address *common.Address `json:"address" gencodec:"required"` Address *common.Address `json:"address" gencodec:"required"`
Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"` Nonce *math.HexOrDecimal64 `json:"nonce" gencodec:"required"`
V *math.HexOrDecimal64 `json:"v" gencodec:"required"` V *math.HexOrDecimal64 `json:"v" gencodec:"required"`
@ -47,9 +47,10 @@ func (s *stAuthorization) UnmarshalJSON(input []byte) error {
if err := json.Unmarshal(input, &dec); err != nil { if err := json.Unmarshal(input, &dec); err != nil {
return err return err
} }
if dec.ChainID != nil { if dec.ChainID == nil {
s.ChainID = uint64(*dec.ChainID) return errors.New("missing required field 'chainId' for stAuthorization")
} }
s.ChainID = (*big.Int)(dec.ChainID)
if dec.Address == nil { if dec.Address == nil {
return errors.New("missing required field 'address' for stAuthorization") return errors.New("missing required field 'address' for stAuthorization")
} }

View File

@ -140,7 +140,7 @@ type stTransactionMarshaling struct {
// Authorization is an authorization from an account to deploy code at it's address. // Authorization is an authorization from an account to deploy code at it's address.
type stAuthorization struct { type stAuthorization struct {
ChainID uint64 ChainID *big.Int `json:"chainId" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"` Address common.Address `json:"address" gencodec:"required"`
Nonce uint64 `json:"nonce" gencodec:"required"` Nonce uint64 `json:"nonce" gencodec:"required"`
V uint8 `json:"v" gencodec:"required"` V uint8 `json:"v" gencodec:"required"`
@ -150,7 +150,7 @@ type stAuthorization struct {
// field type overrides for gencodec // field type overrides for gencodec
type stAuthorizationMarshaling struct { type stAuthorizationMarshaling struct {
ChainID math.HexOrDecimal64 ChainID *math.HexOrDecimal256
Nonce math.HexOrDecimal64 Nonce math.HexOrDecimal64
V math.HexOrDecimal64 V math.HexOrDecimal64
R *math.HexOrDecimal256 R *math.HexOrDecimal256
@ -446,7 +446,7 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList)) authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList))
for i, auth := range tx.AuthorizationList { for i, auth := range tx.AuthorizationList {
authList[i] = types.SetCodeAuthorization{ authList[i] = types.SetCodeAuthorization{
ChainID: auth.ChainID, ChainID: *uint256.MustFromBig(auth.ChainID),
Address: auth.Address, Address: auth.Address,
Nonce: auth.Nonce, Nonce: auth.Nonce,
V: auth.V, V: auth.V,