core, core/types: implement unchained flag in SetCodeAuthorization

This commit is contained in:
Felix Lange 2024-12-19 10:35:10 +01:00
parent f1e6372eea
commit 979f7c9776
4 changed files with 52 additions and 50 deletions

View file

@ -4273,13 +4273,12 @@ func TestEIP7702(t *testing.T) {
// 1. tx -> addr1 which is delegated to 0xaaaa // 1. tx -> addr1 which is delegated to 0xaaaa
// 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, gspec.Config.ChainID, types.SetCodeAuthorization{
ChainID: gspec.Config.ChainID.Uint64(),
Address: aa, Address: aa,
Nonce: 1, Nonce: 1,
}) })
auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{ auth2, _ := types.SignSetCode(key2, gspec.Config.ChainID, types.SetCodeAuthorization{
ChainID: 0, Unchained: true,
Address: bb, Address: bb,
Nonce: 0, Nonce: 0,
}) })

View file

@ -529,16 +529,12 @@ 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.
if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID {
return authority, ErrAuthorizationWrongChainID
}
// Limit nonce to 2^64-1 per EIP-2681. // Limit nonce to 2^64-1 per EIP-2681.
if auth.Nonce+1 < auth.Nonce { if auth.Nonce+1 < auth.Nonce {
return authority, ErrAuthorizationNonceOverflow return authority, ErrAuthorizationNonceOverflow
} }
// Validate signature values and recover authority. // Validate signature values and recover authority.
authority, err = auth.Authority() authority, err = auth.Authority(st.evm.ChainConfig().ChainID)
if err != nil { if err != nil {
return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err) return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err)
} }

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"` Unchained bool `json:"unchained" 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.Unchained = s.Unchained
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"` Unchained *bool `json:"unchained" 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"`
@ -47,10 +47,10 @@ func (s *SetCodeAuthorization) 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.Unchained == nil {
return errors.New("missing required field 'chainId' for SetCodeAuthorization") return errors.New("missing required field 'unchained' for SetCodeAuthorization")
} }
s.ChainID = uint64(*dec.ChainID) s.Unchained = *dec.Unchained
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

@ -70,7 +70,7 @@ type SetCodeTx struct {
// 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"` Unchained bool `json:"unchained" 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,6 @@ type SetCodeAuthorization struct {
// field type overrides for gencodec // field type overrides for gencodec
type authorizationMarshaling struct { type authorizationMarshaling struct {
ChainID hexutil.Uint64
Nonce hexutil.Uint64 Nonce hexutil.Uint64
V hexutil.Uint64 V hexutil.Uint64
R hexutil.U256 R hexutil.U256
@ -88,15 +87,15 @@ type authorizationMarshaling struct {
} }
// SignSetCode creates a signed the SetCode authorization. // SignSetCode creates a signed the SetCode authorization.
func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAuthorization, error) { func SignSetCode(prv *ecdsa.PrivateKey, chainID *big.Int, auth SetCodeAuthorization) (SetCodeAuthorization, error) {
sighash := auth.sigHash() sighash := auth.sigHash(chainID)
sig, err := crypto.Sign(sighash[:], prv) sig, err := crypto.Sign(sighash[:], prv)
if err != nil { if err != nil {
return SetCodeAuthorization{}, err return SetCodeAuthorization{}, err
} }
r, s, _ := decodeSignature(sig) r, s, _ := decodeSignature(sig)
return SetCodeAuthorization{ return SetCodeAuthorization{
ChainID: auth.ChainID, Unchained: auth.Unchained,
Address: auth.Address, Address: auth.Address,
Nonce: auth.Nonce, Nonce: auth.Nonce,
V: sig[64], V: sig[64],
@ -105,17 +104,25 @@ func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAutho
}, nil }, nil
} }
func (a *SetCodeAuthorization) sigHash() common.Hash { func (a *SetCodeAuthorization) sigHash(chainID *big.Int) common.Hash {
if a.Unchained {
chainID = common.Big0
}
return prefixedRlpHash(0x05, []any{ return prefixedRlpHash(0x05, []any{
a.ChainID, chainID,
a.Address, a.Address,
a.Nonce, a.Nonce,
}) })
} }
// Authority recovers the the authorizing account of an authorization. // Authority recovers the the authorizing account of an authorization.
func (a *SetCodeAuthorization) Authority() (common.Address, error) { func (a *SetCodeAuthorization) Authority(chainID *big.Int) (common.Address, error) {
sighash := a.sigHash() if chainID == nil {
// This sanity check is important, since a missing chainID would just end up
// being encoded into the signature hash, leading to an incorrectly derived address.
panic("missing chainID")
}
sighash := a.sigHash(chainID)
if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) { if !crypto.ValidateSignatureValues(a.V, a.R.ToBig(), a.S.ToBig(), true) {
return common.Address{}, ErrInvalidSig return common.Address{}, ErrInvalidSig
} }