Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
a29c9d0
core: adjust the naming to be the same as geth
tnasu Jan 16, 2025
900597d
internal/ethapi: add 7702 tests to eth_estimateGas
tnasu Jan 15, 2025
32c3b04
core/vm: make 7702 variants of EXT* ops
tnasu Jan 16, 2025
f4611eb
core: remove resolve code mechanism from statedb, put in vm
tnasu Jan 16, 2025
d5a31f8
core/vm: add go:generate and update mock
tnasu Jan 21, 2025
227de51
internal/ethapi: handle set code tx type in transaction args
tnasu Jan 16, 2025
dd813b2
core: clarify test a bit
tnasu Jan 16, 2025
86b706e
core/types: remove AuthorizationList and use Authorization as value i…
tnasu Jan 16, 2025
4342516
core/types: improve authority signature handling
tnasu Jan 16, 2025
597d297
core: track validation error for authorizations
tnasu Jan 16, 2025
235a945
core: style improvement in applyAuthorization
tnasu Jan 16, 2025
6bf5844
core: add comment about nonce update order
tnasu Jan 17, 2025
53d3d35
core/vm: add comment about chained EIP-7702 delegations
tnasu Jan 17, 2025
b78e1ee
core: remove debug print
tnasu Jan 17, 2025
45605ae
core: improve checks for 7702
tnasu Jan 17, 2025
15915d5
core: add comment about 7702 state transition error
tnasu Jan 17, 2025
c7433fc
core: clarify delegation deletion flow
tnasu Jan 17, 2025
7a3b8e1
core: more comment
tnasu Jan 17, 2025
23233b9
core: lift convenience warming of tx destination from per auth to pos…
tnasu Jan 17, 2025
1f2ddd8
core/vm: direct check code hash during creation instead of resolving
tnasu Jan 17, 2025
5eeb56c
core/vm: return delegation designator prefix for code reading ops
tnasu Jan 17, 2025
45ebe5b
core/vm: report gas used warming 7702 delegation targets correctly in…
tnasu Jan 17, 2025
9082d7d
core: mod errors + add test
tnasu Jan 17, 2025
3a5944f
internal/ethapi: rename authlist to authorizationList in transaction …
tnasu Jan 17, 2025
89b8473
core/vm: rm dynamic gas calculators for core reading ops
tnasu Jan 17, 2025
72ad9ef
core/vm: simplify 7702 enabler
tnasu Jan 17, 2025
23b0aab
core/types: rename Authorization to SetCodeAuthorization
tnasu Jan 17, 2025
38bd087
core/types: change parameter order of SignAuth and rename
tnasu Jan 17, 2025
113958b
core/types: rename SignAuthorization to SignSetCode
tnasu Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 24 additions & 26 deletions api/api_ethereum.go
Original file line number Diff line number Diff line change
Expand Up @@ -721,26 +721,26 @@ func (api *EthereumAPI) GetBlockTransactionCountByHash(ctx context.Context, bloc
// RPCTransaction in go-ethereum has been renamed to EthRPCTransaction.
// RPCTransaction is defined in go-ethereum's internal package, so RPCTransaction is redefined here as EthRPCTransaction.
type EthRPCTransaction struct {
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
Type hexutil.Uint64 `json:"type"`
Accesses *types.AccessList `json:"accessList,omitempty"`
Authorizations *types.AuthorizationList `json:"authorizationList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
BlockHash *common.Hash `json:"blockHash"`
BlockNumber *hexutil.Big `json:"blockNumber"`
From common.Address `json:"from"`
Gas hexutil.Uint64 `json:"gas"`
GasPrice *hexutil.Big `json:"gasPrice"`
GasFeeCap *hexutil.Big `json:"maxFeePerGas,omitempty"`
GasTipCap *hexutil.Big `json:"maxPriorityFeePerGas,omitempty"`
Hash common.Hash `json:"hash"`
Input hexutil.Bytes `json:"input"`
Nonce hexutil.Uint64 `json:"nonce"`
To *common.Address `json:"to"`
TransactionIndex *hexutil.Uint64 `json:"transactionIndex"`
Value *hexutil.Big `json:"value"`
Type hexutil.Uint64 `json:"type"`
Accesses *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"`
V *hexutil.Big `json:"v"`
R *hexutil.Big `json:"r"`
S *hexutil.Big `json:"s"`
}

// ethTxJSON is the JSON representation of Ethereum transaction.
Expand Down Expand Up @@ -771,7 +771,7 @@ type ethTxJSON struct {
AccessList *types.AccessList `json:"accessList,omitempty"`

// Set code transaction fields:
AuthorizationList *types.AuthorizationList `json:"authorizationList,omitempty"`
AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"`

// Only used for encoding:
Hash common.Hash `json:"hash"`
Expand Down Expand Up @@ -868,9 +868,7 @@ func newEthRPCTransaction(block *types.Block, tx *types.Transaction, blockHash c
}
case types.TxTypeEthereumSetCode:
al := tx.AccessList()
aul := tx.AuthorizationList()
result.Accesses = &al
result.Authorizations = &aul
result.ChainID = (*hexutil.Big)(tx.ChainId())
result.GasFeeCap = (*hexutil.Big)(tx.GasFeeCap())
result.GasTipCap = (*hexutil.Big)(tx.GasTipCap())
Expand All @@ -880,6 +878,7 @@ func newEthRPCTransaction(block *types.Block, tx *types.Transaction, blockHash c
// transaction is not processed yet
result.GasPrice = (*hexutil.Big)(tx.EffectiveGasPrice(nil, nil))
}
result.AuthorizationList = tx.AuthList()
}
return result
}
Expand Down Expand Up @@ -937,12 +936,11 @@ func formatTxToEthTxJSON(tx *types.Transaction) *ethTxJSON {
enc.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
case types.TxTypeEthereumSetCode:
al := tx.AccessList()
aul := tx.AuthorizationList()
enc.AccessList = &al
enc.AuthorizationList = &aul
enc.ChainID = (*hexutil.Big)(tx.ChainId())
enc.MaxFeePerGas = (*hexutil.Big)(tx.GasFeeCap())
enc.MaxPriorityFeePerGas = (*hexutil.Big)(tx.GasTipCap())
enc.AuthorizationList = tx.AuthList()
default:
enc.GasPrice = (*hexutil.Big)(tx.GasPrice())
}
Expand Down Expand Up @@ -1413,7 +1411,7 @@ func EthDoCall(ctx context.Context, b Backend, args EthTransactionArgs, blockNrO
} else {
baseFee = new(big.Int).SetUint64(params.ZeroBaseFee)
}
intrinsicGas, dataTokens, err := types.IntrinsicGas(args.data(), args.GetAccessList(), nil, args.To == nil, b.ChainConfig().Rules(header.Number))
intrinsicGas, dataTokens, err := types.IntrinsicGas(args.data(), args.GetAccessList(), args.GetAuthorizationList(), args.To == nil, b.ChainConfig().Rules(header.Number))
if err != nil {
return nil, err
}
Expand Down
20 changes: 20 additions & 0 deletions api/api_ethereum_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2442,15 +2442,19 @@ func testEstimateGas(t *testing.T, mockBackend *mock_api.MockBackend, fnEstimate
chainConfig.ShanghaiCompatibleBlock = common.Big0
chainConfig.CancunCompatibleBlock = common.Big0
chainConfig.KaiaCompatibleBlock = common.Big0
chainConfig.PragueCompatibleBlock = common.Big0
var (
// genesis
account1 = common.HexToAddress("0xaaaa")
account2 = common.HexToAddress("0xbbbb")
account3 = common.HexToAddress("0xcccc")
account4 = common.HexToAddress("0xdddd")
account5 = common.HexToAddress("0xeeee")
gspec = &blockchain.Genesis{Alloc: blockchain.GenesisAlloc{
account1: {Balance: big.NewInt(params.KAIA * 2)},
account2: {Balance: common.Big0},
account3: {Balance: common.Big0, Code: hexutil.MustDecode(codeRevertHello)},
account4: {Balance: big.NewInt(params.KAIA * 2), Code: append(types.DelegationPrefix, account5.Bytes()...)},
}, Config: chainConfig}

// blockchain
Expand Down Expand Up @@ -2568,6 +2572,22 @@ func testEstimateGas(t *testing.T, mockBackend *mock_api.MockBackend, fnEstimate
},
expectErr: "execution reverted: hello",
},
{ // Should be able to send to an EIP-7702 delegated account.
args: EthTransactionArgs{
From: &account1,
To: &account4,
Value: (*hexutil.Big)(big.NewInt(1)),
},
expectGas: 21000,
},
{ // Should be able to send as EIP-7702 delegated account.
args: EthTransactionArgs{
From: &account4,
To: &account2,
Value: (*hexutil.Big)(big.NewInt(1)),
},
expectGas: 21000,
},
}

