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
// 2. addr1:0xaaaa calls into addr2:0xbbbb
// 3. addr2:0xbbbb writes to storage
auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: gspec.Config.ChainID.Uint64(),
auth1, _ := types.SignSetCode(key1, gspec.Config.ChainID, types.SetCodeAuthorization{
Address: aa,
Nonce: 1,
})
auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
ChainID: 0,
auth2, _ := types.SignSetCode(key2, gspec.Config.ChainID, types.SetCodeAuthorization{
Unchained: true,
Address: bb,
Nonce: 0,
})

View file

@ -529,16 +529,12 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
// validateAuthorization validates an EIP-7702 authorization against the state.
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.
if auth.Nonce+1 < auth.Nonce {
return authority, ErrAuthorizationNonceOverflow
}
// Validate signature values and recover authority.
authority, err = auth.Authority()
authority, err = auth.Authority(st.evm.ChainConfig().ChainID)
if err != nil {
return authority, fmt.Errorf("%w: %v", ErrAuthorizationInvalidSignature, err)
}

View file

@ -16,7 +16,7 @@ var _ = (*authorizationMarshaling)(nil)
// MarshalJSON marshals as JSON.
func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
type SetCodeAuthorization struct {
ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"`
Unchained bool `json:"unchained" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"`
Nonce hexutil.Uint64 `json:"nonce" 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"`
}
var enc SetCodeAuthorization
enc.ChainID = hexutil.Uint64(s.ChainID)
enc.Unchained = s.Unchained
enc.Address = s.Address
enc.Nonce = hexutil.Uint64(s.Nonce)
enc.V = hexutil.Uint64(s.V)
@ -36,7 +36,7 @@ func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
// UnmarshalJSON unmarshals from JSON.
func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error {
type SetCodeAuthorization struct {
ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"`
Unchained *bool `json:"unchained" gencodec:"required"`
Address *common.Address `json:"address" gencodec:"required"`
Nonce *hexutil.Uint64 `json:"nonce" 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 {
return err
}
if dec.ChainID == nil {
return errors.New("missing required field 'chainId' for SetCodeAuthorization")
if dec.Unchained == nil {
return errors.New("missing required field 'unchained' for SetCodeAuthorization")
}
s.ChainID = uint64(*dec.ChainID)
s.Unchained = *dec.Unchained
if dec.Address == nil {
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.
type SetCodeAuthorization struct {
ChainID uint64 `json:"chainId" gencodec:"required"`
Unchained bool `json:"unchained" gencodec:"required"`
Address common.Address `json:"address" gencodec:"required"`
Nonce uint64 `json:"nonce" gencodec:"required"`
V uint8 `json:"yParity" gencodec:"required"`
@ -80,7 +80,6 @@ type SetCodeAuthorization struct {
// field type overrides for gencodec
type authorizationMarshaling struct {
ChainID hexutil.Uint64
Nonce hexutil.Uint64
V hexutil.Uint64
R hexutil.U256
@ -88,15 +87,15 @@ type authorizationMarshaling struct {
}
// SignSetCode creates a signed the SetCode authorization.
func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAuthorization, error) {
sighash := auth.sigHash()
func SignSetCode(prv *ecdsa.PrivateKey, chainID *big.Int, auth SetCodeAuthorization) (SetCodeAuthorization, error) {
sighash := auth.sigHash(chainID)
sig, err := crypto.Sign(sighash[:], prv)
if err != nil {
return SetCodeAuthorization{}, err
}
r, s, _ := decodeSignature(sig)
return SetCodeAuthorization{
ChainID: auth.ChainID,
Unchained: auth.Unchained,
Address: auth.Address,
Nonce: auth.Nonce,
V: sig[64],
@ -105,17 +104,25 @@ func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAutho
}, 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{
a.ChainID,
chainID,
a.Address,
a.Nonce,
})
}
// Authority recovers the the authorizing account of an authorization.
func (a *SetCodeAuthorization) Authority() (common.Address, error) {
sighash := a.sigHash()
func (a *SetCodeAuthorization) Authority(chainID *big.Int) (common.Address, error) {
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) {
return common.Address{}, ErrInvalidSig
}