1717package core
1818
1919import (
20+ "bytes"
2021 "fmt"
2122 "math"
2223 "math/big"
@@ -27,6 +28,7 @@ import (
2728 "github.com/ethereum/go-ethereum/core/types"
2829 "github.com/ethereum/go-ethereum/core/vm"
2930 "github.com/ethereum/go-ethereum/crypto/kzg4844"
31+ "github.com/ethereum/go-ethereum/crypto/secp256k1"
3032 "github.com/ethereum/go-ethereum/params"
3133 "github.com/holiman/uint256"
3234)
@@ -68,7 +70,7 @@ func (result *ExecutionResult) Revert() []byte {
6870}
6971
7072// IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
71- func IntrinsicGas (data []byte , accessList types.AccessList , isContractCreation , isHomestead , isEIP2028 , isEIP3860 bool ) (uint64 , error ) {
73+ func IntrinsicGas (data []byte , accessList types.AccessList , authList types. AuthorizationList , isContractCreation , isHomestead , isEIP2028 , isEIP3860 bool ) (uint64 , error ) {
7274 // Set the starting gas for the raw transaction
7375 var gas uint64
7476 if isContractCreation && isHomestead {
@@ -114,6 +116,9 @@ func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation,
114116 gas += uint64 (len (accessList )) * params .TxAccessListAddressGas
115117 gas += uint64 (accessList .StorageKeys ()) * params .TxAccessListStorageKeyGas
116118 }
119+ if authList != nil {
120+ gas += uint64 (len (authList )) * params .CallNewAccountGas
121+ }
117122 return gas , nil
118123}
119124
@@ -141,6 +146,7 @@ type Message struct {
141146 AccessList types.AccessList
142147 BlobGasFeeCap * big.Int
143148 BlobHashes []common.Hash
149+ AuthList types.AuthorizationList
144150
145151 // When SkipAccountChecks is true, the message nonce is not checked against the
146152 // account nonce in state. It also disables checking that the sender is an EOA.
@@ -160,6 +166,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
160166 Value : tx .Value (),
161167 Data : tx .Data (),
162168 AccessList : tx .AccessList (),
169+ AuthList : tx .AuthList (),
163170 SkipAccountChecks : false ,
164171 BlobHashes : tx .BlobHashes (),
165172 BlobGasFeeCap : tx .BlobGasFeeCap (),
@@ -294,10 +301,10 @@ func (st *StateTransition) preCheck() error {
294301 msg .From .Hex (), stNonce )
295302 }
296303 // Make sure the sender is an EOA
297- codeHash := st .state .GetCodeHash (msg .From )
298- if codeHash != (common. Hash {} ) && codeHash != types . EmptyCodeHash {
304+ code := st .state .GetCode (msg .From )
305+ if 0 < len ( code ) && ! bytes . HasPrefix ( code , [] byte { 0xef , 0x01 , 0x00 }) {
299306 return fmt .Errorf ("%w: address %v, codehash: %s" , ErrSenderNoEOA ,
300- msg .From .Hex (), codeHash )
307+ msg .From .Hex (), st . state . GetCodeHash ( msg . From ) )
301308 }
302309 }
303310 // Make sure that transaction gasFeeCap is greater than the baseFee (post london)
@@ -357,6 +364,27 @@ func (st *StateTransition) preCheck() error {
357364 }
358365 }
359366 }
367+
368+ // Check that auth list isn't empty.
369+ if msg .AuthList != nil && len (msg .AuthList ) == 0 {
370+ return fmt .Errorf ("%w: address %v" , ErrEmptyAuthList , msg .From .Hex ())
371+ }
372+
373+ // TODO: remove after this spec change is merged:
374+ // https://github.com/ethereum/EIPs/pull/8845
375+ if msg .AuthList != nil {
376+ var (
377+ secp256k1N = secp256k1 .S256 ().Params ().N
378+ secp256k1halfN = new (big.Int ).Div (secp256k1N , big .NewInt (2 ))
379+ )
380+ for _ , auth := range msg .AuthList {
381+ if auth .V .Cmp (common .Big1 ) > 0 || auth .S .Cmp (secp256k1halfN ) > 0 {
382+ w := fmt .Errorf ("set code transaction with invalid auth signature" )
383+ return fmt .Errorf ("%w: address %v" , w , msg .From .Hex ())
384+ }
385+ }
386+ }
387+
360388 return st .buyGas ()
361389}
362390
@@ -394,7 +422,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
394422 )
395423
396424 // Check clauses 4-5, subtract intrinsic gas if everything is correct
397- gas , err := IntrinsicGas (msg .Data , msg .AccessList , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
425+ gas , err := IntrinsicGas (msg .Data , msg .AccessList , msg . AuthList , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
398426 if err != nil {
399427 return nil , err
400428 }
@@ -433,15 +461,49 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
433461 // - reset transient storage(eip 1153)
434462 st .state .Prepare (rules , msg .From , st .evm .Context .Coinbase , msg .To , vm .ActivePrecompiles (rules ), msg .AccessList )
435463
464+ if ! contractCreation {
465+ // Increment the nonce for the next transaction
466+ st .state .SetNonce (msg .From , st .state .GetNonce (sender .Address ())+ 1 )
467+ }
468+
469+ // Check authorizations list validity.
470+ if msg .AuthList != nil {
471+ for _ , auth := range msg .AuthList {
472+ // Verify chain ID is 0 or equal to current chain ID.
473+ if auth .ChainID .Sign () != 0 && st .evm .ChainConfig ().ChainID .Cmp (auth .ChainID ) != 0 {
474+ continue
475+ }
476+ authority , err := auth .Authority ()
477+ if err != nil {
478+ continue
479+ }
480+ // Check the authority account 1) doesn't have code or has exisiting
481+ // delegation 2) matches the auth's nonce
482+ st .state .AddAddressToAccessList (authority )
483+ code := st .state .GetCode (authority )
484+ if _ , ok := types .ParseDelegation (code ); len (code ) != 0 && ! ok {
485+ continue
486+ }
487+ if have := st .state .GetNonce (authority ); have != auth .Nonce {
488+ continue
489+ }
490+ // If the account already exists in state, refund the new account cost
491+ // charged in the initrinsic calculation.
492+ if exists := st .state .Exist (authority ); exists {
493+ st .state .AddRefund (params .CallNewAccountGas - params .TxAuthTupleGas )
494+ }
495+ st .state .SetNonce (authority , auth .Nonce + 1 )
496+ st .state .SetCode (authority , types .AddressToDelegation (auth .Address ))
497+ }
498+ }
499+
436500 var (
437501 ret []byte
438502 vmerr error // vm errors do not effect consensus and are therefore not assigned to err
439503 )
440504 if contractCreation {
441505 ret , _ , st .gasRemaining , vmerr = st .evm .Create (sender , msg .Data , st .gasRemaining , value )
442506 } else {
443- // Increment the nonce for the next transaction
444- st .state .SetNonce (msg .From , st .state .GetNonce (sender .Address ())+ 1 )
445507 ret , st .gasRemaining , vmerr = st .evm .Call (sender , st .to (), msg .Data , st .gasRemaining , value )
446508 }
447509
0 commit comments