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 SkipNonceChecks is true, the message nonce is not checked against the
146152 // account nonce in state.
@@ -163,6 +169,7 @@ func TransactionToMessage(tx *types.Transaction, s types.Signer, baseFee *big.In
163169 Value : tx .Value (),
164170 Data : tx .Data (),
165171 AccessList : tx .AccessList (),
172+ AuthList : tx .AuthList (),
166173 SkipNonceChecks : false ,
167174 SkipFromEOACheck : false ,
168175 BlobHashes : tx .BlobHashes (),
@@ -300,10 +307,10 @@ func (st *StateTransition) preCheck() error {
300307 }
301308 if ! msg .SkipFromEOACheck {
302309 // Make sure the sender is an EOA
303- codeHash := st .state .GetCodeHash (msg .From )
304- if codeHash != (common. Hash {} ) && codeHash != types . EmptyCodeHash {
310+ code := st .state .GetCode (msg .From )
311+ if 0 < len ( code ) && ! bytes . HasPrefix ( code , [] byte { 0xef , 0x01 , 0x00 }) {
305312 return fmt .Errorf ("%w: address %v, codehash: %s" , ErrSenderNoEOA ,
306- msg .From .Hex (), codeHash )
313+ msg .From .Hex (), st . state . GetCodeHash ( msg . From ) )
307314 }
308315 }
309316 // Make sure that transaction gasFeeCap is greater than the baseFee (post london)
@@ -363,6 +370,27 @@ func (st *StateTransition) preCheck() error {
363370 }
364371 }
365372 }
373+
374+ // Check that auth list isn't empty.
375+ if msg .AuthList != nil && len (msg .AuthList ) == 0 {
376+ return fmt .Errorf ("%w: address %v" , ErrEmptyAuthList , msg .From .Hex ())
377+ }
378+
379+ // TODO: remove after this spec change is merged:
380+ // https://github.com/ethereum/EIPs/pull/8845
381+ if msg .AuthList != nil {
382+ var (
383+ secp256k1N = secp256k1 .S256 ().Params ().N
384+ secp256k1halfN = new (big.Int ).Div (secp256k1N , big .NewInt (2 ))
385+ )
386+ for _ , auth := range msg .AuthList {
387+ if auth .V .Cmp (common .Big1 ) > 0 || auth .S .Cmp (secp256k1halfN ) > 0 {
388+ w := fmt .Errorf ("set code transaction with invalid auth signature" )
389+ return fmt .Errorf ("%w: address %v" , w , msg .From .Hex ())
390+ }
391+ }
392+ }
393+
366394 return st .buyGas ()
367395}
368396
@@ -400,7 +428,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
400428 )
401429
402430 // Check clauses 4-5, subtract intrinsic gas if everything is correct
403- gas , err := IntrinsicGas (msg .Data , msg .AccessList , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
431+ gas , err := IntrinsicGas (msg .Data , msg .AccessList , msg . AuthList , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
404432 if err != nil {
405433 return nil , err
406434 }
@@ -439,15 +467,49 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
439467 // - reset transient storage(eip 1153)
440468 st .state .Prepare (rules , msg .From , st .evm .Context .Coinbase , msg .To , vm .ActivePrecompiles (rules ), msg .AccessList )
441469
470+ if ! contractCreation {
471+ // Increment the nonce for the next transaction
472+ st .state .SetNonce (msg .From , st .state .GetNonce (sender .Address ())+ 1 )
473+ }
474+
475+ // Check authorizations list validity.
476+ if msg .AuthList != nil {
477+ for _ , auth := range msg .AuthList {
478+ // Verify chain ID is 0 or equal to current chain ID.
479+ if auth .ChainID .Sign () != 0 && st .evm .ChainConfig ().ChainID .Cmp (auth .ChainID ) != 0 {
480+ continue
481+ }
482+ authority , err := auth .Authority ()
483+ if err != nil {
484+ continue
485+ }
486+ // Check the authority account 1) doesn't have code or has exisiting
487+ // delegation 2) matches the auth's nonce
488+ st .state .AddAddressToAccessList (authority )
489+ code := st .state .GetCode (authority )
490+ if _ , ok := types .ParseDelegation (code ); len (code ) != 0 && ! ok {
491+ continue
492+ }
493+ if have := st .state .GetNonce (authority ); have != auth .Nonce {
494+ continue
495+ }
496+ // If the account already exists in state, refund the new account cost
497+ // charged in the initrinsic calculation.
498+ if exists := st .state .Exist (authority ); exists {
499+ st .state .AddRefund (params .CallNewAccountGas - params .TxAuthTupleGas )
500+ }
501+ st .state .SetNonce (authority , auth .Nonce + 1 )
502+ st .state .SetCode (authority , types .AddressToDelegation (auth .Address ))
503+ }
504+ }
505+
442506 var (
443507 ret []byte
444508 vmerr error // vm errors do not effect consensus and are therefore not assigned to err
445509 )
446510 if contractCreation {
447511 ret , _ , st .gasRemaining , vmerr = st .evm .Create (sender , msg .Data , st .gasRemaining , value )
448512 } else {
449- // Increment the nonce for the next transaction
450- st .state .SetNonce (msg .From , st .state .GetNonce (sender .Address ())+ 1 )
451513 ret , st .gasRemaining , vmerr = st .evm .Call (sender , st .to (), msg .Data , st .gasRemaining , value )
452514 }
453515
0 commit comments