core/types: updates for EIP-7702 API functions (#30933)

Here I am proposing two small changes to the exported API for EIP-7702:

(1) `Authorization` has a very generic name, but it is in fact only used
for one niche use case: authorizing code in a `SetCodeTx`. So I propose
calling it `SetCodeAuthorization` instead. The signing function is
renamed to `SignSetCode` instead of `SignAuth`.
   
(2) The signing function for authorizations should take key as the first
parameter, and the authorization second. The key will almost always be
in a variable, while the authorization can be given as a literal.
pull/30935/head
Felix Lange 2 months ago committed by GitHub
parent 1321a42525
commit 9d4b29f291
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 10
      core/blockchain_test.go
  2. 2
      core/state_processor_test.go
  3. 8
      core/state_transition.go
  4. 48
      core/types/gen_authorization.go
  5. 2
      core/types/transaction.go
  6. 34
      core/types/transaction_marshalling.go
  7. 36
      core/types/tx_setcode.go
  8. 46
      internal/ethapi/api.go
  9. 4
      internal/ethapi/transaction_args.go
  10. 6
      tests/state_test_util.go

@ -4273,16 +4273,16 @@ 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.SignAuth(types.Authorization{ auth1, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: gspec.Config.ChainID.Uint64(), ChainID: gspec.Config.ChainID.Uint64(),
Address: aa, Address: aa,
Nonce: 1, Nonce: 1,
}, key1) })
auth2, _ := types.SignAuth(types.Authorization{ auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
ChainID: 0, ChainID: 0,
Address: bb, Address: bb,
Nonce: 0, Nonce: 0,
}, key2) })
_, 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)
@ -4293,7 +4293,7 @@ func TestEIP7702(t *testing.T) {
Gas: 500000, Gas: 500000,
GasFeeCap: uint256.MustFromBig(newGwei(5)), GasFeeCap: uint256.MustFromBig(newGwei(5)),
GasTipCap: uint256.NewInt(2), GasTipCap: uint256.NewInt(2),
AuthList: []types.Authorization{auth1, auth2}, AuthList: []types.SetCodeAuthorization{auth1, auth2},
} }
tx := types.MustSignNewTx(key1, signer, txdata) tx := types.MustSignNewTx(key1, signer, txdata)
b.AddTx(tx) b.AddTx(tx)