for i, tc := range testcases {
Expand Down
45 changes: 40 additions & 5 deletions api/tx_args.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,10 @@ type SendTxArgs struct {

Key *hexutil.Bytes `json:"key"`

AccessList *types.AccessList `json:"accessList,omitempty"`
AuthorizationList *types.AuthorizationList `json:"authorizationList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`
AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`

AuthorizationList []types.SetCodeAuthorization `json:"authorizationList,omitempty"`

FeePayer *common.Address `json:"feePayer"`
FeeRatio *types.FeeRatio `json:"feeRatio"`
Expand Down Expand Up @@ -326,7 +327,7 @@ func (args *SendTxArgs) genTxValuesMap() map[types.TxValueKeyType]interface{} {
values[types.TxValueKeyAccessList] = *args.AccessList
}
if args.AuthorizationList != nil {
values[types.TxValueKeyAuthorizationList] = *args.AuthorizationList
values[types.TxValueKeyAuthorizationList] = args.AuthorizationList
}
if args.MaxPriorityFeePerGas != nil {
values[types.TxValueKeyGasTipCap] = (*big.Int)(args.MaxPriorityFeePerGas)
Expand Down Expand Up @@ -561,6 +562,9 @@ type EthTransactionArgs struct {
// Introduced by AccessListTxType transaction.
AccessList *types.AccessList `json:"accessList,omitempty"`
ChainID *hexutil.Big `json:"chainId,omitempty"`

// For SetCodeTxType
AuthorizationList []types.SetCodeAuthorization `json:"authorizationList"`
}

// from retrieves the transaction sender address.
Expand Down Expand Up @@ -602,6 +606,14 @@ func (args *EthTransactionArgs) GetAccessList() types.AccessList {
}
}

func (args *EthTransactionArgs) GetAuthorizationList() []types.SetCodeAuthorization {
if args.AuthorizationList != nil {
return args.AuthorizationList
} else {
return nil
}
}

func (args *EthTransactionArgs) setGas(gas *hexutil.Uint64) {
args.Gas = gas
}
Expand Down Expand Up @@ -708,6 +720,7 @@ func (args *EthTransactionArgs) setDefaults(ctx context.Context, b Backend) erro
Value: args.Value,
Data: (*hexutil.Bytes)(&data),
AccessList: args.AccessList,
AuthorizationList: args.AuthorizationList,
}
pendingBlockNr := rpc.NewBlockNumberOrHashWithNumber(rpc.PendingBlockNumber)
gasCap := uint64(0)
Expand Down Expand Up @@ -780,14 +793,36 @@ func (args *EthTransactionArgs) ToMessage(globalGasCap uint64, baseFee *big.Int,
if args.AccessList != nil {
accessList = *args.AccessList
}
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, false, intrinsicGas, dataTokens, accessList, nil), nil

var AuthorizationList []types.SetCodeAuthorization
if args.AuthorizationList != nil {
AuthorizationList = args.AuthorizationList
}
return types.NewMessage(addr, args.To, 0, value, gas, gasPrice, nil, nil, data, false, intrinsicGas, dataTokens, accessList, AuthorizationList), nil
}

// toTransaction converts the arguments to a transaction.
// This assumes that setDefaults has been called.
func (args *EthTransactionArgs) toTransaction() (*types.Transaction, error) {
var tx *types.Transaction
switch {
case args.AuthorizationList != nil:
al := types.AccessList{}
if args.AccessList != nil {
al = *args.AccessList
}
tx = types.NewTx(&types.TxInternalDataEthereumSetCode{
ChainID: (*big.Int)(args.ChainID),
AccountNonce: uint64(*args.Nonce),
GasTipCap: (*big.Int)(args.MaxPriorityFeePerGas),
GasFeeCap: (*big.Int)(args.MaxFeePerGas),
GasLimit: uint64(*args.Gas),
Recipient: *args.To,
Amount: (*big.Int)(args.Value),
Payload: args.data(),
AccessList: al,
AuthorizationList: args.AuthorizationList,
})
case args.MaxFeePerGas != nil:
al := types.AccessList{}
if args.AccessList != nil {
Expand Down
20 changes: 12 additions & 8 deletions blockchain/blockchain_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2325,17 +2325,21 @@ func TestEIP7702(t *testing.T) {
gspec.Config.PragueCompatibleBlock = common.Big0

// Sign authorization tuples.
auth1, _ := types.SignAuth(&types.Authorization{
// The way the auths are combined, it becomes
// 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(),
Address: aa,
Nonce: 1,
}, key1)
})

auth2, _ := types.SignAuth(&types.Authorization{
auth2, _ := types.SignSetCode(key2, types.SetCodeAuthorization{
ChainID: uint64(0),
Address: bb,
Nonce: 0,
}, key2)
})

signer := types.LatestSignerForChainID(params.TestChainConfig.ChainID)

Expand All @@ -2344,7 +2348,7 @@ func TestEIP7702(t *testing.T) {
blocks, _ := GenerateChain(gspec.Config, genesis, engine, testdb, 1, func(i int, b *BlockGen) {
b.SetRewardbase(common.Address{1})

authorizationList := []types.Authorization{*auth1, *auth2}
authorizationList := []types.SetCodeAuthorization{auth1, auth2}
intrinsicGas, dataTokens, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
if err != nil {
t.Fatalf("failed to run intrinsic gas: %v", err)
Expand Down Expand Up @@ -2419,13 +2423,13 @@ func TestEIP7702(t *testing.T) {

// Set 0x0000000000000000000000000000000000000000000 test
{
authForEmpty, _ := types.SignAuth(&types.Authorization{
authForEmpty, _ := types.SignSetCode(key1, types.SetCodeAuthorization{
ChainID: gspec.Config.ChainID.Uint64(),
Address: common.Address{},
Nonce: state.GetNonce(addr1) + 1,
}, key1)
})

authorizationList := []types.Authorization{*authForEmpty}
authorizationList := []types.SetCodeAuthorization{authForEmpty}
intrinsicGas, dataTokens, err := types.IntrinsicGas(nil, nil, authorizationList, false, params.TestRules)
if err != nil {
t.Fatalf("failed to run intrinsic gas: %v", err)
Expand Down
23 changes: 18 additions & 5 deletions blockchain/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,23 @@ var (
// ErrGasPriceBelowBaseFee is returned if gas price of transaction is lower than gas unit price.
ErrGasPriceBelowBaseFee = errors.New("invalid gas price. It must be set to value greater than or equal to baseFee")

// ErrEmptyAuthList is returned if a set code transaction has an empty auth list.
ErrEmptyAuthList = errors.New("set code transaction with empty auth list")
// -- EIP-7702 errors --

// ErrAuthSignatureVeryHigh is returned if a set code transaction has a
// signature with R or S larger than 2^256-1.
ErrAuthSignatureVeryHigh = errors.New("set code transaction has authorization with R or S value greater than 2^256 - 1")
// Message validation errors:
// Note these are just informational, and do not cause tx execution abort.
ErrEmptyAuthList = errors.New("EIP-7702 transaction with empty auth list")
ErrSetCodeTxCreate = errors.New("EIP-7702 transaction cannot be used to create contract")
)

// EIP-7702 state transition errors.
// Note these are just informational, and do not cause tx execution abort.
var (

// EIP-7702 state transition errors:
ErrAuthorizationWrongChainID = errors.New("EIP-7702 authorization chain ID mismatch")
ErrAuthorizationNonceOverflow = errors.New("EIP-7702 authorization nonce > 64 bit")
ErrAuthorizationInvalidSignature = errors.New("EIP-7702 authorization has invalid signature")
ErrAuthorizationDestinationHasCode = errors.New("EIP-7702 authorization destination is a contract")
ErrAuthorizationNonceMismatch = errors.New("EIP-7702 authorization nonce does not match current account nonce")
ErrAuthorizationNotAllowAccountKeyType = errors.New("EIP-7702 authorization don't allow AccountKeyType")
)
24 changes: 0 additions & 24 deletions blockchain/state/statedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,26 +339,6 @@ func (s *StateDB) GetCodeHash(addr common.Address) common.Hash {
return common.BytesToHash(stateObject.CodeHash())
}

// ResolveCode retrieves the code at addr, resolving any delegation designations
// that may exist.
func (s *StateDB) ResolveCode(addr common.Address) []byte {
stateObject := s.resolveStateObject(addr)
if stateObject != nil {
return stateObject.Code(s.db)
}
return nil
}

// ResolveCodeHash retrieves the code at addr, resolving any delegation
// designations that may exist.
func (s *StateDB) ResolveCodeHash(addr common.Address) common.Hash {
stateObject := s.resolveStateObject(addr)
if stateObject != nil {
return common.BytesToHash(stateObject.CodeHash())
}
return common.Hash{}
}

// GetState retrieves a value from the given account's storage trie.
func (s *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
stateObject := s.getStateObject(addr)
Expand Down Expand Up @@ -1231,10 +1211,6 @@ func (s *StateDB) Prepare(rules params.Rules, sender, feepayer, coinbase common.
}
if dst != nil {
s.AddAddressToAccessList(*dst)
// If the dst has a delegation, also warm its target.
if addr, ok := types.ParseDelegation(s.GetCode(*dst)); ok {
s.AddAddressToAccessList(addr)
}
// If it's a create-tx, the destination will be added inside evm.create
}
for _, addr := range precompiles {
Expand Down
Loading
Loading