@ -111,7 +111,7 @@ func TestStateProcessorErrors(t *testing.T) {
} }
return tx return tx
} }
var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.Authorization) *types.Transaction { var mkSetCodeTx = func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int, authlist []types.SetCodeAuthorization) *types.Transaction {
tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{ tx, err := types.SignTx(types.NewTx(&types.SetCodeTx{
Nonce: nonce, Nonce: nonce,
GasTipCap: uint256.MustFromBig(gasTipCap), GasTipCap: uint256.MustFromBig(gasTipCap),

@ -67,7 +67,7 @@ func (result *ExecutionResult) Revert() []byte {
} }
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Authorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) {
// Set the starting gas for the raw transaction // Set the starting gas for the raw transaction
var gas uint64 var gas uint64
if isContractCreation && isHomestead { if isContractCreation && isHomestead {
@ -143,7 +143,7 @@ type Message struct {
AccessList types.AccessList AccessList types.AccessList
BlobGasFeeCap *big.Int BlobGasFeeCap *big.Int
BlobHashes []common.Hash BlobHashes []common.Hash
AuthList []types.Authorization AuthList []types.SetCodeAuthorization
// When SkipNonceChecks is true, the message nonce is not checked against the // When SkipNonceChecks is true, the message nonce is not checked against the
// account nonce in state. // account nonce in state.
@ -528,7 +528,7 @@ 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.Authorization) (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 0 or equal to current chain ID.
if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID { if auth.ChainID != 0 && st.evm.ChainConfig().ChainID.Uint64() != auth.ChainID {
return authority, ErrAuthorizationWrongChainID return authority, ErrAuthorizationWrongChainID
@ -559,7 +559,7 @@ func (st *stateTransition) validateAuthorization(auth *types.Authorization) (aut
} }
// applyAuthorization applies an EIP-7702 code delegation to the state. // applyAuthorization applies an EIP-7702 code delegation to the state.
func (st *stateTransition) applyAuthorization(msg *Message, auth *types.Authorization) error { func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeAuthorization) error {
authority, err := st.validateAuthorization(auth) authority, err := st.validateAuthorization(auth)
if err != nil { if err != nil {
return err return err

@ -14,8 +14,8 @@ import (
var _ = (*authorizationMarshaling)(nil) var _ = (*authorizationMarshaling)(nil)
// MarshalJSON marshals as JSON. // MarshalJSON marshals as JSON.
func (a Authorization) MarshalJSON() ([]byte, error) { func (s SetCodeAuthorization) MarshalJSON() ([]byte, error) {
type Authorization struct { type SetCodeAuthorization struct {
ChainID hexutil.Uint64 `json:"chainId" gencodec:"required"` ChainID hexutil.Uint64 `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"`
@ -23,19 +23,19 @@ func (a Authorization) MarshalJSON() ([]byte, error) {
R hexutil.U256 `json:"r" gencodec:"required"` R hexutil.U256 `json:"r" gencodec:"required"`
S hexutil.U256 `json:"s" gencodec:"required"` S hexutil.U256 `json:"s" gencodec:"required"`
} }
var enc Authorization var enc SetCodeAuthorization
enc.ChainID = hexutil.Uint64(a.ChainID) enc.ChainID = hexutil.Uint64(s.ChainID)
enc.Address = a.Address enc.Address = s.Address
enc.Nonce = hexutil.Uint64(a.Nonce) enc.Nonce = hexutil.Uint64(s.Nonce)
enc.V = hexutil.Uint64(a.V) enc.V = hexutil.Uint64(s.V)
enc.R = hexutil.U256(a.R) enc.R = hexutil.U256(s.R)
enc.S = hexutil.U256(a.S) enc.S = hexutil.U256(s.S)
return json.Marshal(&enc) return json.Marshal(&enc)
} }
// UnmarshalJSON unmarshals from JSON. // UnmarshalJSON unmarshals from JSON.
func (a *Authorization) UnmarshalJSON(input []byte) error { func (s *SetCodeAuthorization) UnmarshalJSON(input []byte) error {
type Authorization struct { type SetCodeAuthorization struct {
ChainID *hexutil.Uint64 `json:"chainId" gencodec:"required"` ChainID *hexutil.Uint64 `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"`
@ -43,33 +43,33 @@ func (a *Authorization) UnmarshalJSON(input []byte) error {
R *hexutil.U256 `json:"r" gencodec:"required"` R *hexutil.U256 `json:"r" gencodec:"required"`
S *hexutil.U256 `json:"s" gencodec:"required"` S *hexutil.U256 `json:"s" gencodec:"required"`
} }
var dec Authorization var dec SetCodeAuthorization
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 {
return errors.New("missing required field 'chainId' for Authorization") return errors.New("missing required field 'chainId' for SetCodeAuthorization")
} }
a.ChainID = uint64(*dec.ChainID) s.ChainID = uint64(*dec.ChainID)
if dec.Address == nil { if dec.Address == nil {
return errors.New("missing required field 'address' for Authorization") return errors.New("missing required field 'address' for SetCodeAuthorization")
} }
a.Address = *dec.Address s.Address = *dec.Address
if dec.Nonce == nil { if dec.Nonce == nil {
return errors.New("missing required field 'nonce' for Authorization") return errors.New("missing required field 'nonce' for SetCodeAuthorization")
} }
a.Nonce = uint64(*dec.Nonce) s.Nonce = uint64(*dec.Nonce)
if dec.V == nil { if dec.V == nil {
return errors.New("missing required field 'v' for Authorization") return errors.New("missing required field 'v' for SetCodeAuthorization")
} }
a.V = uint8(*dec.V) s.V = uint8(*dec.V)
if dec.R == nil { if dec.R == nil {
return errors.New("missing required field 'r' for Authorization") return errors.New("missing required field 'r' for SetCodeAuthorization")
} }
a.R = uint256.Int(*dec.R) s.R = uint256.Int(*dec.R)
if dec.S == nil { if dec.S == nil {
return errors.New("missing required field 's' for Authorization") return errors.New("missing required field 's' for SetCodeAuthorization")
} }
a.S = uint256.Int(*dec.S) s.S = uint256.Int(*dec.S)
return nil return nil
} }

@ -475,7 +475,7 @@ func (tx *Transaction) WithBlobTxSidecar(sideCar *BlobTxSidecar) *Transaction {
} }
// AuthList returns the authorizations list of the transaction. // AuthList returns the authorizations list of the transaction.
func (tx *Transaction) AuthList() []Authorization { func (tx *Transaction) AuthList() []SetCodeAuthorization {
setcodetx, ok := tx.inner.(*SetCodeTx) setcodetx, ok := tx.inner.(*SetCodeTx)
if !ok { if !ok {
return nil return nil

@ -31,23 +31,23 @@ import (
type txJSON struct { type txJSON struct {
Type hexutil.Uint64 `json:"type"` Type hexutil.Uint64 `json:"type"`
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
Nonce *hexutil.Uint64 `json:"nonce"` Nonce *hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"` To *common.Address `json:"to"`
Gas *hexutil.Uint64 `json:"gas"` Gas *hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"`
MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"`
MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
Value *hexutil.Big `json:"value"` Value *hexutil.Big `json:"value"`
Input *hexutil.Bytes `json:"input"` Input *hexutil.Bytes `json:"input"`
AccessList *AccessList `json:"accessList,omitempty"` AccessList *AccessList `json:"accessList,omitempty"`
BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
AuthorizationList []Authorization `json:"authorizationList,omitempty"` AuthorizationList []SetCodeAuthorization `json:"authorizationList,omitempty"`
V *hexutil.Big `json:"v"` V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"` R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"` S *hexutil.Big `json:"s"`
YParity *hexutil.Uint64 `json:"yParity,omitempty"` YParity *hexutil.Uint64 `json:"yParity,omitempty"`
// Blob transaction sidecar encoding: // Blob transaction sidecar encoding:
Blobs []kzg4844.Blob `json:"blobs,omitempty"` Blobs []kzg4844.Blob `json:"blobs,omitempty"`

@ -58,7 +58,7 @@ type SetCodeTx struct {
Value *uint256.Int Value *uint256.Int
Data []byte Data []byte
AccessList AccessList AccessList AccessList
AuthList []Authorization AuthList []SetCodeAuthorization
// Signature values // Signature values
V *uint256.Int `json:"v" gencodec:"required"` V *uint256.Int `json:"v" gencodec:"required"`
@ -66,10 +66,10 @@ type SetCodeTx struct {
S *uint256.Int `json:"s" gencodec:"required"` S *uint256.Int `json:"s" gencodec:"required"`
} }
//go:generate go run github.com/fjl/gencodec -type Authorization -field-override authorizationMarshaling -out gen_authorization.go //go:generate go run github.com/fjl/gencodec -type SetCodeAuthorization -field-override authorizationMarshaling -out gen_authorization.go
// Authorization 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 Authorization struct { type SetCodeAuthorization struct {
ChainID uint64 `json:"chainId" gencodec:"required"` ChainID uint64 `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"`
@ -87,31 +87,25 @@ type authorizationMarshaling struct {
S hexutil.U256 S hexutil.U256
} }
// SignAuth signs the provided authorization. // SignSetCode creates a signed the SetCode authorization.
func SignAuth(auth Authorization, prv *ecdsa.PrivateKey) (Authorization, error) { func SignSetCode(prv *ecdsa.PrivateKey, auth SetCodeAuthorization) (SetCodeAuthorization, error) {
sighash := auth.sigHash() sighash := auth.sigHash()
sig, err := crypto.Sign(sighash[:], prv) sig, err := crypto.Sign(sighash[:], prv)
if err != nil { if err != nil {
return Authorization{}, err return SetCodeAuthorization{}, err
} }
return auth.withSignature(sig), nil
}
// withSignature updates the signature of an Authorization to be equal the
// decoded signature provided in sig.
func (a *Authorization) withSignature(sig []byte) Authorization {
r, s, _ := decodeSignature(sig) r, s, _ := decodeSignature(sig)
return Authorization{ return SetCodeAuthorization{
ChainID: a.ChainID, ChainID: auth.ChainID,
Address: a.Address, Address: auth.Address,
Nonce: a.Nonce, Nonce: auth.Nonce,
V: sig[64], V: sig[64],
R: *uint256.MustFromBig(r), R: *uint256.MustFromBig(r),
S: *uint256.MustFromBig(s), S: *uint256.MustFromBig(s),
} }, nil
} }
func (a *Authorization) sigHash() common.Hash { func (a *SetCodeAuthorization) sigHash() common.Hash {
return prefixedRlpHash(0x05, []any{ return prefixedRlpHash(0x05, []any{
a.ChainID, a.ChainID,
a.Address, a.Address,
@ -120,7 +114,7 @@ func (a *Authorization) sigHash() common.Hash {
} }
// Authority recovers the the authorizing account of an authorization. // Authority recovers the the authorizing account of an authorization.
func (a *Authorization) Authority() (common.Address, error) { func (a *SetCodeAuthorization) Authority() (common.Address, error) {
sighash := a.sigHash() sighash := a.sigHash()
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
@ -152,7 +146,7 @@ func (tx *SetCodeTx) copy() TxData {
Gas: tx.Gas, Gas: tx.Gas,
// These are copied below. // These are copied below.
AccessList: make(AccessList, len(tx.AccessList)), AccessList: make(AccessList, len(tx.AccessList)),
AuthList: make([]Authorization, len(tx.AuthList)), AuthList: make([]SetCodeAuthorization, len(tx.AuthList)),
Value: new(uint256.Int), Value: new(uint256.Int),
ChainID: tx.ChainID, ChainID: tx.ChainID,
GasTipCap: new(uint256.Int), GasTipCap: new(uint256.Int),

@ -937,29 +937,29 @@ func RPCMarshalBlock(block *types.Block, inclTx bool, fullTx bool, config *param
// RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction // RPCTransaction represents a transaction that will serialize to the RPC representation of a transaction
type RPCTransaction struct { type RPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"` BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"` BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"` From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"` Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"` GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"` GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"` GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"` MaxFeePerBlobGas *hexutil.Big `json:"maxFeePerBlobGas,omitempty"`
Hash common.Hash `json:"hash"` Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"` Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"` Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"` To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"` TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"` Value *hexutil.Big `json:"value"`
Type hexutil.Uint64 `json:"type"` Type hexutil.Uint64 `json:"type"`
Accesses *types.AccessList `json:"accessList,omitempty"` Accesses *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"` ChainID *hexutil.Big `json:"chainId,omitempty"`
BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"`
AuthorizationList []types.Authorization `json:"authorizationList,omitempty"` AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"`
V *hexutil.Big `json:"v"` V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"` R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"` S *hexutil.Big `json:"s"`
YParity *hexutil.Uint64 `json:"yParity,omitempty"` YParity *hexutil.Uint64 `json:"yParity,omitempty"`
} }
// newRPCTransaction returns a transaction that will serialize to the RPC // newRPCTransaction returns a transaction that will serialize to the RPC

@ -73,7 +73,7 @@ type TransactionArgs struct {
Proofs []kzg4844.Proof `json:"proofs"` Proofs []kzg4844.Proof `json:"proofs"`
// For SetCodeTxType // For SetCodeTxType
AuthorizationList []types.Authorization `json:"authorizationList"` AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"`
// This configures whether blobs are allowed to be passed. // This configures whether blobs are allowed to be passed.
blobSidecarAllowed bool blobSidecarAllowed bool
@ -497,7 +497,7 @@ func (args *TransactionArgs) ToTransaction(defaultType int) *types.Transaction {
if args.AccessList != nil { if args.AccessList != nil {
al = *args.AccessList al = *args.AccessList
} }
authList := []types.Authorization{} authList := []types.SetCodeAuthorization{}
if args.AuthorizationList != nil { if args.AuthorizationList != nil {
authList = args.AuthorizationList authList = args.AuthorizationList
} }

@ -441,11 +441,11 @@ func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Mess
if gasPrice == nil { if gasPrice == nil {
return nil, errors.New("no gas price provided") return nil, errors.New("no gas price provided")
} }
var authList []types.Authorization var authList []types.SetCodeAuthorization
if tx.AuthorizationList != nil { if tx.AuthorizationList != nil {
authList = make([]types.Authorization, 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.Authorization{ authList[i] = types.SetCodeAuthorization{
ChainID: auth.ChainID, ChainID: auth.ChainID,
Address: auth.Address, Address: auth.Address,
Nonce: auth.Nonce, Nonce: auth.Nonce,

Loading…
Cancel
Save